gprofng-gui-1.0/0000755000175000017500000000000014517775727010625 500000000000000gprofng-gui-1.0/compile0000755000175000017500000001635014517772130012111 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1999-2020 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN* | MSYS*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/* | msys/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe | \ icl | *[/\\]icl | icl.exe | *[/\\]icl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: gprofng-gui-1.0/ChangeLog0000644000175000017500000000011514517772113012276 000000000000002023-10-24 Jose E. Marchesi * New changelog. gprofng-gui-1.0/configure.ac0000644000175000017500000000234314517772113013017 00000000000000dnl Copyright (C) 2022 Free Software Foundation dnl dnl This program is free software: you can redistribute it and/or modify dnl it under the terms of the GNU General Public License as published by dnl the Free Software Foundation, either version 3 of the License, or dnl (at your option) any later version. dnl dnl This program is distributed in the hope that it will be useful, dnl but WITHOUT ANY WARRANTY; without even the implied warranty of dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the dnl GNU General Public License for more details. dnl dnl You should have received a copy of the GNU General Public License dnl along with this program. If not, see . AC_INIT([gprofng-gui], 1.0) AM_INIT_AUTOMAKE AC_PROG_CC AC_CHECK_PROGS([JAVA],[java],[no]) AC_CHECK_PROGS([JAVAC],[javac],[no]) AC_CHECK_PROGS([JAR],[jar],[no]) AC_CONFIG_FILES(Makefile) AC_OUTPUT if test "x$JAVA" = "xno"; then AC_ERROR([java is needed to build gprofng-gui. Please install the JRE.]) fi if test "x$JAVAC" = "xno"; then AC_ERROR([A java compiler is needed to build gprofng-gui. Please install the JDK.]) fi if test "x$JAR" = "xno"; then AC_ERROR([JAR is needed to buidl gprofng-guil. Please install the JDK.]) fi gprofng-gui-1.0/gprofng-gui.mf0000644000175000017500000000073714517772113013306 00000000000000Manifest-Version: 1.0 OpenIDE-Module-Layer: org/gprofng/mpmt/resources/mf-layer.xml Specification-Title: gprofng GUI OpenIDE-Module-Public-Packages: org.gprofng.mpmt.** OpenIDE-Module: org.gprofng.mpmt/1 Specification-Version: 8.2 OpenIDE-Module-Specification-Version: 8.2 OpenIDE-Module-Localizing-Bundle: org/gprofng/mpmt/Bundle.properties Implementation-Title: org.gprofng.mpmt Specification-Vendor: gprofng GUI Implementation-Version: 8.2 Implementation-Vendor: gprofng GUI gprofng-gui-1.0/README0000644000175000017500000000251014517772113011405 00000000000000The GNU gprofng GUI is a feature rich graphical user interface for the GNU gprofng tool. It makes it possible to interactively analyze and compare gprofng profiling experiments. Users can drill into an applications profile together with the applications code to gather an understanding and insight into what an application is doing throughout its runtime. The GUI is a Java application utilizing the Swing GUI framework. To build gprofng-gui from a released tarball: $ wget https://ftp.gnu.org/gnu/gprofng-gui/gprofng-gui.VERSION.tar.gz $ tar xzvf gprofng-gui.VERSION.tar.gz $ cd gprofng-gui.VERSION $ mkdir build && cd build/ $ ../configure --prefix=PREFIX && make && make install To build gprofn-gui from the development git repo: $ git clone https://git.savannah.gnu.org/git/gprofng-gui.git $ cd gprofng-gui $ autoreconf -i -f $ mkdir build && cd build/ $ ../configure --prefix=PREFIX && make && make install This GUI requires gprofng to be installed in the system to be used. The gprofng profiler is part of the GNU binutils. Make sure to have installed in your system and available in your PATH. Then you can launch the GUI using the following gprofng command: $ gprofng display gui [GUI_OPTIONS] [EXPERIMENT] Note that it is also possible to invoke the GUI directly: $ gp-display-gui [GUI_OPTIONS] [EXPERIMENT] gprofng-gui-1.0/Makefile.in0000644000175000017500000014325314517775005012607 00000000000000# Makefile.in generated by automake 1.16.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2020 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ # Copyright (C) 2022 Free Software Foundation # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # Copyright (C) 2012-2023 Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING3. If not see # . # VPATH = @srcdir@ am__is_gnu_make = { \ if test -z '$(MAKELEVEL)'; then \ false; \ elif test -n '$(MAKE_HOST)'; then \ true; \ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ true; \ else \ false; \ fi; \ } am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \ $(am__configure_deps) $(am__DIST_COMMON) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(pkgdatadir)" SCRIPTS = $(bin_SCRIPTS) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac man1dir = $(mandir)/man1 NROFF = nroff MANS = $(man_MANS) DATA = $(pkgdata_DATA) am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/doc/local.mk AUTHORS \ COPYING ChangeLog INSTALL NEWS README compile install-sh \ missing DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip # Exists only to be overridden by the user if desired. AM_DISTCHECK_DVI_TARGET = dvi distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EXEEXT = @EXEEXT@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ JAR = @JAR@ JAVA = @JAVA@ JAVAC = @JAVAC@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build_alias = @build_alias@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = $(srcdir)/doc dvidir = @dvidir@ exec_prefix = @exec_prefix@ host_alias = @host_alias@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ runstatedir = @runstatedir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AUTOMAKE_OPTIONS = ACLOCAL_AMFLAGS = -I . JAVA_FLAGS = JAVAC_FLAGS = JAR_FLAGS = cfvm MPMT_DIR = org/gprofng/mpmt ANALYZER_DIR = org/gprofng/analyzer COLLECTOR_DIR = org/gprofng/collector ANALYZER_JAR = gprofng-analyzer.jar GPROFNG_JAR = gprofng.jar COLLECTOR_JAR = gprofng-collector.jar MPMT_SRC = \ $(MPMT_DIR)/AboutPanel.java \ $(MPMT_DIR)/AnAction.java \ $(MPMT_DIR)/AnAddress.java \ $(MPMT_DIR)/Analyzer.java \ $(MPMT_DIR)/AnChooser.java \ $(MPMT_DIR)/AnCompDisp.java \ $(MPMT_DIR)/AnDialog.java \ $(MPMT_DIR)/AnDisplay.java \ $(MPMT_DIR)/AnDouble.java \ $(MPMT_DIR)/AnEvent.java \ $(MPMT_DIR)/AnFile.java \ $(MPMT_DIR)/AnFileSystemView.java \ $(MPMT_DIR)/AnFrame.java \ $(MPMT_DIR)/AnHotGap.java \ $(MPMT_DIR)/AnIconButton.java \ $(MPMT_DIR)/AnInteger.java \ $(MPMT_DIR)/AnListener.java \ $(MPMT_DIR)/AnList.java \ $(MPMT_DIR)/AnLocale.java \ $(MPMT_DIR)/AnLong.java \ $(MPMT_DIR)/AnMemoryManager.java \ $(MPMT_DIR)/AnMetric.java \ $(MPMT_DIR)/AnObject.java \ $(MPMT_DIR)/AnShellCommand.java \ $(MPMT_DIR)/AnString.java \ $(MPMT_DIR)/AnTable.java \ $(MPMT_DIR)/AnTree.java \ $(MPMT_DIR)/AnVariable.java \ $(MPMT_DIR)/AnWindow.java \ $(MPMT_DIR)/CalledByCallsDisassemblyView.java \ $(MPMT_DIR)/CalledByCallsDisp.java \ $(MPMT_DIR)/CalledByCallsFunctionsView.java \ $(MPMT_DIR)/CalledByCallsSourceView.java \ $(MPMT_DIR)/CallerCalleesView.java \ $(MPMT_DIR)/CallTreeView.java \ $(MPMT_DIR)/CannotFindFilePanel.java \ $(MPMT_DIR)/collect/CollectDialog.java \ $(MPMT_DIR)/collect/Collector.java \ $(MPMT_DIR)/collect/CollectorOpenPanel.java \ $(MPMT_DIR)/collect/CollectPanel2.java \ $(MPMT_DIR)/collect/CollectPanel3.java \ $(MPMT_DIR)/collect/CollectPanel.java \ $(MPMT_DIR)/collect/CollectUtility.java \ $(MPMT_DIR)/collect/HWCEntry.java \ $(MPMT_DIR)/collect/HWCSelectDialog.java \ $(MPMT_DIR)/collect/HWCSelectPanel.java \ $(MPMT_DIR)/compare/AnTransferHandler.java \ $(MPMT_DIR)/compare/CompareAdvancedDialog.java \ $(MPMT_DIR)/compare/CompareGroupsPanel.java \ $(MPMT_DIR)/compare/CompareNavigationPanel.java \ $(MPMT_DIR)/compare/CompareSimpleDialog.java \ $(MPMT_DIR)/compare/CompareSimplePanel.java \ $(MPMT_DIR)/compare/CompareStatusPanel.java \ $(MPMT_DIR)/compare/ExperimentGroupsPanel.java \ $(MPMT_DIR)/ConfigurationPanel.java \ $(MPMT_DIR)/control_panel/CPDetailsScrollPane.java \ $(MPMT_DIR)/control_panel/CPFilterPanelHandler.java \ $(MPMT_DIR)/control_panel/CPLayoutPanel.java \ $(MPMT_DIR)/control_panel/CPToolbarHandler.java \ $(MPMT_DIR)/control_panel/CPToolbar.java \ $(MPMT_DIR)/DataLayoutView.java \ $(MPMT_DIR)/DataObjectsView.java \ $(MPMT_DIR)/DisasmDisp.java \ $(MPMT_DIR)/DisassemblyView.java \ $(MPMT_DIR)/DualSourceView.java \ $(MPMT_DIR)/event/AnChangeEvent.java \ $(MPMT_DIR)/event/AnChangeListener.java \ $(MPMT_DIR)/event/AnEventManager.java \ $(MPMT_DIR)/event/AnSelectionEvent.java \ $(MPMT_DIR)/ExperimentPickListElement.java \ $(MPMT_DIR)/ExperimentPickList.java \ $(MPMT_DIR)/ExperimentPickLists.java \ $(MPMT_DIR)/experiment_props/DataDescriptor.java \ $(MPMT_DIR)/experiment_props/ExperimentProperties.java \ $(MPMT_DIR)/experiment_props/Experiments.java \ $(MPMT_DIR)/experiment_props/PropDescriptor.java \ $(MPMT_DIR)/ExperimentsView.java \ $(MPMT_DIR)/export/ExportDialog.java \ $(MPMT_DIR)/export/Export.java \ $(MPMT_DIR)/export/ExportPanel.java \ $(MPMT_DIR)/export/ExportSupport.java \ $(MPMT_DIR)/filter/CustomEditPanel.java \ $(MPMT_DIR)/filter/CustomFilterAction.java \ $(MPMT_DIR)/filter/CustomFilterDialog.java \ $(MPMT_DIR)/filter/CustomPanel.java \ $(MPMT_DIR)/filter/FilterClause.java \ $(MPMT_DIR)/filter/FilterNavigationPanel.java \ $(MPMT_DIR)/filter/FilterParser.java \ $(MPMT_DIR)/filter/Filters.java \ $(MPMT_DIR)/filter/FilterStatusPanel.java \ $(MPMT_DIR)/filter/FilterTextField.java \ $(MPMT_DIR)/filter/KeywordsPanel.java \ $(MPMT_DIR)/filter/RedoFilterAction.java \ $(MPMT_DIR)/filter/RemoveAllFilterAction.java \ $(MPMT_DIR)/filter/UndoFilterAction.java \ $(MPMT_DIR)/flame/FlameBlock.java \ $(MPMT_DIR)/flame/FlameData.java \ $(MPMT_DIR)/flame/FlamePanel.java \ $(MPMT_DIR)/flame/FlameRow.java \ $(MPMT_DIR)/flame/FlameToolBar.java \ $(MPMT_DIR)/flame/FlameView.java \ $(MPMT_DIR)/FuncListDisp.java \ $(MPMT_DIR)/FunctionsView.java \ $(MPMT_DIR)/guitesting/GUITesting.java \ $(MPMT_DIR)/HeapView.java \ $(MPMT_DIR)/HotGapPanel.java \ $(MPMT_DIR)/IDispToModel.java \ $(MPMT_DIR)/IExtTreeModel.java \ $(MPMT_DIR)/InstructionFrequencyView.java \ $(MPMT_DIR)/IOView.java \ $(MPMT_DIR)/ipc/IPCCancelledException.java \ $(MPMT_DIR)/ipc/IPCContext.java \ $(MPMT_DIR)/ipc/IPCErrorReader.java \ $(MPMT_DIR)/ipc/IPCHandle.java \ $(MPMT_DIR)/ipc/IPCListener.java \ $(MPMT_DIR)/ipc/IPCLogger.java \ $(MPMT_DIR)/ipc/IPCProtocol.java \ $(MPMT_DIR)/ipc/IPCReader.java \ $(MPMT_DIR)/ipc/IPCRequestHeader.java \ $(MPMT_DIR)/ipc/IPCRequest.java \ $(MPMT_DIR)/ipc/IPCResponseHeader.java \ $(MPMT_DIR)/ipc/IPCResponse.java \ $(MPMT_DIR)/ipc/IPCResult.java \ $(MPMT_DIR)/ipc/IPCTester.java \ $(MPMT_DIR)/IPC.java \ $(MPMT_DIR)/IPCProcess.java \ $(MPMT_DIR)/ITreeToPanel.java \ $(MPMT_DIR)/KeyboardShortcuts.java \ $(MPMT_DIR)/LibraryVisibilityDialog.java \ $(MPMT_DIR)/LibraryVisibilityPanel.java \ $(MPMT_DIR)/LinesView.java \ $(MPMT_DIR)/mainview/BorderPanel.java \ $(MPMT_DIR)/mainview/MainViewPanel.java \ $(MPMT_DIR)/mainview/Panel.java \ $(MPMT_DIR)/mainview/SubviewAreaPanel.java \ $(MPMT_DIR)/mainview/Subview.java \ $(MPMT_DIR)/MemoryIndexObjectView.java \ $(MPMT_DIR)/metrics/BasicMetric.java \ $(MPMT_DIR)/metrics/CompareBarData.java \ $(MPMT_DIR)/metrics/IPCMetricsAPI.java \ $(MPMT_DIR)/metrics/MetricAttr.java \ $(MPMT_DIR)/metrics/MetricColors.java \ $(MPMT_DIR)/metrics/MetricLabel.java \ $(MPMT_DIR)/metrics/MetricNode.java \ $(MPMT_DIR)/metrics/MetricOption.java \ $(MPMT_DIR)/metrics/MetricsGUI.java \ $(MPMT_DIR)/metrics/MetricValue.java \ $(MPMT_DIR)/metrics/SelectableMetricNode.java \ $(MPMT_DIR)/metrics/ValueMetricNode.java \ $(MPMT_DIR)/MiniFuncListDisp.java \ $(MPMT_DIR)/navigation/ActionPanel.java \ $(MPMT_DIR)/navigation/NavigationPanel.java \ $(MPMT_DIR)/navigation/PanelDropTargetListener.java \ $(MPMT_DIR)/navigation/TopNavigationPanel.java \ $(MPMT_DIR)/navigation/View.java \ $(MPMT_DIR)/navigation/ViewPanel.java \ $(MPMT_DIR)/navigation/ViewsPanel.java \ $(MPMT_DIR)/NoMetricsSelectedPanel.java \ $(MPMT_DIR)/overview/AnBarTree.java \ $(MPMT_DIR)/overview/BarColorKey.java \ $(MPMT_DIR)/overview/Bar.java \ $(MPMT_DIR)/overview/BarPanel.java \ $(MPMT_DIR)/overview/CheckBoxBarPanel.java \ $(MPMT_DIR)/overview/GradientPanel.java \ $(MPMT_DIR)/overview/OuterPanel.java \ $(MPMT_DIR)/overview/Overview.java \ $(MPMT_DIR)/overview/OverviewPanel.java \ $(MPMT_DIR)/overview/OverviewView.java \ $(MPMT_DIR)/overview/ProgressBarPanel.java \ $(MPMT_DIR)/overview/TopButtonPanel.java \ $(MPMT_DIR)/overview/TurnerLabelPanel.java \ $(MPMT_DIR)/overview/TurnerPanel.java \ $(MPMT_DIR)/PCsView.java \ $(MPMT_DIR)/persistence/UserPref.java \ $(MPMT_DIR)/persistence/UserPrefPersistence.java \ $(MPMT_DIR)/picklist/PickListElement.java \ $(MPMT_DIR)/picklist/PickListEvent.java \ $(MPMT_DIR)/picklist/PickList.java \ $(MPMT_DIR)/picklist/PickListListener.java \ $(MPMT_DIR)/picklist/StringPickListElement.java \ $(MPMT_DIR)/picklist/StringPickList.java \ $(MPMT_DIR)/progress/CancelContext.java \ $(MPMT_DIR)/progress/Cancellable.java \ $(MPMT_DIR)/progress/InternalHandle.java \ $(MPMT_DIR)/progress/ProgressHandle.java \ $(MPMT_DIR)/progress/ProgressPanel.java \ $(MPMT_DIR)/progress/SystemProgressPanel.java \ $(MPMT_DIR)/PsParser.java \ $(MPMT_DIR)/remote/Authentication.java \ $(MPMT_DIR)/remote/AuthenticationPanel.java \ $(MPMT_DIR)/remote/CheckBoxList.java \ $(MPMT_DIR)/remote/CloseExperimentDialog.java \ $(MPMT_DIR)/remote/CloseExperimentPanel.java \ $(MPMT_DIR)/remote/ConnectionDialog.java \ $(MPMT_DIR)/remote/ConnectionManager.java \ $(MPMT_DIR)/remote/ConnectionPanel.java \ $(MPMT_DIR)/ResolveFilePathDialog.java \ $(MPMT_DIR)/ResolveFilePathPanel.java \ $(MPMT_DIR)/SelectedObject.java \ $(MPMT_DIR)/SelectionManager.java \ $(MPMT_DIR)/settings/AnSettingChangeEvent.java \ $(MPMT_DIR)/settings/CallTreePanel.java \ $(MPMT_DIR)/settings/CallTreeSetting.java \ $(MPMT_DIR)/settings/CompareModeSetting.java \ $(MPMT_DIR)/settings/ExportSettingsDialog.java \ $(MPMT_DIR)/settings/ExportSettingsPanel.java \ $(MPMT_DIR)/settings/FormatSetting.java \ $(MPMT_DIR)/settings/ImportSettingsDialog.java \ $(MPMT_DIR)/settings/ImportSettingsPanel.java \ $(MPMT_DIR)/settings/LibraryVisibilitySetting.java \ $(MPMT_DIR)/settings/MetricAttributes.java \ $(MPMT_DIR)/settings/MetricNameSelected.java \ $(MPMT_DIR)/settings/MetricNameSelection.java \ $(MPMT_DIR)/settings/MetricSelection.java \ $(MPMT_DIR)/settings/MetricsPanel.java \ $(MPMT_DIR)/settings/MetricsSetting.java \ $(MPMT_DIR)/settings/MetricState.java \ $(MPMT_DIR)/settings/MetricStates.java \ $(MPMT_DIR)/settings/MetricType.java \ $(MPMT_DIR)/settings/MMetric.java \ $(MPMT_DIR)/settings/PathMapSetting.java \ $(MPMT_DIR)/settings/PathmapsPanel.java \ $(MPMT_DIR)/settings/SearchPathPanel.java \ $(MPMT_DIR)/settings/SearchPathSetting.java \ $(MPMT_DIR)/settings/Setting.java \ $(MPMT_DIR)/settings/Settings.java \ $(MPMT_DIR)/settings/SourceDisassemblySetting.java \ $(MPMT_DIR)/settings/TableSettings.java \ $(MPMT_DIR)/settings/TimelineSetting.java \ $(MPMT_DIR)/settings/ViewModeEnabledSetting.java \ $(MPMT_DIR)/settings/ViewModeSetting.java \ $(MPMT_DIR)/settings/ViewsSetting.java \ $(MPMT_DIR)/SourceDisassemblyView.java \ $(MPMT_DIR)/SourceDisp.java \ $(MPMT_DIR)/SourceView.java \ $(MPMT_DIR)/statecolors/AnColorChooser.java \ $(MPMT_DIR)/statecolors/ChooserStateView.java \ $(MPMT_DIR)/statecolors/ColorMap.java \ $(MPMT_DIR)/statecolors/ColorRule.java \ $(MPMT_DIR)/statecolors/StackState.java \ $(MPMT_DIR)/statecolors/StackStateList.java \ $(MPMT_DIR)/statecolors/StackView.java \ $(MPMT_DIR)/statecolors/StackViewState.java \ $(MPMT_DIR)/statecolors/StateColorMap.java \ $(MPMT_DIR)/StatisticsView.java \ $(MPMT_DIR)/statuspanel/StatusComponentHandle.java \ $(MPMT_DIR)/statuspanel/StatusComponent.java \ $(MPMT_DIR)/statuspanel/StatusHandleFactory.java \ $(MPMT_DIR)/statuspanel/StatusLabelHandle.java \ $(MPMT_DIR)/statuspanel/StatusLabel.java \ $(MPMT_DIR)/statuspanel/StatusLabelValueHandle.java \ $(MPMT_DIR)/statuspanel/StatusPanel.java \ $(MPMT_DIR)/SummaryPanel.java \ $(MPMT_DIR)/table/AnJTable.java \ $(MPMT_DIR)/table/AnTableHeaderPanel.java \ $(MPMT_DIR)/table/AnTableScrollPane.java \ $(MPMT_DIR)/table/AttributePanel.java \ $(MPMT_DIR)/table/ExclusiveAndInclusivePanel.java \ $(MPMT_DIR)/table/ExclusiveOrInclusivePanel.java \ $(MPMT_DIR)/table/HeaderMouseHandler.java \ $(MPMT_DIR)/table/MetricPanelDropTargetListener.java \ $(MPMT_DIR)/table/MetricPanel.java \ $(MPMT_DIR)/timeline2/cursorevent/CursorEvent.java \ $(MPMT_DIR)/timeline2/cursorevent/CursorMoveEvent.java \ $(MPMT_DIR)/timeline2/cursorevent/CursorSetEvent.java \ $(MPMT_DIR)/timeline2/data/GenericEvent.java \ $(MPMT_DIR)/timeline2/data/SampleEvent.java \ $(MPMT_DIR)/timeline2/data/StackEvent.java \ $(MPMT_DIR)/timeline2/Entity.java \ $(MPMT_DIR)/timeline2/EventDetails.java \ $(MPMT_DIR)/timeline2/IconRuler.java \ $(MPMT_DIR)/timeline2/MetaExperiment.java \ $(MPMT_DIR)/timeline2/RowData.java \ $(MPMT_DIR)/timeline2/RowDataRequestParams.java \ $(MPMT_DIR)/timeline2/RowDefinition.java \ $(MPMT_DIR)/timeline2/RowGeometry.java \ $(MPMT_DIR)/timeline2/TimelineDraw.java \ $(MPMT_DIR)/timeline2/TimelineSelectionEvent.java \ $(MPMT_DIR)/timeline2/TimelineSelectionRowEvent.java \ $(MPMT_DIR)/timeline2/TimelineVariable.java \ $(MPMT_DIR)/timeline2/TimelineView.java \ $(MPMT_DIR)/timeline2/TL2ControlPanel.java \ $(MPMT_DIR)/timeline2/TL2CoordCalcData.java \ $(MPMT_DIR)/timeline2/TL2DataFetcher.java \ $(MPMT_DIR)/timeline2/TL2DataSnapshot.java \ $(MPMT_DIR)/timeline2/TL2Drawer.java \ $(MPMT_DIR)/timeline2/TLExperiment.java \ $(MPMT_DIR)/timeline_common/CoordCalcDataImpl.java \ $(MPMT_DIR)/timeline_common/CoordCalcDataMaster.java \ $(MPMT_DIR)/timeline_common/CoordCalcDataReader.java \ $(MPMT_DIR)/timeline_common/CoordCalcTimeImpl.java \ $(MPMT_DIR)/timeline_common/CoordCalcTimeMaster.java \ $(MPMT_DIR)/timeline_common/CoordCalcTimeReader.java \ $(MPMT_DIR)/timeline_common/TimelineCaliper.java \ $(MPMT_DIR)/timeline_common/TimelineCursor.java \ $(MPMT_DIR)/timeline_common/TimelineDrawer.java \ $(MPMT_DIR)/timeline_common/TimelinePanel.java \ $(MPMT_DIR)/timeline_common/TimelineSelectionCaliperEvent.java \ $(MPMT_DIR)/timeline_common/TimelineSelectionGenericEvent.java \ $(MPMT_DIR)/timeline_common/TimelineSelectionHistoryEvent.java \ $(MPMT_DIR)/timeline_common/TimelineSelectionListener.java \ $(MPMT_DIR)/timeline_common/VerticalRowRuler.java \ $(MPMT_DIR)/timeline/events/DeadlockEvent.java \ $(MPMT_DIR)/timeline/events/DetailsIPC.java \ $(MPMT_DIR)/timeline/events/DurationEvent.java \ $(MPMT_DIR)/timeline/events/EventDetail.java \ $(MPMT_DIR)/timeline/events/ExtendedEvent.java \ $(MPMT_DIR)/timeline/events/HeapEvent.java \ $(MPMT_DIR)/timeline/events/HWCEvent.java \ $(MPMT_DIR)/timeline/events/IOEvent.java \ $(MPMT_DIR)/timeline/events/MPIEvent.java \ $(MPMT_DIR)/timeline/events/ProfileEvent.java \ $(MPMT_DIR)/timeline/events/RaceEvent.java \ $(MPMT_DIR)/timeline/events/Sample.java \ $(MPMT_DIR)/timeline/events/StateEvent.java \ $(MPMT_DIR)/timeline/events/SyncEvent.java \ $(MPMT_DIR)/toolbar/FindTextPanel.java \ $(MPMT_DIR)/toolbar/ToolBarFiller.java \ $(MPMT_DIR)/toolbar/ToolBarPanel.java \ $(MPMT_DIR)/toolbar/ToolBarSeparator.java \ $(MPMT_DIR)/util/gui/ActionTextField.java \ $(MPMT_DIR)/util/gui/AnBorderPanel.java \ $(MPMT_DIR)/util/gui/AnCheckBox.java \ $(MPMT_DIR)/util/gui/AnDialog2.java \ $(MPMT_DIR)/util/gui/AnDialogOuterPanel.java \ $(MPMT_DIR)/util/gui/AnGradientPanel.java \ $(MPMT_DIR)/util/gui/AnInsetsPanel.java \ $(MPMT_DIR)/util/gui/AnJList.java \ $(MPMT_DIR)/util/gui/AnJPanel.java \ $(MPMT_DIR)/util/gui/AnJScrollPane.java \ $(MPMT_DIR)/util/gui/AnJTree.java \ $(MPMT_DIR)/util/gui/AnLongScrollBar.java \ $(MPMT_DIR)/util/gui/AnMenuBar.java \ $(MPMT_DIR)/util/gui/AnScrollBarUI.java \ $(MPMT_DIR)/util/gui/AnSplitPaneFixedRightSize.java \ $(MPMT_DIR)/util/gui/AnSplitPaneInternal.java \ $(MPMT_DIR)/util/gui/AnSplitPane.java \ $(MPMT_DIR)/util/gui/AnTabbedPane.java \ $(MPMT_DIR)/util/gui/AnTabbedPaneUI.java \ $(MPMT_DIR)/util/gui/AnTextIcon.java \ $(MPMT_DIR)/util/gui/AnUtility.java \ $(MPMT_DIR)/util/gui/RainbowColorScale.java \ $(MPMT_DIR)/util/gui/ToolTipPopup.java \ $(MPMT_DIR)/util/ruler/LabelCoordinateCalculator.java \ $(MPMT_DIR)/util/ruler/RangeRuler.java \ $(MPMT_DIR)/util/ruler/Ruler.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesBytes.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesGeneric.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesLabelList.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesLong.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesNanoseconds.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesWithUnits.java \ $(MPMT_DIR)/util/zoomruler/OverlayMouseHandler.java \ $(MPMT_DIR)/util/zoomruler/PaintListener.java \ $(MPMT_DIR)/util/zoomruler/ZoomRulerComponent.java \ $(MPMT_DIR)/util/zoomruler/ZoomRulerEvent.java \ $(MPMT_DIR)/util/zoomruler/ZoomRulerListener.java \ $(MPMT_DIR)/util/zoomruler/ZoomRulerOverlay.java \ $(MPMT_DIR)/ViewDisplayPanel.java \ $(MPMT_DIR)/welcome/WelcomeButton.java \ $(MPMT_DIR)/welcome/WelcomeInnerPanel.java \ $(MPMT_DIR)/welcome/WelcomePanel.java \ $(MPMT_DIR)/welcome/WelcomeView.java MPMT_FILES = \ $(MPMT_SRC:%.java=$(srcdir)/%.java) \ $(ANALYZER_FILES) ICONS = \ $(MPMT_DIR)/icons/add.png \ $(MPMT_DIR)/icons/addtablecolumns.png \ $(MPMT_DIR)/icons/analyzer64.png \ $(MPMT_DIR)/icons/apply_filter.png \ $(MPMT_DIR)/icons/apply_mtrs.png \ $(MPMT_DIR)/icons/attributed.png \ $(MPMT_DIR)/icons/back_filter.png \ $(MPMT_DIR)/icons/backward.png \ $(MPMT_DIR)/icons/badexperiment.png \ $(MPMT_DIR)/icons/base1.png \ $(MPMT_DIR)/icons/base2.png \ $(MPMT_DIR)/icons/blank.png \ $(MPMT_DIR)/icons/bubble_icon_16.png \ $(MPMT_DIR)/icons/callee.png \ $(MPMT_DIR)/icons/caller.png \ $(MPMT_DIR)/icons/cancelProcess.png \ $(MPMT_DIR)/icons/class.png \ $(MPMT_DIR)/icons/collect.png \ $(MPMT_DIR)/icons/color.png \ $(MPMT_DIR)/icons/compareAbsolute.png \ $(MPMT_DIR)/icons/compareDelta.png \ $(MPMT_DIR)/icons/compareHamburger.png \ $(MPMT_DIR)/icons/compare.png \ $(MPMT_DIR)/icons/compareRatio.png \ $(MPMT_DIR)/icons/compareReverse.png \ $(MPMT_DIR)/icons/connect.png \ $(MPMT_DIR)/icons/data.png \ $(MPMT_DIR)/icons/delete.png \ $(MPMT_DIR)/icons/down.png \ $(MPMT_DIR)/icons/errorNew.png \ $(MPMT_DIR)/icons/error.png \ $(MPMT_DIR)/icons/errorWarningNew.png \ $(MPMT_DIR)/icons/exclusive.png \ $(MPMT_DIR)/icons/exe_elf.png \ $(MPMT_DIR)/icons/expandcollaps.png \ $(MPMT_DIR)/icons/experiment.png \ $(MPMT_DIR)/icons/expgroup.png \ $(MPMT_DIR)/icons/fileResolved.png \ $(MPMT_DIR)/icons/fileUnResolved.png \ $(MPMT_DIR)/icons/filter.png \ $(MPMT_DIR)/icons/find_next.png \ $(MPMT_DIR)/icons/find_prev.png \ $(MPMT_DIR)/icons/forward_filter.png \ $(MPMT_DIR)/icons/forward.png \ $(MPMT_DIR)/icons/func_item.png \ $(MPMT_DIR)/icons/gear.png \ $(MPMT_DIR)/icons/gobackward.png \ $(MPMT_DIR)/icons/godown.png \ $(MPMT_DIR)/icons/goforward.png \ $(MPMT_DIR)/icons/goup.png \ $(MPMT_DIR)/icons/green100.png \ $(MPMT_DIR)/icons/hamburgerBlank.png \ $(MPMT_DIR)/icons/hamburgerFocused.png \ $(MPMT_DIR)/icons/hamburger.png \ $(MPMT_DIR)/icons/heaptrace.png \ $(MPMT_DIR)/icons/hollowArrowDown.png \ $(MPMT_DIR)/icons/hollowArrowLeft.png \ $(MPMT_DIR)/icons/hollowArrowRight.png \ $(MPMT_DIR)/icons/hollowArrowUp.png \ $(MPMT_DIR)/icons/hot.png \ $(MPMT_DIR)/icons/hwc.png \ $(MPMT_DIR)/icons/inclusive.png \ $(MPMT_DIR)/icons/i_o_usage_16.png \ $(MPMT_DIR)/icons/jar.png \ $(MPMT_DIR)/icons/more_icon.png \ $(MPMT_DIR)/icons/mpitrace.png \ $(MPMT_DIR)/icons/nav_bar_arrow.png \ $(MPMT_DIR)/icons/nextview.png \ $(MPMT_DIR)/icons/number.png \ $(MPMT_DIR)/icons/oldexperiment.png \ $(MPMT_DIR)/icons/open.png \ $(MPMT_DIR)/icons/panhand.png \ $(MPMT_DIR)/icons/percent.png \ $(MPMT_DIR)/icons/previousview.png \ $(MPMT_DIR)/icons/profile.png \ $(MPMT_DIR)/icons/races.png \ $(MPMT_DIR)/icons/redo.png \ $(MPMT_DIR)/icons/removeBlank.png \ $(MPMT_DIR)/icons/removeFocused.png \ $(MPMT_DIR)/icons/remove.png \ $(MPMT_DIR)/icons/reset.png \ $(MPMT_DIR)/icons/sample.png \ $(MPMT_DIR)/icons/save.png \ $(MPMT_DIR)/icons/smallBlank.png \ $(MPMT_DIR)/icons/small_down_focused.png \ $(MPMT_DIR)/icons/small_down.png \ $(MPMT_DIR)/icons/small_left.png \ $(MPMT_DIR)/icons/small_right.png \ $(MPMT_DIR)/icons/small_up_focused.png \ $(MPMT_DIR)/icons/small_up.png \ $(MPMT_DIR)/icons/stop.png \ $(MPMT_DIR)/icons/synctrace.png \ $(MPMT_DIR)/icons/tab.png \ $(MPMT_DIR)/icons/time.png \ $(MPMT_DIR)/icons/undo.png \ $(MPMT_DIR)/icons/up.png \ $(MPMT_DIR)/icons/values.png \ $(MPMT_DIR)/icons/warnexperiment.png \ $(MPMT_DIR)/icons/warningNew.png \ $(MPMT_DIR)/icons/warning.png \ $(MPMT_DIR)/icons/welcomeBackgroundShadow.png \ $(MPMT_DIR)/icons/zoom_in.png \ $(MPMT_DIR)/icons/zoom_out.png \ $(MPMT_DIR)/icons/circleBlue.gif \ $(MPMT_DIR)/icons/circleGreen.gif \ $(MPMT_DIR)/icons/circleOrange.gif \ $(MPMT_DIR)/icons/circleRed.gif \ $(MPMT_DIR)/icons/performanceAnalyzerSplash.gif GPROFNG_CLASSES = \ $(MPMT_DIR)/*.class \ $(MPMT_DIR)/*/*.class \ $(MPMT_DIR)/*/*/*.class \ $(MPMT_DIR)/*/*/*/*.class GPROFNG_FORMS = \ $(MPMT_DIR)/AboutPanel.form \ $(MPMT_DIR)/CannotFindFilePanel.form \ $(MPMT_DIR)/collect/CollectorOpenPanel.form \ $(MPMT_DIR)/collect/CollectPanel2.form \ $(MPMT_DIR)/collect/CollectPanel3.form \ $(MPMT_DIR)/collect/HWCSelectPanel.form \ $(MPMT_DIR)/compare/CompareGroupsPanel.form \ $(MPMT_DIR)/compare/CompareSimplePanel.form \ $(MPMT_DIR)/compare/CompareStatusPanel.form \ $(MPMT_DIR)/compare/ExperimentGroupsPanel.form \ $(MPMT_DIR)/ConfigurationPanel.form \ $(MPMT_DIR)/export/ExportPanel.form \ $(MPMT_DIR)/filter/CustomPanel.form \ $(MPMT_DIR)/filter/FilterNavigationPanel.form \ $(MPMT_DIR)/filter/FilterStatusPanel.form \ $(MPMT_DIR)/filter/KeywordsPanel.form \ $(MPMT_DIR)/LibraryVisibilityPanel.form \ $(MPMT_DIR)/mainview/BorderPanel.form \ $(MPMT_DIR)/mainview/MainViewPanel.form \ $(MPMT_DIR)/navigation/ActionPanel.form \ $(MPMT_DIR)/navigation/TopNavigationPanel.form \ $(MPMT_DIR)/navigation/ViewPanel.form \ $(MPMT_DIR)/navigation/ViewsPanel.form \ $(MPMT_DIR)/NoMetricsSelectedPanel.form \ $(MPMT_DIR)/overview/BarPanel.form \ $(MPMT_DIR)/overview/CheckBoxBarPanel.form \ $(MPMT_DIR)/overview/GradientPanel.form \ $(MPMT_DIR)/overview/OuterPanel.form \ $(MPMT_DIR)/overview/OverviewPanel.form \ $(MPMT_DIR)/overview/ProgressBarPanel.form \ $(MPMT_DIR)/overview/TopButtonPanel.form \ $(MPMT_DIR)/overview/TurnerLabelPanel.form \ $(MPMT_DIR)/overview/TurnerPanel.form \ $(MPMT_DIR)/progress/ProgressPanel.form \ $(MPMT_DIR)/remote/AuthenticationPanel.form \ $(MPMT_DIR)/remote/CloseExperimentPanel.form \ $(MPMT_DIR)/remote/ConnectionPanel.form \ $(MPMT_DIR)/ResolveFilePathPanel.form \ $(MPMT_DIR)/settings/CallTreePanel.form \ $(MPMT_DIR)/settings/ExportSettingsPanel.form \ $(MPMT_DIR)/settings/ImportSettingsPanel.form \ $(MPMT_DIR)/settings/MetricsPanel.form \ $(MPMT_DIR)/settings/PathmapsPanel.form \ $(MPMT_DIR)/settings/SearchPathPanel.form \ $(MPMT_DIR)/statuspanel/StatusPanel.form \ $(MPMT_DIR)/util/gui/AnDialogOuterPanel.form \ $(MPMT_DIR)/util/gui/AnInsetsPanel.form \ $(MPMT_DIR)/welcome/WelcomeInnerPanel.form \ $(MPMT_DIR)/welcome/WelcomePanel.form anmodule_MF = $(srcdir)/gprofng-gui.mf MPMT_PROPERTIES = $(MPMT_DIR)/Bundle.properties # # Standalone gprofng GUI # ANALYZER_SRC = \ $(ANALYZER_DIR)/AnEnvironment.java \ $(ANALYZER_DIR)/AnLog.java \ $(ANALYZER_DIR)/AnMain.java ANALYZER_FILES = $(ANALYZER_SRC:%.java=$(srcdir)/%.java) ANALYZER_MF = $(srcdir)/analyzer_st.mf ANALYZER_CLASSES = $(ANALYZER_DIR)/*.class ANALYZER_PROPERTIES = $(ANALYZER_DIR)/Bundle.properties # Rules for generating a jar file implementing Java collector API # COLLECTOR_SRC = $(COLLECTOR_DIR)/CollectorAPI.java collector_FILES = $(COLLECTOR_SRC:%.java=$(srcdir)/%.java) collector_MF = $(srcdir)/gprofng-collector.mf collector_CLASSES = $(COLLECTOR_DIR)/*.class bin_SCRIPTS = gp-display-gui CLEANFILES = gp-display-gui $(GPROFNG_JAR) $(ANALYZER_JAR) \ $(COLLECTOR_JAR) $(GPROFNG_CLASSES) $(ANALYZER_CLASSES) \ $(collector_CLASSES) $(ANALYZER_PROPERTIES) $(MPMT_PROPERTIES) \ LocaleString*.class $(man_MANS) pkgdata_DATA = $(ANALYZER_JAR) $(COLLECTOR_JAR) $(GPROFNG_JAR) EXTRA_DIST = $(MPMT_SRC) $(ANALYZER_SRC) $(COLLECTOR_SRC) $(ICONS) \ $(GPROFNG_FORMS) aclocal.m4 analyzer_st.mf compile \ configure.ac configure gprofng-collector.mf gprofng-gui.mf \ gprofng-gui.sh gprofng-gui.spec gprofng.properties INSTALL \ install-sh Makefile.am Makefile.in missing README AUTHORS NEWS \ tools $(man_MANS) $(docdir)/gp-macros.texi \ $(docdir)/gp-display-gui.texi # Options to extract the man page MANCONF = -Dman TEXI2POD = perl $(srcdir)/etc/texi2pod.pl $(AM_MAKEINFOFLAGS) POD2MAN = pod2man --center="User Commands" \ --release="binutils-$(VERSION)" --section=1 #info_TEXINFOS = gp-display-gui.texi TEXINFO_TEX = . MAKEINFOHTML = $(MAKEINFO) --html --no-split man_MANS = gp-display-gui.1 all: all-am .SUFFIXES: am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(srcdir)/doc/local.mk $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --gnu Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__maybe_remake_depfiles);; \ esac; $(srcdir)/doc/local.mk $(am__empty): $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): install-binSCRIPTS: $(bin_SCRIPTS) @$(NORMAL_INSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(bin_SCRIPTS)'; test -n "$(bindir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(bindir)'; $(am__uninstall_files_from_dir) install-man1: $(man_MANS) @$(NORMAL_INSTALL) @list1=''; \ list2='$(man_MANS)'; \ test -n "$(man1dir)" \ && test -n "`echo $$list1$$list2`" \ || exit 0; \ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \ { for i in $$list1; do echo "$$i"; done; \ if test -n "$$list2"; then \ for i in $$list2; do echo "$$i"; done \ | sed -n '/\.1[a-z]*$$/p'; \ fi; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-pkgdataDATA: $(pkgdata_DATA) @$(NORMAL_INSTALL) @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(pkgdatadir)'"; \ $(MKDIR_P) "$(DESTDIR)$(pkgdatadir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgdatadir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgdatadir)" || exit $$?; \ done uninstall-pkgdataDATA: @$(NORMAL_UNINSTALL) @list='$(pkgdata_DATA)'; test -n "$(pkgdatadir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgdatadir)'; $(am__uninstall_files_from_dir) tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) distdir-am distdir-am: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-zstd: distdir tardir=$(distdir) && $(am__tar) | zstd -c $${ZSTD_CLEVEL-$${ZSTD_OPT--19}} >$(distdir).tar.zst $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | eval GZIP= gzip $(GZIP_ENV) -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ eval GZIP= gzip $(GZIP_ENV) -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ *.tar.zst*) \ zstd -dc $(distdir).tar.zst | $(am__untar) ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_build/sub $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build/sub \ && ../../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=../.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-am all-am: Makefile $(SCRIPTS) $(MANS) $(DATA) installdirs: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(pkgdatadir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-man install-pkgdataDATA install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binSCRIPTS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-binSCRIPTS uninstall-man uninstall-pkgdataDATA uninstall-man: uninstall-man1 .MAKE: install-am install-strip .PHONY: all all-am am--refresh check check-am clean clean-generic \ cscopelist-am ctags-am dist dist-all dist-bzip2 dist-gzip \ dist-lzip dist-shar dist-tarZ dist-xz dist-zip dist-zstd \ distcheck distclean distclean-generic distcleancheck distdir \ distuninstallcheck dvi dvi-am html html-am info info-am \ install install-am install-binSCRIPTS install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-man1 install-pdf \ install-pdf-am install-pkgdataDATA install-ps install-ps-am \ install-strip installcheck installcheck-am installdirs \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-generic pdf pdf-am ps ps-am tags-am uninstall \ uninstall-am uninstall-binSCRIPTS uninstall-man uninstall-man1 \ uninstall-pkgdataDATA .PRECIOUS: Makefile LocaleString.class: $(srcdir)/tools/LocaleString.java @echo "================= $@" $(JAVAC) $(JAVAC_FLAGS) -d . $(srcdir)/tools/LocaleString.java $(MPMT_PROPERTIES): $(MPMT_FILES) LocaleString.class \ $(srcdir)/gprofng.properties @echo "================= $@" mkdir -m 777 -p $(@D) echo "# THIS FILE IS AUTO-GENERATED. DON'T EDIT IT." > $@ echo "" >> $@ cat $(srcdir)/gprofng.properties >> $@ cat $(MPMT_FILES) | $(JAVA) $(JAVA_FLAGS) -cp . LocaleString >> $@ $(GPROFNG_JAR): $(anmodule_MF) $(MPMT_FILES) \ $(MPMT_PROPERTIES) $(ICONS:%=$(srcdir)/%) @echo "================= $@" rm -f $(GPROFNG_CLASSES) $(JAVAC) -cp $(srcdir) $(JAVAC_FLAGS) -d . $(srcdir)/$(MPMT_DIR)/Analyzer.java $(JAR) $(JAR_FLAGS) $@ $(anmodule_MF) $(GPROFNG_CLASSES) \ $(ICONS:%=-C $(srcdir) %) $(MPMT_PROPERTIES) $(ANALYZER_PROPERTIES): $(ANALYZER_FILES) LocaleString.class @echo "================= $@" mkdir -m 777 -p $(@D) echo "# THIS FILE IS AUTO-GENERATED. DON'T EDIT IT." > $@ echo "" >> $@ cat $(ANALYZER_FILES) | $(JAVA) $(JAVA_FLAGS) -cp . LocaleString >> $@ $(ANALYZER_JAR): $(GPROFNG_JAR) \ $(ANALYZER_MF) $(ANALYZER_FILES) $(ANALYZER_PROPERTIES) @echo "================= $@" rm -f $(ANALYZER_CLASSES) $(JAVAC) -classpath $(GPROFNG_JAR) $(JAVAC_FLAGS) -d . $(ANALYZER_FILES) echo "Create $(ANALYZER_JAR) in `pwd`" $(JAR) $(JAR_FLAGS) $@ $(ANALYZER_MF) $(ANALYZER_CLASSES) \ $(ANALYZER_PROPERTIES) $(COLLECTOR_JAR): $(GPROFNG_JAR) $(collector_FILES) $(collector_MF) @echo "================= $@" rm -f $(collector_CLASSES) $(JAVAC) $(JAVAC_FLAGS) -d . $(collector_FILES) $(JAR) $(JAR_FLAGS) $@ $(collector_MF) $(collector_CLASSES) gp-display-gui: $(srcdir)/gprofng-gui.sh @echo "================= $@" sed -e "s~REPLACE_ME_WITH_VERSION~$(VERSION)~" < $(srcdir)/gprofng-gui.sh \ | sed -e "s~GPROFNG_bindir=~GPROFNG_bindir='$(bindir)'~" \ | sed -e "s~GPROFNG_libdir=~GPROFNG_libdir='$(libdir)'~" \ | sed -e "s~GPROFNG_datadir=~GPROFNG_datadir='$(datadir)'~" \ > $@ chmod +x $@ # Build the man page from the texinfo file # The sed command removes the no-adjust Nroff command so that # the man output looks standard. $(man_MANS): $(docdir)/gp-macros.texi $(AM_V_GEN)touch $@ ( nm=`basename $@ .1` ; \ $(AM_V_at)$(TEXI2POD) $(MANCONF) < $(docdir)/$$nm.texi > $$nm.pod ; \ $(AM_V_at)($(POD2MAN) $$nm.pod | sed -e '/^.if n .na/d' > $@.tmp && \ mv -f $@.tmp $@) || (rm -f $@.tmp && exit 1) ; \ $(AM_V_at)rm -f $$nm.pod ) gp-display-gui.1: $(docdir)/gp-display-gui.texi # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: gprofng-gui-1.0/NEWS0000644000175000017500000000056614517775161011243 00000000000000This NEWS file records noteworthy changes, very tersely. See the manual for detailed information. Copyright 2023 The gprofng-gui authors. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. Version 1.0 (30 October 2023) - Initial release. gprofng-gui-1.0/gprofng-collector.mf0000644000175000017500000000023214517772113014476 00000000000000Manifest-Version: 1.0 OpenIDE-Module-Public-Packages: org.gprofng.collector.** OpenIDE-Module: org.gprofng.collector/1 Specification-Version: 1.0 gprofng-gui-1.0/AUTHORS0000644000175000017500000000006314517772113011576 00000000000000Vladimir Mezentsev gprofng-gui-1.0/analyzer_st.mf0000644000175000017500000000015014517772113013402 00000000000000Class-Path: gprofng.jar gprofng-collector.jar analyzer_help.jar Main-Class: org.gprofng.analyzer.AnMain gprofng-gui-1.0/gprofng.properties0000644000175000017500000000126214517772113014310 00000000000000OpenIDE-Module-Name=gprofng GUI OpenIDE-Module-Display-Category=Tools OpenIDE-Module-Short-Description=gprofng GUI OpenIDE-Module-Long-Description=gprofng GUI Actions/Analyze=Analyze Menu/Analyze=&Analyze Menu/Help/HelpShortcuts/org-gprofng-mpmt-help-Welcome_Analyzer.xml=gprofng GUI Help LBL_loaderName=gprofng GUI Data Loader LBL_Action=Analyze CTL_Analyzing=Analyzing CTL_AnalyzingDescription=gprofng GUI CTL_display=gprofng GUI CTL_displayDescription=gprofng GUI CTL_editor=Editor Window CTL_editorDescription=gprofng GUI Editor CTL_explorer=Explorer CTL_explorerDescription=gprofng GUI Explorer CTL_properties=Properties Window CTL_propertiesDescription=gprofng GUI Properties Window gprofng-gui-1.0/Makefile.am0000644000175000017500000006276614517774700012610 00000000000000# Copyright (C) 2022 Free Software Foundation # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . AUTOMAKE_OPTIONS = ACLOCAL_AMFLAGS = -I . JAVA = @JAVA@ JAVAC = @JAVAC@ JAR = @JAR@ JAVA_FLAGS = JAVAC_FLAGS = JAR_FLAGS = cfvm MPMT_DIR = org/gprofng/mpmt ANALYZER_DIR = org/gprofng/analyzer COLLECTOR_DIR = org/gprofng/collector ANALYZER_JAR = gprofng-analyzer.jar GPROFNG_JAR = gprofng.jar COLLECTOR_JAR = gprofng-collector.jar MPMT_SRC = \ $(MPMT_DIR)/AboutPanel.java \ $(MPMT_DIR)/AnAction.java \ $(MPMT_DIR)/AnAddress.java \ $(MPMT_DIR)/Analyzer.java \ $(MPMT_DIR)/AnChooser.java \ $(MPMT_DIR)/AnCompDisp.java \ $(MPMT_DIR)/AnDialog.java \ $(MPMT_DIR)/AnDisplay.java \ $(MPMT_DIR)/AnDouble.java \ $(MPMT_DIR)/AnEvent.java \ $(MPMT_DIR)/AnFile.java \ $(MPMT_DIR)/AnFileSystemView.java \ $(MPMT_DIR)/AnFrame.java \ $(MPMT_DIR)/AnHotGap.java \ $(MPMT_DIR)/AnIconButton.java \ $(MPMT_DIR)/AnInteger.java \ $(MPMT_DIR)/AnListener.java \ $(MPMT_DIR)/AnList.java \ $(MPMT_DIR)/AnLocale.java \ $(MPMT_DIR)/AnLong.java \ $(MPMT_DIR)/AnMemoryManager.java \ $(MPMT_DIR)/AnMetric.java \ $(MPMT_DIR)/AnObject.java \ $(MPMT_DIR)/AnShellCommand.java \ $(MPMT_DIR)/AnString.java \ $(MPMT_DIR)/AnTable.java \ $(MPMT_DIR)/AnTree.java \ $(MPMT_DIR)/AnVariable.java \ $(MPMT_DIR)/AnWindow.java \ $(MPMT_DIR)/CalledByCallsDisassemblyView.java \ $(MPMT_DIR)/CalledByCallsDisp.java \ $(MPMT_DIR)/CalledByCallsFunctionsView.java \ $(MPMT_DIR)/CalledByCallsSourceView.java \ $(MPMT_DIR)/CallerCalleesView.java \ $(MPMT_DIR)/CallTreeView.java \ $(MPMT_DIR)/CannotFindFilePanel.java \ $(MPMT_DIR)/collect/CollectDialog.java \ $(MPMT_DIR)/collect/Collector.java \ $(MPMT_DIR)/collect/CollectorOpenPanel.java \ $(MPMT_DIR)/collect/CollectPanel2.java \ $(MPMT_DIR)/collect/CollectPanel3.java \ $(MPMT_DIR)/collect/CollectPanel.java \ $(MPMT_DIR)/collect/CollectUtility.java \ $(MPMT_DIR)/collect/HWCEntry.java \ $(MPMT_DIR)/collect/HWCSelectDialog.java \ $(MPMT_DIR)/collect/HWCSelectPanel.java \ $(MPMT_DIR)/compare/AnTransferHandler.java \ $(MPMT_DIR)/compare/CompareAdvancedDialog.java \ $(MPMT_DIR)/compare/CompareGroupsPanel.java \ $(MPMT_DIR)/compare/CompareNavigationPanel.java \ $(MPMT_DIR)/compare/CompareSimpleDialog.java \ $(MPMT_DIR)/compare/CompareSimplePanel.java \ $(MPMT_DIR)/compare/CompareStatusPanel.java \ $(MPMT_DIR)/compare/ExperimentGroupsPanel.java \ $(MPMT_DIR)/ConfigurationPanel.java \ $(MPMT_DIR)/control_panel/CPDetailsScrollPane.java \ $(MPMT_DIR)/control_panel/CPFilterPanelHandler.java \ $(MPMT_DIR)/control_panel/CPLayoutPanel.java \ $(MPMT_DIR)/control_panel/CPToolbarHandler.java \ $(MPMT_DIR)/control_panel/CPToolbar.java \ $(MPMT_DIR)/DataLayoutView.java \ $(MPMT_DIR)/DataObjectsView.java \ $(MPMT_DIR)/DisasmDisp.java \ $(MPMT_DIR)/DisassemblyView.java \ $(MPMT_DIR)/DualSourceView.java \ $(MPMT_DIR)/event/AnChangeEvent.java \ $(MPMT_DIR)/event/AnChangeListener.java \ $(MPMT_DIR)/event/AnEventManager.java \ $(MPMT_DIR)/event/AnSelectionEvent.java \ $(MPMT_DIR)/ExperimentPickListElement.java \ $(MPMT_DIR)/ExperimentPickList.java \ $(MPMT_DIR)/ExperimentPickLists.java \ $(MPMT_DIR)/experiment_props/DataDescriptor.java \ $(MPMT_DIR)/experiment_props/ExperimentProperties.java \ $(MPMT_DIR)/experiment_props/Experiments.java \ $(MPMT_DIR)/experiment_props/PropDescriptor.java \ $(MPMT_DIR)/ExperimentsView.java \ $(MPMT_DIR)/export/ExportDialog.java \ $(MPMT_DIR)/export/Export.java \ $(MPMT_DIR)/export/ExportPanel.java \ $(MPMT_DIR)/export/ExportSupport.java \ $(MPMT_DIR)/filter/CustomEditPanel.java \ $(MPMT_DIR)/filter/CustomFilterAction.java \ $(MPMT_DIR)/filter/CustomFilterDialog.java \ $(MPMT_DIR)/filter/CustomPanel.java \ $(MPMT_DIR)/filter/FilterClause.java \ $(MPMT_DIR)/filter/FilterNavigationPanel.java \ $(MPMT_DIR)/filter/FilterParser.java \ $(MPMT_DIR)/filter/Filters.java \ $(MPMT_DIR)/filter/FilterStatusPanel.java \ $(MPMT_DIR)/filter/FilterTextField.java \ $(MPMT_DIR)/filter/KeywordsPanel.java \ $(MPMT_DIR)/filter/RedoFilterAction.java \ $(MPMT_DIR)/filter/RemoveAllFilterAction.java \ $(MPMT_DIR)/filter/UndoFilterAction.java \ $(MPMT_DIR)/flame/FlameBlock.java \ $(MPMT_DIR)/flame/FlameData.java \ $(MPMT_DIR)/flame/FlamePanel.java \ $(MPMT_DIR)/flame/FlameRow.java \ $(MPMT_DIR)/flame/FlameToolBar.java \ $(MPMT_DIR)/flame/FlameView.java \ $(MPMT_DIR)/FuncListDisp.java \ $(MPMT_DIR)/FunctionsView.java \ $(MPMT_DIR)/guitesting/GUITesting.java \ $(MPMT_DIR)/HeapView.java \ $(MPMT_DIR)/HotGapPanel.java \ $(MPMT_DIR)/IDispToModel.java \ $(MPMT_DIR)/IExtTreeModel.java \ $(MPMT_DIR)/InstructionFrequencyView.java \ $(MPMT_DIR)/IOView.java \ $(MPMT_DIR)/ipc/IPCCancelledException.java \ $(MPMT_DIR)/ipc/IPCContext.java \ $(MPMT_DIR)/ipc/IPCErrorReader.java \ $(MPMT_DIR)/ipc/IPCHandle.java \ $(MPMT_DIR)/ipc/IPCListener.java \ $(MPMT_DIR)/ipc/IPCLogger.java \ $(MPMT_DIR)/ipc/IPCProtocol.java \ $(MPMT_DIR)/ipc/IPCReader.java \ $(MPMT_DIR)/ipc/IPCRequestHeader.java \ $(MPMT_DIR)/ipc/IPCRequest.java \ $(MPMT_DIR)/ipc/IPCResponseHeader.java \ $(MPMT_DIR)/ipc/IPCResponse.java \ $(MPMT_DIR)/ipc/IPCResult.java \ $(MPMT_DIR)/ipc/IPCTester.java \ $(MPMT_DIR)/IPC.java \ $(MPMT_DIR)/IPCProcess.java \ $(MPMT_DIR)/ITreeToPanel.java \ $(MPMT_DIR)/KeyboardShortcuts.java \ $(MPMT_DIR)/LibraryVisibilityDialog.java \ $(MPMT_DIR)/LibraryVisibilityPanel.java \ $(MPMT_DIR)/LinesView.java \ $(MPMT_DIR)/mainview/BorderPanel.java \ $(MPMT_DIR)/mainview/MainViewPanel.java \ $(MPMT_DIR)/mainview/Panel.java \ $(MPMT_DIR)/mainview/SubviewAreaPanel.java \ $(MPMT_DIR)/mainview/Subview.java \ $(MPMT_DIR)/MemoryIndexObjectView.java \ $(MPMT_DIR)/metrics/BasicMetric.java \ $(MPMT_DIR)/metrics/CompareBarData.java \ $(MPMT_DIR)/metrics/IPCMetricsAPI.java \ $(MPMT_DIR)/metrics/MetricAttr.java \ $(MPMT_DIR)/metrics/MetricColors.java \ $(MPMT_DIR)/metrics/MetricLabel.java \ $(MPMT_DIR)/metrics/MetricNode.java \ $(MPMT_DIR)/metrics/MetricOption.java \ $(MPMT_DIR)/metrics/MetricsGUI.java \ $(MPMT_DIR)/metrics/MetricValue.java \ $(MPMT_DIR)/metrics/SelectableMetricNode.java \ $(MPMT_DIR)/metrics/ValueMetricNode.java \ $(MPMT_DIR)/MiniFuncListDisp.java \ $(MPMT_DIR)/navigation/ActionPanel.java \ $(MPMT_DIR)/navigation/NavigationPanel.java \ $(MPMT_DIR)/navigation/PanelDropTargetListener.java \ $(MPMT_DIR)/navigation/TopNavigationPanel.java \ $(MPMT_DIR)/navigation/View.java \ $(MPMT_DIR)/navigation/ViewPanel.java \ $(MPMT_DIR)/navigation/ViewsPanel.java \ $(MPMT_DIR)/NoMetricsSelectedPanel.java \ $(MPMT_DIR)/overview/AnBarTree.java \ $(MPMT_DIR)/overview/BarColorKey.java \ $(MPMT_DIR)/overview/Bar.java \ $(MPMT_DIR)/overview/BarPanel.java \ $(MPMT_DIR)/overview/CheckBoxBarPanel.java \ $(MPMT_DIR)/overview/GradientPanel.java \ $(MPMT_DIR)/overview/OuterPanel.java \ $(MPMT_DIR)/overview/Overview.java \ $(MPMT_DIR)/overview/OverviewPanel.java \ $(MPMT_DIR)/overview/OverviewView.java \ $(MPMT_DIR)/overview/ProgressBarPanel.java \ $(MPMT_DIR)/overview/TopButtonPanel.java \ $(MPMT_DIR)/overview/TurnerLabelPanel.java \ $(MPMT_DIR)/overview/TurnerPanel.java \ $(MPMT_DIR)/PCsView.java \ $(MPMT_DIR)/persistence/UserPref.java \ $(MPMT_DIR)/persistence/UserPrefPersistence.java \ $(MPMT_DIR)/picklist/PickListElement.java \ $(MPMT_DIR)/picklist/PickListEvent.java \ $(MPMT_DIR)/picklist/PickList.java \ $(MPMT_DIR)/picklist/PickListListener.java \ $(MPMT_DIR)/picklist/StringPickListElement.java \ $(MPMT_DIR)/picklist/StringPickList.java \ $(MPMT_DIR)/progress/CancelContext.java \ $(MPMT_DIR)/progress/Cancellable.java \ $(MPMT_DIR)/progress/InternalHandle.java \ $(MPMT_DIR)/progress/ProgressHandle.java \ $(MPMT_DIR)/progress/ProgressPanel.java \ $(MPMT_DIR)/progress/SystemProgressPanel.java \ $(MPMT_DIR)/PsParser.java \ $(MPMT_DIR)/remote/Authentication.java \ $(MPMT_DIR)/remote/AuthenticationPanel.java \ $(MPMT_DIR)/remote/CheckBoxList.java \ $(MPMT_DIR)/remote/CloseExperimentDialog.java \ $(MPMT_DIR)/remote/CloseExperimentPanel.java \ $(MPMT_DIR)/remote/ConnectionDialog.java \ $(MPMT_DIR)/remote/ConnectionManager.java \ $(MPMT_DIR)/remote/ConnectionPanel.java \ $(MPMT_DIR)/ResolveFilePathDialog.java \ $(MPMT_DIR)/ResolveFilePathPanel.java \ $(MPMT_DIR)/SelectedObject.java \ $(MPMT_DIR)/SelectionManager.java \ $(MPMT_DIR)/settings/AnSettingChangeEvent.java \ $(MPMT_DIR)/settings/CallTreePanel.java \ $(MPMT_DIR)/settings/CallTreeSetting.java \ $(MPMT_DIR)/settings/CompareModeSetting.java \ $(MPMT_DIR)/settings/ExportSettingsDialog.java \ $(MPMT_DIR)/settings/ExportSettingsPanel.java \ $(MPMT_DIR)/settings/FormatSetting.java \ $(MPMT_DIR)/settings/ImportSettingsDialog.java \ $(MPMT_DIR)/settings/ImportSettingsPanel.java \ $(MPMT_DIR)/settings/LibraryVisibilitySetting.java \ $(MPMT_DIR)/settings/MetricAttributes.java \ $(MPMT_DIR)/settings/MetricNameSelected.java \ $(MPMT_DIR)/settings/MetricNameSelection.java \ $(MPMT_DIR)/settings/MetricSelection.java \ $(MPMT_DIR)/settings/MetricsPanel.java \ $(MPMT_DIR)/settings/MetricsSetting.java \ $(MPMT_DIR)/settings/MetricState.java \ $(MPMT_DIR)/settings/MetricStates.java \ $(MPMT_DIR)/settings/MetricType.java \ $(MPMT_DIR)/settings/MMetric.java \ $(MPMT_DIR)/settings/PathMapSetting.java \ $(MPMT_DIR)/settings/PathmapsPanel.java \ $(MPMT_DIR)/settings/SearchPathPanel.java \ $(MPMT_DIR)/settings/SearchPathSetting.java \ $(MPMT_DIR)/settings/Setting.java \ $(MPMT_DIR)/settings/Settings.java \ $(MPMT_DIR)/settings/SourceDisassemblySetting.java \ $(MPMT_DIR)/settings/TableSettings.java \ $(MPMT_DIR)/settings/TimelineSetting.java \ $(MPMT_DIR)/settings/ViewModeEnabledSetting.java \ $(MPMT_DIR)/settings/ViewModeSetting.java \ $(MPMT_DIR)/settings/ViewsSetting.java \ $(MPMT_DIR)/SourceDisassemblyView.java \ $(MPMT_DIR)/SourceDisp.java \ $(MPMT_DIR)/SourceView.java \ $(MPMT_DIR)/statecolors/AnColorChooser.java \ $(MPMT_DIR)/statecolors/ChooserStateView.java \ $(MPMT_DIR)/statecolors/ColorMap.java \ $(MPMT_DIR)/statecolors/ColorRule.java \ $(MPMT_DIR)/statecolors/StackState.java \ $(MPMT_DIR)/statecolors/StackStateList.java \ $(MPMT_DIR)/statecolors/StackView.java \ $(MPMT_DIR)/statecolors/StackViewState.java \ $(MPMT_DIR)/statecolors/StateColorMap.java \ $(MPMT_DIR)/StatisticsView.java \ $(MPMT_DIR)/statuspanel/StatusComponentHandle.java \ $(MPMT_DIR)/statuspanel/StatusComponent.java \ $(MPMT_DIR)/statuspanel/StatusHandleFactory.java \ $(MPMT_DIR)/statuspanel/StatusLabelHandle.java \ $(MPMT_DIR)/statuspanel/StatusLabel.java \ $(MPMT_DIR)/statuspanel/StatusLabelValueHandle.java \ $(MPMT_DIR)/statuspanel/StatusPanel.java \ $(MPMT_DIR)/SummaryPanel.java \ $(MPMT_DIR)/table/AnJTable.java \ $(MPMT_DIR)/table/AnTableHeaderPanel.java \ $(MPMT_DIR)/table/AnTableScrollPane.java \ $(MPMT_DIR)/table/AttributePanel.java \ $(MPMT_DIR)/table/ExclusiveAndInclusivePanel.java \ $(MPMT_DIR)/table/ExclusiveOrInclusivePanel.java \ $(MPMT_DIR)/table/HeaderMouseHandler.java \ $(MPMT_DIR)/table/MetricPanelDropTargetListener.java \ $(MPMT_DIR)/table/MetricPanel.java \ $(MPMT_DIR)/timeline2/cursorevent/CursorEvent.java \ $(MPMT_DIR)/timeline2/cursorevent/CursorMoveEvent.java \ $(MPMT_DIR)/timeline2/cursorevent/CursorSetEvent.java \ $(MPMT_DIR)/timeline2/data/GenericEvent.java \ $(MPMT_DIR)/timeline2/data/SampleEvent.java \ $(MPMT_DIR)/timeline2/data/StackEvent.java \ $(MPMT_DIR)/timeline2/Entity.java \ $(MPMT_DIR)/timeline2/EventDetails.java \ $(MPMT_DIR)/timeline2/IconRuler.java \ $(MPMT_DIR)/timeline2/MetaExperiment.java \ $(MPMT_DIR)/timeline2/RowData.java \ $(MPMT_DIR)/timeline2/RowDataRequestParams.java \ $(MPMT_DIR)/timeline2/RowDefinition.java \ $(MPMT_DIR)/timeline2/RowGeometry.java \ $(MPMT_DIR)/timeline2/TimelineDraw.java \ $(MPMT_DIR)/timeline2/TimelineSelectionEvent.java \ $(MPMT_DIR)/timeline2/TimelineSelectionRowEvent.java \ $(MPMT_DIR)/timeline2/TimelineVariable.java \ $(MPMT_DIR)/timeline2/TimelineView.java \ $(MPMT_DIR)/timeline2/TL2ControlPanel.java \ $(MPMT_DIR)/timeline2/TL2CoordCalcData.java \ $(MPMT_DIR)/timeline2/TL2DataFetcher.java \ $(MPMT_DIR)/timeline2/TL2DataSnapshot.java \ $(MPMT_DIR)/timeline2/TL2Drawer.java \ $(MPMT_DIR)/timeline2/TLExperiment.java \ $(MPMT_DIR)/timeline_common/CoordCalcDataImpl.java \ $(MPMT_DIR)/timeline_common/CoordCalcDataMaster.java \ $(MPMT_DIR)/timeline_common/CoordCalcDataReader.java \ $(MPMT_DIR)/timeline_common/CoordCalcTimeImpl.java \ $(MPMT_DIR)/timeline_common/CoordCalcTimeMaster.java \ $(MPMT_DIR)/timeline_common/CoordCalcTimeReader.java \ $(MPMT_DIR)/timeline_common/TimelineCaliper.java \ $(MPMT_DIR)/timeline_common/TimelineCursor.java \ $(MPMT_DIR)/timeline_common/TimelineDrawer.java \ $(MPMT_DIR)/timeline_common/TimelinePanel.java \ $(MPMT_DIR)/timeline_common/TimelineSelectionCaliperEvent.java \ $(MPMT_DIR)/timeline_common/TimelineSelectionGenericEvent.java \ $(MPMT_DIR)/timeline_common/TimelineSelectionHistoryEvent.java \ $(MPMT_DIR)/timeline_common/TimelineSelectionListener.java \ $(MPMT_DIR)/timeline_common/VerticalRowRuler.java \ $(MPMT_DIR)/timeline/events/DeadlockEvent.java \ $(MPMT_DIR)/timeline/events/DetailsIPC.java \ $(MPMT_DIR)/timeline/events/DurationEvent.java \ $(MPMT_DIR)/timeline/events/EventDetail.java \ $(MPMT_DIR)/timeline/events/ExtendedEvent.java \ $(MPMT_DIR)/timeline/events/HeapEvent.java \ $(MPMT_DIR)/timeline/events/HWCEvent.java \ $(MPMT_DIR)/timeline/events/IOEvent.java \ $(MPMT_DIR)/timeline/events/MPIEvent.java \ $(MPMT_DIR)/timeline/events/ProfileEvent.java \ $(MPMT_DIR)/timeline/events/RaceEvent.java \ $(MPMT_DIR)/timeline/events/Sample.java \ $(MPMT_DIR)/timeline/events/StateEvent.java \ $(MPMT_DIR)/timeline/events/SyncEvent.java \ $(MPMT_DIR)/toolbar/FindTextPanel.java \ $(MPMT_DIR)/toolbar/ToolBarFiller.java \ $(MPMT_DIR)/toolbar/ToolBarPanel.java \ $(MPMT_DIR)/toolbar/ToolBarSeparator.java \ $(MPMT_DIR)/util/gui/ActionTextField.java \ $(MPMT_DIR)/util/gui/AnBorderPanel.java \ $(MPMT_DIR)/util/gui/AnCheckBox.java \ $(MPMT_DIR)/util/gui/AnDialog2.java \ $(MPMT_DIR)/util/gui/AnDialogOuterPanel.java \ $(MPMT_DIR)/util/gui/AnGradientPanel.java \ $(MPMT_DIR)/util/gui/AnInsetsPanel.java \ $(MPMT_DIR)/util/gui/AnJList.java \ $(MPMT_DIR)/util/gui/AnJPanel.java \ $(MPMT_DIR)/util/gui/AnJScrollPane.java \ $(MPMT_DIR)/util/gui/AnJTree.java \ $(MPMT_DIR)/util/gui/AnLongScrollBar.java \ $(MPMT_DIR)/util/gui/AnMenuBar.java \ $(MPMT_DIR)/util/gui/AnScrollBarUI.java \ $(MPMT_DIR)/util/gui/AnSplitPaneFixedRightSize.java \ $(MPMT_DIR)/util/gui/AnSplitPaneInternal.java \ $(MPMT_DIR)/util/gui/AnSplitPane.java \ $(MPMT_DIR)/util/gui/AnTabbedPane.java \ $(MPMT_DIR)/util/gui/AnTabbedPaneUI.java \ $(MPMT_DIR)/util/gui/AnTextIcon.java \ $(MPMT_DIR)/util/gui/AnUtility.java \ $(MPMT_DIR)/util/gui/RainbowColorScale.java \ $(MPMT_DIR)/util/gui/ToolTipPopup.java \ $(MPMT_DIR)/util/ruler/LabelCoordinateCalculator.java \ $(MPMT_DIR)/util/ruler/RangeRuler.java \ $(MPMT_DIR)/util/ruler/Ruler.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesBytes.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesGeneric.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesLabelList.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesLong.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesNanoseconds.java \ $(MPMT_DIR)/util/ruler/valuetypes/ValuesWithUnits.java \ $(MPMT_DIR)/util/zoomruler/OverlayMouseHandler.java \ $(MPMT_DIR)/util/zoomruler/PaintListener.java \ $(MPMT_DIR)/util/zoomruler/ZoomRulerComponent.java \ $(MPMT_DIR)/util/zoomruler/ZoomRulerEvent.java \ $(MPMT_DIR)/util/zoomruler/ZoomRulerListener.java \ $(MPMT_DIR)/util/zoomruler/ZoomRulerOverlay.java \ $(MPMT_DIR)/ViewDisplayPanel.java \ $(MPMT_DIR)/welcome/WelcomeButton.java \ $(MPMT_DIR)/welcome/WelcomeInnerPanel.java \ $(MPMT_DIR)/welcome/WelcomePanel.java \ $(MPMT_DIR)/welcome/WelcomeView.java MPMT_FILES = \ $(MPMT_SRC:%.java=$(srcdir)/%.java) \ $(ANALYZER_FILES) ICONS = \ $(MPMT_DIR)/icons/add.png \ $(MPMT_DIR)/icons/addtablecolumns.png \ $(MPMT_DIR)/icons/analyzer64.png \ $(MPMT_DIR)/icons/apply_filter.png \ $(MPMT_DIR)/icons/apply_mtrs.png \ $(MPMT_DIR)/icons/attributed.png \ $(MPMT_DIR)/icons/back_filter.png \ $(MPMT_DIR)/icons/backward.png \ $(MPMT_DIR)/icons/badexperiment.png \ $(MPMT_DIR)/icons/base1.png \ $(MPMT_DIR)/icons/base2.png \ $(MPMT_DIR)/icons/blank.png \ $(MPMT_DIR)/icons/bubble_icon_16.png \ $(MPMT_DIR)/icons/callee.png \ $(MPMT_DIR)/icons/caller.png \ $(MPMT_DIR)/icons/cancelProcess.png \ $(MPMT_DIR)/icons/class.png \ $(MPMT_DIR)/icons/collect.png \ $(MPMT_DIR)/icons/color.png \ $(MPMT_DIR)/icons/compareAbsolute.png \ $(MPMT_DIR)/icons/compareDelta.png \ $(MPMT_DIR)/icons/compareHamburger.png \ $(MPMT_DIR)/icons/compare.png \ $(MPMT_DIR)/icons/compareRatio.png \ $(MPMT_DIR)/icons/compareReverse.png \ $(MPMT_DIR)/icons/connect.png \ $(MPMT_DIR)/icons/data.png \ $(MPMT_DIR)/icons/delete.png \ $(MPMT_DIR)/icons/down.png \ $(MPMT_DIR)/icons/errorNew.png \ $(MPMT_DIR)/icons/error.png \ $(MPMT_DIR)/icons/errorWarningNew.png \ $(MPMT_DIR)/icons/exclusive.png \ $(MPMT_DIR)/icons/exe_elf.png \ $(MPMT_DIR)/icons/expandcollaps.png \ $(MPMT_DIR)/icons/experiment.png \ $(MPMT_DIR)/icons/expgroup.png \ $(MPMT_DIR)/icons/fileResolved.png \ $(MPMT_DIR)/icons/fileUnResolved.png \ $(MPMT_DIR)/icons/filter.png \ $(MPMT_DIR)/icons/find_next.png \ $(MPMT_DIR)/icons/find_prev.png \ $(MPMT_DIR)/icons/forward_filter.png \ $(MPMT_DIR)/icons/forward.png \ $(MPMT_DIR)/icons/func_item.png \ $(MPMT_DIR)/icons/gear.png \ $(MPMT_DIR)/icons/gobackward.png \ $(MPMT_DIR)/icons/godown.png \ $(MPMT_DIR)/icons/goforward.png \ $(MPMT_DIR)/icons/goup.png \ $(MPMT_DIR)/icons/green100.png \ $(MPMT_DIR)/icons/hamburgerBlank.png \ $(MPMT_DIR)/icons/hamburgerFocused.png \ $(MPMT_DIR)/icons/hamburger.png \ $(MPMT_DIR)/icons/heaptrace.png \ $(MPMT_DIR)/icons/hollowArrowDown.png \ $(MPMT_DIR)/icons/hollowArrowLeft.png \ $(MPMT_DIR)/icons/hollowArrowRight.png \ $(MPMT_DIR)/icons/hollowArrowUp.png \ $(MPMT_DIR)/icons/hot.png \ $(MPMT_DIR)/icons/hwc.png \ $(MPMT_DIR)/icons/inclusive.png \ $(MPMT_DIR)/icons/i_o_usage_16.png \ $(MPMT_DIR)/icons/jar.png \ $(MPMT_DIR)/icons/more_icon.png \ $(MPMT_DIR)/icons/mpitrace.png \ $(MPMT_DIR)/icons/nav_bar_arrow.png \ $(MPMT_DIR)/icons/nextview.png \ $(MPMT_DIR)/icons/number.png \ $(MPMT_DIR)/icons/oldexperiment.png \ $(MPMT_DIR)/icons/open.png \ $(MPMT_DIR)/icons/panhand.png \ $(MPMT_DIR)/icons/percent.png \ $(MPMT_DIR)/icons/previousview.png \ $(MPMT_DIR)/icons/profile.png \ $(MPMT_DIR)/icons/races.png \ $(MPMT_DIR)/icons/redo.png \ $(MPMT_DIR)/icons/removeBlank.png \ $(MPMT_DIR)/icons/removeFocused.png \ $(MPMT_DIR)/icons/remove.png \ $(MPMT_DIR)/icons/reset.png \ $(MPMT_DIR)/icons/sample.png \ $(MPMT_DIR)/icons/save.png \ $(MPMT_DIR)/icons/smallBlank.png \ $(MPMT_DIR)/icons/small_down_focused.png \ $(MPMT_DIR)/icons/small_down.png \ $(MPMT_DIR)/icons/small_left.png \ $(MPMT_DIR)/icons/small_right.png \ $(MPMT_DIR)/icons/small_up_focused.png \ $(MPMT_DIR)/icons/small_up.png \ $(MPMT_DIR)/icons/stop.png \ $(MPMT_DIR)/icons/synctrace.png \ $(MPMT_DIR)/icons/tab.png \ $(MPMT_DIR)/icons/time.png \ $(MPMT_DIR)/icons/undo.png \ $(MPMT_DIR)/icons/up.png \ $(MPMT_DIR)/icons/values.png \ $(MPMT_DIR)/icons/warnexperiment.png \ $(MPMT_DIR)/icons/warningNew.png \ $(MPMT_DIR)/icons/warning.png \ $(MPMT_DIR)/icons/welcomeBackgroundShadow.png \ $(MPMT_DIR)/icons/zoom_in.png \ $(MPMT_DIR)/icons/zoom_out.png \ $(MPMT_DIR)/icons/circleBlue.gif \ $(MPMT_DIR)/icons/circleGreen.gif \ $(MPMT_DIR)/icons/circleOrange.gif \ $(MPMT_DIR)/icons/circleRed.gif \ $(MPMT_DIR)/icons/performanceAnalyzerSplash.gif GPROFNG_CLASSES = \ $(MPMT_DIR)/*.class \ $(MPMT_DIR)/*/*.class \ $(MPMT_DIR)/*/*/*.class \ $(MPMT_DIR)/*/*/*/*.class GPROFNG_FORMS = \ $(MPMT_DIR)/AboutPanel.form \ $(MPMT_DIR)/CannotFindFilePanel.form \ $(MPMT_DIR)/collect/CollectorOpenPanel.form \ $(MPMT_DIR)/collect/CollectPanel2.form \ $(MPMT_DIR)/collect/CollectPanel3.form \ $(MPMT_DIR)/collect/HWCSelectPanel.form \ $(MPMT_DIR)/compare/CompareGroupsPanel.form \ $(MPMT_DIR)/compare/CompareSimplePanel.form \ $(MPMT_DIR)/compare/CompareStatusPanel.form \ $(MPMT_DIR)/compare/ExperimentGroupsPanel.form \ $(MPMT_DIR)/ConfigurationPanel.form \ $(MPMT_DIR)/export/ExportPanel.form \ $(MPMT_DIR)/filter/CustomPanel.form \ $(MPMT_DIR)/filter/FilterNavigationPanel.form \ $(MPMT_DIR)/filter/FilterStatusPanel.form \ $(MPMT_DIR)/filter/KeywordsPanel.form \ $(MPMT_DIR)/LibraryVisibilityPanel.form \ $(MPMT_DIR)/mainview/BorderPanel.form \ $(MPMT_DIR)/mainview/MainViewPanel.form \ $(MPMT_DIR)/navigation/ActionPanel.form \ $(MPMT_DIR)/navigation/TopNavigationPanel.form \ $(MPMT_DIR)/navigation/ViewPanel.form \ $(MPMT_DIR)/navigation/ViewsPanel.form \ $(MPMT_DIR)/NoMetricsSelectedPanel.form \ $(MPMT_DIR)/overview/BarPanel.form \ $(MPMT_DIR)/overview/CheckBoxBarPanel.form \ $(MPMT_DIR)/overview/GradientPanel.form \ $(MPMT_DIR)/overview/OuterPanel.form \ $(MPMT_DIR)/overview/OverviewPanel.form \ $(MPMT_DIR)/overview/ProgressBarPanel.form \ $(MPMT_DIR)/overview/TopButtonPanel.form \ $(MPMT_DIR)/overview/TurnerLabelPanel.form \ $(MPMT_DIR)/overview/TurnerPanel.form \ $(MPMT_DIR)/progress/ProgressPanel.form \ $(MPMT_DIR)/remote/AuthenticationPanel.form \ $(MPMT_DIR)/remote/CloseExperimentPanel.form \ $(MPMT_DIR)/remote/ConnectionPanel.form \ $(MPMT_DIR)/ResolveFilePathPanel.form \ $(MPMT_DIR)/settings/CallTreePanel.form \ $(MPMT_DIR)/settings/ExportSettingsPanel.form \ $(MPMT_DIR)/settings/ImportSettingsPanel.form \ $(MPMT_DIR)/settings/MetricsPanel.form \ $(MPMT_DIR)/settings/PathmapsPanel.form \ $(MPMT_DIR)/settings/SearchPathPanel.form \ $(MPMT_DIR)/statuspanel/StatusPanel.form \ $(MPMT_DIR)/util/gui/AnDialogOuterPanel.form \ $(MPMT_DIR)/util/gui/AnInsetsPanel.form \ $(MPMT_DIR)/welcome/WelcomeInnerPanel.form \ $(MPMT_DIR)/welcome/WelcomePanel.form anmodule_MF = $(srcdir)/gprofng-gui.mf MPMT_PROPERTIES = $(MPMT_DIR)/Bundle.properties LocaleString.class: $(srcdir)/tools/LocaleString.java @echo "================= $@" $(JAVAC) $(JAVAC_FLAGS) -d . $(srcdir)/tools/LocaleString.java $(MPMT_PROPERTIES): $(MPMT_FILES) LocaleString.class \ $(srcdir)/gprofng.properties @echo "================= $@" mkdir -m 777 -p $(@D) echo "# THIS FILE IS AUTO-GENERATED. DON'T EDIT IT." > $@ echo "" >> $@ cat $(srcdir)/gprofng.properties >> $@ cat $(MPMT_FILES) | $(JAVA) $(JAVA_FLAGS) -cp . LocaleString >> $@ $(GPROFNG_JAR): $(anmodule_MF) $(MPMT_FILES) \ $(MPMT_PROPERTIES) $(ICONS:%=$(srcdir)/%) @echo "================= $@" rm -f $(GPROFNG_CLASSES) $(JAVAC) -cp $(srcdir) $(JAVAC_FLAGS) -d . $(srcdir)/$(MPMT_DIR)/Analyzer.java $(JAR) $(JAR_FLAGS) $@ $(anmodule_MF) $(GPROFNG_CLASSES) \ $(ICONS:%=-C $(srcdir) %) $(MPMT_PROPERTIES) # # Standalone gprofng GUI # ANALYZER_SRC = \ $(ANALYZER_DIR)/AnEnvironment.java \ $(ANALYZER_DIR)/AnLog.java \ $(ANALYZER_DIR)/AnMain.java ANALYZER_FILES = $(ANALYZER_SRC:%.java=$(srcdir)/%.java) ANALYZER_MF = $(srcdir)/analyzer_st.mf ANALYZER_CLASSES = $(ANALYZER_DIR)/*.class ANALYZER_PROPERTIES = $(ANALYZER_DIR)/Bundle.properties $(ANALYZER_PROPERTIES): $(ANALYZER_FILES) LocaleString.class @echo "================= $@" mkdir -m 777 -p $(@D) echo "# THIS FILE IS AUTO-GENERATED. DON'T EDIT IT." > $@ echo "" >> $@ cat $(ANALYZER_FILES) | $(JAVA) $(JAVA_FLAGS) -cp . LocaleString >> $@ $(ANALYZER_JAR): $(GPROFNG_JAR) \ $(ANALYZER_MF) $(ANALYZER_FILES) $(ANALYZER_PROPERTIES) @echo "================= $@" rm -f $(ANALYZER_CLASSES) $(JAVAC) -classpath $(GPROFNG_JAR) $(JAVAC_FLAGS) -d . $(ANALYZER_FILES) echo "Create $(ANALYZER_JAR) in `pwd`" $(JAR) $(JAR_FLAGS) $@ $(ANALYZER_MF) $(ANALYZER_CLASSES) \ $(ANALYZER_PROPERTIES) # Rules for generating a jar file implementing Java collector API # COLLECTOR_SRC = $(COLLECTOR_DIR)/CollectorAPI.java collector_FILES = $(COLLECTOR_SRC:%.java=$(srcdir)/%.java) collector_MF = $(srcdir)/gprofng-collector.mf collector_CLASSES = $(COLLECTOR_DIR)/*.class $(COLLECTOR_JAR): $(GPROFNG_JAR) $(collector_FILES) $(collector_MF) @echo "================= $@" rm -f $(collector_CLASSES) $(JAVAC) $(JAVAC_FLAGS) -d . $(collector_FILES) $(JAR) $(JAR_FLAGS) $@ $(collector_MF) $(collector_CLASSES) bin_SCRIPTS = gp-display-gui CLEANFILES = gp-display-gui $(GPROFNG_JAR) $(ANALYZER_JAR) $(COLLECTOR_JAR) \ $(GPROFNG_CLASSES) $(ANALYZER_CLASSES) $(collector_CLASSES) \ $(ANALYZER_PROPERTIES) $(MPMT_PROPERTIES) LocaleString*.class gp-display-gui: $(srcdir)/gprofng-gui.sh @echo "================= $@" sed -e "s~REPLACE_ME_WITH_VERSION~$(VERSION)~" < $(srcdir)/gprofng-gui.sh \ | sed -e "s~GPROFNG_bindir=~GPROFNG_bindir='$(bindir)'~" \ | sed -e "s~GPROFNG_libdir=~GPROFNG_libdir='$(libdir)'~" \ | sed -e "s~GPROFNG_datadir=~GPROFNG_datadir='$(datadir)'~" \ > $@ chmod +x $@ pkgdata_DATA = $(ANALYZER_JAR) $(COLLECTOR_JAR) $(GPROFNG_JAR) EXTRA_DIST = $(MPMT_SRC) $(ANALYZER_SRC) $(COLLECTOR_SRC) \ $(ICONS) $(GPROFNG_FORMS) \ aclocal.m4 analyzer_st.mf compile configure.ac configure \ gprofng-collector.mf gprofng-gui.mf gprofng-gui.sh gprofng-gui.spec \ gprofng.properties INSTALL install-sh Makefile.am Makefile.in missing \ README AUTHORS NEWS tools include doc/local.mk gprofng-gui-1.0/COPYING0000644000175000017500000010451314517772113011566 00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . gprofng-gui-1.0/org/0000755000175000017500000000000014517775726011413 500000000000000gprofng-gui-1.0/org/gprofng/0000755000175000017500000000000014517775726013055 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/0000755000175000017500000000000014517775727014033 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/toolbar/0000755000175000017500000000000014517775726015474 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/toolbar/FindTextPanel.java0000644000175000017500000002467614517772113020766 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.toolbar; import org.gprofng.mpmt.AnIconButton; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.picklist.StringPickList; import org.gprofng.mpmt.picklist.StringPickListElement; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; public class FindTextPanel extends JPanel { private JLabel findLabel; private JComboBox findComboBox; private AnIconButton findUp; private AnIconButton findDown; private JCheckBox findCase; public static final int MAX_FIND_ITEMS = 10; private ActionListener findActionListener; private DocumentListener findDocumentListener; public FindTextPanel() { GridBagConstraints gridBagConstraints; int gridx = 0; setLayout(new GridBagLayout()); setOpaque(false); // Combobox findComboBox = new FindComboBox(); findComboBox.setToolTipText(AnLocale.getString("Find text in view...")); AnUtility.setAccessibleContext( findComboBox.getAccessibleContext(), findComboBox.getToolTipText()); findComboBox.setFont(findComboBox.getFont().deriveFont(Font.PLAIN)); findComboBox.setMaximumRowCount(MAX_FIND_ITEMS); // findComboBox.setEditable(true); // This causes the panel to 'jump' up/down. Moving to // setConrolsEnabled. Don't understand..... findComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxx"); initializeFindTexts(UserPref.getInstance().getFindPickList(), null); findComboBox.setSelectedItem(""); findComboBox.setPreferredSize(new Dimension(findComboBox.getPreferredSize().width, 20)); findComboBox.setEnabled(true); // Combobox Listeners findComboBox.addPopupMenuListener( new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { find(getFindComboBoxText(), true, findCase.isSelected()); } @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); findComboBox .getEditor() .addActionListener( new ActionListener() { @Override public void actionPerformed(final ActionEvent event) { if (event.getID() == ActionEvent.ACTION_PERFORMED) { find(getFindComboBoxText(), true, findCase.isSelected()); } } }); findDocumentListener = new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { resetComboBoxState(); } @Override public void removeUpdate(DocumentEvent e) { resetComboBoxState(); } @Override public void changedUpdate(DocumentEvent e) { resetComboBoxState(); } }; ((JTextField) findComboBox.getEditor().getEditorComponent()) .getDocument() .addDocumentListener(findDocumentListener); findComboBox.addPopupMenuListener( new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { resetComboBoxState(); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); ((JTextField) findComboBox.getEditor().getEditorComponent()) .addKeyListener( new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { if (e.getKeyChar() == KeyEvent.VK_ENTER && e.getModifiers() == KeyEvent.SHIFT_MASK) { find(getFindComboBoxText(), false, findCase.isSelected()); } else { super.keyTyped(e); } } }); findLabel = new JLabel(); AnUtility.setTextAndAccessibleContext(findLabel, AnLocale.getString("Find:")); findLabel.setDisplayedMnemonic(AnLocale.getString('n', "MN_FindLabel")); findLabel.setLabelFor(findComboBox); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 4, 0, 0); add(findLabel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 4, 0, 0); add(findComboBox, gridBagConstraints); // Up findUp = new AnIconButton(AnUtility.prev_icon); findUp.setToolTipText(AnLocale.getString("Find Previous") + " (Shift+Enter)"); findUp.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { find(getFindComboBoxText(), false, findCase.isSelected()); } }); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 2, 0, 0); add(findUp, gridBagConstraints); // Down findDown = new AnIconButton(AnUtility.next_icon); findDown.setToolTipText(AnLocale.getString("Find Next") + " (Enter)"); findDown.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { find(getFindComboBoxText(), true, findCase.isSelected()); } }); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 0, 0, 0); add(findDown, gridBagConstraints); // Case findCase = new JCheckBox(AnLocale.getString("Match Case")); AnUtility.setAccessibleContext(findCase.getAccessibleContext(), findCase.getText()); findCase.setMnemonic(AnLocale.getString('C', "FindMatchCaseMN")); findCase.setFont(findCase.getFont().deriveFont(Font.PLAIN)); findCase.setOpaque(false); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 0, 0, 2); add(findCase, gridBagConstraints); } private class FindComboBox extends JComboBox { @Override public void paint(Graphics g) { super.paint(g); // To change body of generated methods, choose Tools | Templates. int yOffset = getSize().height - 6; String val = (String) findComboBox.getSelectedItem(); if (val == null || val.length() == 0) { String helpText = AnLocale.getString("Find text in view"); g.setColor(new Color(190, 190, 190)); g.drawString(helpText, 7, yOffset); } ((JTextField) getEditor().getEditorComponent()) .setToolTipText(AnLocale.getString("Find Text in View")); } } public void initializeFindTexts(StringPickList spl, String selected) { findComboBox.removeActionListener(findActionListener); ((JTextField) findComboBox.getEditor().getEditorComponent()) .getDocument() .removeDocumentListener(findDocumentListener); findComboBox.removeAllItems(); for (StringPickListElement elem : spl.getStringElements()) { findComboBox.addItem(elem.getString()); } if (selected != null) { findComboBox.setSelectedItem(selected); } findComboBox.addActionListener(findActionListener); ((JTextField) findComboBox.getEditor().getEditorComponent()) .getDocument() .addDocumentListener(findDocumentListener); } private void resetComboBoxState() { JTextField textField = (JTextField) findComboBox.getEditor().getEditorComponent(); textField.setForeground(Color.BLACK); findComboBox.setToolTipText(""); } public void setConrolsEnabled(boolean enabled) { findLabel.setEnabled(enabled); findComboBox.setEditable(enabled); findComboBox.setEnabled(enabled); findUp.setEnabled(enabled); findDown.setEnabled(enabled); findCase.setEnabled(enabled); } private String getFindComboBoxText() { JTextField textField = (JTextField) findComboBox.getEditor().getEditorComponent(); return textField.getText(); } private void updateFindComboBox(String str) { String selected = getFindComboBoxText(); UserPref.getInstance().getFindPickList().addElement(str); initializeFindTexts(UserPref.getInstance().getFindPickList(), selected); } private void find(final String str, final boolean next, boolean caseSensitive) { final int status; if ((str != null) && (str.length() == 0)) { return; } Object progressBarHandle = AnWindow.getInstance() .getSystemProgressPanel() .progressBarStart(AnLocale.getString("Searching")); status = AnWindow.getInstance().getViews().getCurrentViewDisplay().find(str, next, caseSensitive); JTextField findTextField = (JTextField) findComboBox.getEditor().getEditorComponent(); if (status == -1) { findTextField.setForeground(Color.RED); findComboBox.setToolTipText(AnLocale.getString("Text not found")); } else { findTextField.setForeground(Color.BLACK); findComboBox.setToolTipText(AnLocale.getString("")); } updateFindComboBox(str); AnWindow.getInstance().getSystemProgressPanel().progressBarStop(progressBarHandle); } } gprofng-gui-1.0/org/gprofng/mpmt/toolbar/ToolBarSeparator.java0000644000175000017500000000270014517772113021464 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.toolbar; import org.gprofng.analyzer.AnEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.JPanel; import javax.swing.JSeparator; /** * @author tpreisle */ public class ToolBarSeparator extends JPanel { public ToolBarSeparator(int leftSpace, int rightSpace) { setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); setLayout(new GridBagLayout()); JSeparator separator = new JSeparator(JSeparator.VERTICAL); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.VERTICAL; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(2, leftSpace, 2, rightSpace); add(separator, gridBagConstraints); } } gprofng-gui-1.0/org/gprofng/mpmt/toolbar/ToolBarFiller.java0000644000175000017500000000165614517772113020752 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.toolbar; import java.awt.Dimension; import javax.swing.Box.Filler; /** * @author tpreisle */ public class ToolBarFiller extends Filler { public ToolBarFiller(int i) { super(new Dimension(i, 0), new Dimension(i, 0), new Dimension(i, 0)); } } gprofng-gui-1.0/org/gprofng/mpmt/toolbar/ToolBarPanel.java0000644000175000017500000001073114517772113020566 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.toolbar; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.KeyboardShortcuts; import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JToolBar; public class ToolBarPanel extends JPanel { private JPanel controlPanel; private JComponent separator; private JComponent currentControls = null; private FindTextPanel findTextPanel; public ToolBarPanel(JToolBar toolBar) { initToolBarPanel(toolBar); } // Initialize aux area private void initToolBarPanel(JToolBar toolBar) { GridBagConstraints gridBagConstraints; int gridx = 0; JPanel tbPanel = this; tbPanel.setBorder( BorderFactory.createMatteBorder(1, 0, 1, 0, AnEnvironment.TOOLBAR_BORDER_COLOR)); tbPanel.setLayout(new GridBagLayout()); tbPanel.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); // Toolbar gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = gridx++; // gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(1, 0, 1, 0); tbPanel.add(toolBar, gridBagConstraints); separator = new ToolBarSeparator(3, 6); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = gridx++; gridBagConstraints.fill = GridBagConstraints.VERTICAL; gridBagConstraints.insets = new Insets(1, 0, 2, 0); tbPanel.add(separator, gridBagConstraints); // Control panel controlPanel = new JPanel(); controlPanel.setLayout(new BorderLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = gridx++; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(1, 0, 1, 0); tbPanel.add(controlPanel, gridBagConstraints); // Find panel findTextPanel = new FindTextPanel(); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.EAST; gridBagConstraints.gridx = gridx++; gridBagConstraints.weightx = 1.0; tbPanel.add(findTextPanel, gridBagConstraints); separator.setVisible(false); controlPanel.setVisible(false); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getInputMap(JComponent.WHEN_FOCUSED) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getActionMap() .put( KeyboardShortcuts.helpActionShortcut, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { // Analyzer.getInstance().showHelp(null); AnWindow.getInstance().getViews().getCurrentViewDisplay().showHelp(); } }); } public void setControls(JComponent component) { removeControls(); controlPanel.add(component); currentControls = component; separator.setVisible(true); controlPanel.setVisible(true); } public FindTextPanel getFindTextPanel() { return findTextPanel; } public JComponent getControls() { return currentControls; } public void removeControls() { controlPanel.removeAll(); currentControls = null; separator.setVisible(false); controlPanel.setVisible(false); } } gprofng-gui-1.0/org/gprofng/mpmt/AnLocale.java0000644000175000017500000000724114517772113016262 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.guitesting.GUITesting; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; public final class AnLocale { private static boolean addDebugInfo = false; private static Locale locale = Locale.getDefault(); private static ResourceBundle resource = null; static { try { if (!GUITesting.getInstance().isRunningUnderNB()) { ClassLoader loader = getLoader("org-gprofng-mpmt"); resource = ResourceBundle.getBundle("org.gprofng.mpmt.Bundle", locale, loader); } } catch (MissingResourceException e) { System.err.println("Cannot find resource bundle."); } } // Get the locale ClassLoader public static ClassLoader getLoader(String name) { String path; URL[] urls; if (null == Analyzer.fdhome) { Analyzer.initPath(false); // Initialize Analyzer.fdhome } if (name.equals("analyzer_help")) { path = "file:" + Analyzer.fdhome + "/modules/docs/"; } else { path = "file:" + Analyzer.fdhome + "/modules/autoload/"; } try { urls = new URL[] { new URL(path + "locale/" + name + "_" + locale.getLanguage() + ".jar"), new URL( path + "locale/" + name + "_" + locale.getLanguage() + "_" + locale.getCountry() + ".jar"), new URL(path + name + ".jar") }; } catch (MalformedURLException e) { return null; } return new URLClassLoader(urls); } private static String addDebugInfo(String ret) { ret = "XXX>" + ret + ". */ package org.gprofng.mpmt; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import javax.swing.JPanel; public final class LinesView extends FuncListDisp implements AnChangeListener { public LinesView() { super(AnWindow.getInstance(), AnDisplay.DSP_Lines, 0, AnVariable.HELP_TabsLines); setAccessibility(AnLocale.getString("Lines")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("LinesView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public JPanel getToolbarPanel() { return null; } } gprofng-gui-1.0/org/gprofng/mpmt/AnIconButton.java0000644000175000017500000000442414517772113017147 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import java.awt.Color; import java.awt.Insets; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.Icon; import javax.swing.JButton; public class AnIconButton extends JButton implements MouseListener, FocusListener { private Insets insets = new Insets(2, 2, 2, 2); public AnIconButton(Icon icon) { super(icon); setBorder(javax.swing.BorderFactory.createLineBorder(new Color(115, 115, 115))); setOpaque(false); setContentAreaFilled(false); setBorderPainted(false); addMouseListener(this); addFocusListener(this); } @Override public Insets getInsets() { return insets; } @Override public void setMargin(Insets m) { super.setMargin(m); insets = m; } @Override public void mouseExited(MouseEvent e) { setBorderPainted(false); validate(); repaint(); } @Override public void mouseClicked(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) { setBorderPainted(true); validate(); repaint(); } @Override public void mousePressed(MouseEvent e) { if (isEnabled()) { setContentAreaFilled(true); validate(); repaint(); } } @Override public void mouseReleased(MouseEvent e) { setContentAreaFilled(false); validate(); repaint(); } @Override public void focusGained(FocusEvent e) { setBorderPainted(true); validate(); repaint(); } @Override public void focusLost(FocusEvent e) { setBorderPainted(false); validate(); repaint(); } } gprofng-gui-1.0/org/gprofng/mpmt/settings/0000755000175000017500000000000014517775727015673 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/settings/PathMapSetting.java0000644000175000017500000001222414517772113021331 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; public class PathMapSetting extends Setting { private String[][] pathMap = null; public PathMapSetting() { pathMap = new String[2][]; // Default pathMap[0] = new String[0]; pathMap[1] = new String[0]; } public void set(Object originalSource, String[][] newPathMap) { boolean changed = false; if (pathMap == null) { changed = true; } else { assert pathMap.length == 2 && newPathMap.length == 2; String[] oldTo = pathMap[0]; String[] oldFrom = pathMap[1]; String[] newTo = newPathMap[0]; String[] newFrom = newPathMap[1]; assert oldTo.length == oldFrom.length; assert newTo.length == newFrom.length; if (oldTo.length != newTo.length) { changed = true; } else { for (int i = 0; i < oldTo.length; i++) { if (!oldTo[i].equals(newTo[i])) { changed = true; break; } } for (int i = 0; i < oldFrom.length; i++) { if (!oldFrom[i].equals(newFrom[i])) { changed = true; break; } } } } if (changed) { setValueAndFireChangeEvent(originalSource, this, newPathMap); } } public void addPathMap(Object originalSource, String from, String to) { String[][] newPathMap = new String[pathMap.length][]; String fromPaths[] = new String[pathMap[0].length + 1]; String toPaths[] = new String[pathMap[1].length + 1]; for (int i = 0; i < pathMap[0].length; i++) { fromPaths[i] = pathMap[0][i]; toPaths[i] = pathMap[1][i]; } fromPaths[pathMap[0].length] = from; toPaths[pathMap[0].length] = to; newPathMap[0] = fromPaths; newPathMap[1] = toPaths; set(originalSource, newPathMap); } public void init(Object originalSource, String[][] pathMap) { setValue(pathMap); fireChangeEvent(originalSource, pathMap); } public static String[][] getDefaultPathmap() { String[][] pathMap = new String[2][]; // Default pathMap[0] = new String[0]; pathMap[1] = new String[0]; return pathMap; } public static boolean isDefault(String[][] pathmap) { String[][] def = getDefaultPathmap(); boolean ret = true; if (def.length != pathmap.length) { ret = false; } else { String[] deffrom = def[0]; String[] defto = def[1]; String[] pathmapfrom = pathmap[0]; String[] pathmapto = pathmap[1]; if (deffrom.length != pathmapfrom.length) { ret = false; } else if (defto.length != pathmapto.length) { ret = false; } else { for (int i = 0; i < deffrom.length; i++) { if (!deffrom[i].equals(pathmapfrom[i])) { ret = false; break; } } for (int i = 0; i < defto.length; i++) { if (!defto[i].equals(pathmapto[i])) { ret = false; break; } } } } return ret; } public String[][] get() { return pathMap; } public String[] getPathMapFrom() { return pathMap[0]; } public String[] getPathMapTo() { return pathMap[1]; } @Override Type getType() { return AnSettingChangeEvent.Type.PATH_MAP; } @Override Object getValue() { return pathMap; } @Override void setValue(Object newValue) { Object[] newPathMap = (Object[]) newValue; pathMap = (String[][]) newPathMap; setPathMapIPC(pathMap); // IPC } public static String[][] getPathMapsIPC() { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getPathmaps"); Object[] ret = (Object[]) anWindow.IPC().recvObject(); String[][] retS = new String[2][]; retS[0] = (String[]) ret[0]; retS[1] = (String[]) ret[1]; return retS; } } private static String addPathMapIPC(String from, final String to) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("addPathmap"); anWindow.IPC().send(from); anWindow.IPC().send(to); return anWindow.IPC().recvString(); } } private static void setPathMapIPC(String[][] pathMap) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("setPathmaps"); anWindow.IPC().send(pathMap[0]); anWindow.IPC().send(pathMap[1]); anWindow.IPC().recvString(); // synchronize } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricType.java0000644000175000017500000000174614517772113020535 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; public class MetricType { private String command; private int subType; public MetricType(String command, int subType) { this.command = command; this.subType = subType; } public String getCommand() { return command; } public int getSubType() { return subType; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/CompareModeSetting.java0000644000175000017500000000734514517772113022202 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; public class CompareModeSetting extends Setting { private CompareMode compareMode = CompareMode.CMP_DISABLE; // Default public enum CompareMode { CMP_DISABLE(0, AnLocale.getString("Disable")), CMP_ENABLE(1, AnLocale.getString("Enable")), CMP_RATIO(2, AnLocale.getString("Ratio")), CMP_DELTA(4, AnLocale.getString("Delta")); private final int value; private final String name; private CompareMode(int value, String name) { this.value = value; this.name = name; } public int value() { return value; } public static CompareMode fromValue(int val) { for (CompareMode rt : CompareMode.values()) { if (rt.value() == val) { return rt; } } return null; } @Override public String toString() { return name; } }; public CompareModeSetting() {} public static CompareMode getDefaultCompareMode() { return CompareMode.CMP_DISABLE; } public void init(Object originalSource, CompareMode mode) { if (mode != compareMode) { this.compareMode = mode; fireChangeEvent(originalSource, mode); } } public void set(Object originalSource, CompareMode mode) { if (mode != compareMode) { setValueAndFireChangeEvent(originalSource, this, mode); } } public CompareMode get() { return compareMode; } public boolean comparingExperiments() { return compareMode != CompareMode.CMP_DISABLE; } @Override Type getType() { return AnSettingChangeEvent.Type.COMPARE_MODE; } @Override Object getValue() { return compareMode; } @Override void setValue(Object newValue) { CompareMode newMode = (CompareMode) newValue; this.compareMode = newMode; setCompareModeV2IPC(newMode); // IPC } private static void setCompareModeV2IPC(final CompareMode mode) { synchronized (IPC.lock) { final IPC ipc = AnWindow.getInstance().IPC(); ipc.send("setCompareModeV2"); ipc.send(0); ipc.send(mode.value()); ipc.recvVoid(); } } public static CompareMode getCompareModeV2IPC() { synchronized (IPC.lock) { final IPC ipc = AnWindow.getInstance().IPC(); ipc.send("getCompareModeV2"); ipc.send(0); int mode = ipc.recvInt(); CompareMode compareMode = CompareMode.fromValue(mode); return compareMode; } } /** * Send request to get Compare Mode. Non-blocking IPC call. Caller should call ipcResult.getInt() * to get the result * * @return IPCResult */ public static IPCResult getCompareModeV2IPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getCompareModeV2"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // CompareMode result = ipcResult.getInt() // blocking return ipcResult; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/SourceDisassemblySetting.java0000644000175000017500000001061714517772113023443 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; public class SourceDisassemblySetting extends Setting { private static final int settingsSource = 0x7ff; // 2147483647; private static final int settingsDisassembly = 0x7ff; // 2147483647; private static final int thresholdSource = 75; private static final int thresholdDisassembly = 75; private static final int sourceCode = 1; private static final int metricsForSourceLines = 0; private static final int hexadecimalInstructions = 0; private static final int onlyShowDataOfCurrentFunction = 0; private static final int showCompilerCommandLlineFlags = 0; private static final int showFunctionBeginningLine = 1; private static final int[] defaultSettings = new int[] { settingsSource, settingsDisassembly, thresholdSource, thresholdDisassembly, sourceCode, metricsForSourceLines, hexadecimalInstructions, showCompilerCommandLlineFlags, onlyShowDataOfCurrentFunction, showFunctionBeginningLine }; private int[] settings = defaultSettings; public SourceDisassemblySetting() {} public static int[] getDefaultSourceDisassemblySetting() { return defaultSettings; } public void init(Object originalSource, int[] newSettings) { newSettings[0] = 0x7ff & newSettings[0]; newSettings[1] = 0x7ff & newSettings[1]; boolean changed = changed(settings, newSettings); if (changed) { this.settings = newSettings; fireChangeEvent(originalSource, newSettings); } } public void set(Object originalSource, int[] newSettings) { newSettings[0] = 0x7ff & newSettings[0]; newSettings[1] = 0x7ff & newSettings[1]; boolean changed = changed(settings, newSettings); if (changed) { setValueAndFireChangeEvent(originalSource, this, newSettings); } } public static boolean changed(int[] oldSettings, int[] newSettings) { boolean changed = false; // check if any changes if (oldSettings.length != newSettings.length) { changed = true; } else { for (int i = 0; i < oldSettings.length; i++) { if (oldSettings[i] != newSettings[i]) { changed = true; break; } } } return changed; } public int[] get() { return settings; } @Override Type getType() { return AnSettingChangeEvent.Type.SRC_DIS; } @Override Object getValue() { return settings; } @Override void setValue(Object newValue) { int[] newSetting = (int[]) newValue; this.settings = newSetting; setAnoValueIPC(newSetting); // IPC } public static int[] getAnoValueIPC() { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("getAnoValue"); window.IPC().send(0); return (int[]) window.IPC().recvObject(); } } /** * Send request to get AnoValue. Non-blocking IPC call. Caller should call ipcResult.getInts() to * get the result * * @return IPCResult */ public static IPCResult getAnoValueIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getAnoValue"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // int[] result = ipcResult.getInts() // blocking return ipcResult; } private static void setAnoValueIPC(final int[] set) { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("setAnoValue"); window.IPC().send(0); window.IPC().send(set); window.IPC().recvString(); // synchronize } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricNameSelected.java0000644000175000017500000000176414517772113022145 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; public class MetricNameSelected { private String name; private boolean selected; public MetricNameSelected(String name, boolean selected) { this.name = name; this.selected = selected; } public String getName() { return name; } public boolean isSelected() { return selected; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/CallTreePanel.java0000644000175000017500000001030314517772113021110 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JSpinner; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * @author tpreisle */ public class CallTreePanel extends JPanel { private final ChangeListener spinnerChangeListener; public CallTreePanel() { initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); AnUtility.setTextAndAccessibleContext( label, AnLocale.getString("Expand branches when percent of metric exceeds this threshold (%):")); JComponent editor = ((JSpinner.DefaultEditor) spinner.getEditor()); Dimension size = editor.getPreferredSize(); editor.setPreferredSize(new Dimension(20, size.height)); label.setLabelFor(spinner); label.setDisplayedMnemonic(AnLocale.getString('E', "MN_SETTINGS_CALLTREE_THRESHOLD")); AnUtility.setTTAndAccessibleContext(spinner, AnLocale.getString("Threshold")); spinner.setValue(UserPref.getInstance().getCallStackThreshold()); spinner.addChangeListener( spinnerChangeListener = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { Integer val = (Integer) spinner.getValue(); if (val < 0) { spinner.setValue(0); } else if (val > 100) { spinner.setValue(100); } AnWindow.getInstance().getSettings().stateChanged(null); } }); } public void updateGUI() { int threshold = AnWindow.getInstance().getSettings().getCallTreeSetting().getThreshold(); spinner.removeChangeListener(spinnerChangeListener); spinner.setValue(threshold); spinner.addChangeListener(spinnerChangeListener); } public void checkChanges(Object originalSource) { Integer val = (Integer) spinner.getValue(); AnWindow.getInstance() .getSettings() .getCallTreeSetting() .setThreshold(originalSource, val.intValue()); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; label = new javax.swing.JLabel(); spinner = new javax.swing.JSpinner(); setLayout(new java.awt.GridBagLayout()); label.setText(""); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.PAGE_START; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(label, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.PAGE_START; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); add(spinner, gridBagConstraints); } // //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel label; private javax.swing.JSpinner spinner; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricsPanel.form0000644000175000017500000004455514517772113021065 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/settings/Settings.java0000644000175000017500000033563114517772113020253 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnDialog; import org.gprofng.mpmt.AnFile; import org.gprofng.mpmt.AnList; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.navigation.View; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.settings.CompareModeSetting.CompareMode; import org.gprofng.mpmt.settings.ViewModeSetting.ViewMode; import org.gprofng.mpmt.util.gui.AnJPanel; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnTabbedPane; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.gui.AnUtility.AnRadioButton; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSlider; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.SwingConstants; import javax.swing.border.EtchedBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; public final class Settings implements ActionListener, ItemListener, DocumentListener, ChangeListener { private Settings instance = null; private final Frame frame; private AnWindow anWindow; private SettingsDialog settingsDialog; private JTabbedPane tabbedPane; public int settingsviewsIndex = -1; public int settingsMetricsIndex = -1; public int settingsTimelineIndex = -1; public int settingsSourceDisassemblyIndex = -1; public int settingsCalltreeIndex = -1; // States private final ViewModeSetting viewModeSetting = new ViewModeSetting(); private final ViewModeEnabledSetting viewModeEnabledSetting = new ViewModeEnabledSetting(); private final FormatSetting formatSetting = new FormatSetting(); private final TableSettings tableSettings = new TableSettings(); private final CompareModeSetting compareModeSetting = new CompareModeSetting(); private final TimelineSetting timelineSetting = new TimelineSetting(); private final SourceDisassemblySetting sourceDisassemblySetting = new SourceDisassemblySetting(); private final MetricsSetting metricSetting = new MetricsSetting(); private final SearchPathSetting searchPathSetting = new SearchPathSetting(); private final PathMapSetting pathMapSetting = new PathMapSetting(); private final CallTreeSetting callTreeSetting = new CallTreeSetting(); private final ViewsSetting viewsSetting = new ViewsSetting(); private final LibraryVisibilitySetting libraryVisibilitySetting = new LibraryVisibilitySetting(); // Metrics Tab private MetricsPanel metricsPanel; // Source/Disassembly Tab private int vis_src; private int vis_dis; private static final int[] ccmv_type; private static final String[] ccmv_desc; private static final String[] ccmv_comd; private static final char[] ccmv_mnem; private int threshold_src; private int threshold_dis; private boolean src_visible; private boolean src_metric; private boolean hex_visible; private boolean cmp_visible; private boolean func_visible; private boolean scope_only; private JComponent[] src_chks; private JComponent[] dis_chks; private JComponent[] threshold; private JCheckBox dis_src; private JCheckBox dis_asrc; private JCheckBox dis_hex; private JCheckBox cmp_line; private JCheckBox func_line; private JCheckBox dis_scope; // Formats Tab private AnList tab_name_format; // Formats Tab: Function Name Style private JRadioButton short_fmt; private JRadioButton mangled_fmt; private JRadioButton long_fmt; private JCheckBox soname_chk; // Formats Tab: View Mode private JComponent viewModeLabel; private JRadioButton view_fmt; private JRadioButton view_expert_fmt; private JRadioButton view_machine_fmt; // Formats Tab: Compare private JLabel cmpModeLabel; private JRadioButton cmp_abs_value; private JRadioButton cmp_delta; private JRadioButton cmp_ratio; // Wrap long metric names in table headers private JCheckBox wrapNameCheckBox; // Timeline Tab public static final int PROP_NONE = 0; private ArrayList tldata_checkBoxes; // checkboxes private ArrayList tldata_check_unames; // names shown for checkboxes private int previous_tldata_names_version; private boolean tldata_show_states; // show per-DATA_* event states (mstates) private boolean tldata_show_counts; // show per-DATA_* event values private JCheckBox tldata_show_states_cb; // checkboxes private JCheckBox tldata_show_counts_cb; // checkboxes // TL options' components private JPanel tl_type_panel; private ArrayList tl_entity_button; // Entities == LWP, Thread, CPU, Experiments private JRadioButton[] tl_stack_align; private JSlider tl_slider; private int tldata_stack_depth; private boolean needsTimelineEvent = false; // Search Path private SearchPathPanel searchPathPanel; // Path Map private PathmapsPanel pathmapsPanel; // Views Tab private JPanel viewsPanel; private JPanel memchk_panel, indxchk_panel; private AnList memlist, indxlist; private CustomMemDialog tabs_custom_mem_dlg; private CustomIndxDialog tabs_custom_indx_dlg; private AnUtility.AnCheckBox[] staticViewCheckBoxes; private AnUtility.AnCheckBox[] standardObjectCheckBoxes; private AnUtility.AnCheckBox[] memoryObjectCheckBoxes; private AnUtility.AnCheckBox[] indexObjectCheckBoxes; // Call Tree private CallTreePanel callTreePanel; // Constructor public Settings(final AnWindow window, final Frame frame) { // name_col = -1; // tldata tldata_checkBoxes = new ArrayList(); tldata_check_unames = new ArrayList(); previous_tldata_names_version = 0; tldata_show_states = false; tldata_show_counts = false; tldata_stack_depth = 0; anWindow = window; this.frame = frame; instance = this; initComponents(); updateGUIViewModeVisible(); settingsDialog = new SettingsDialog(); // FIXUP: Settings dialog keeps some states!!!!!!! } private Settings getDefault() { return instance; } public SourceDisassemblySetting getSourceDisassemblySetting() { return sourceDisassemblySetting; } public ViewModeSetting getViewModeSetting() { return viewModeSetting; } public ViewModeEnabledSetting getViewModeEnabledSetting() { return viewModeEnabledSetting; } public FormatSetting getFormatSetting() { return formatSetting; } public CompareModeSetting getCompareModeSetting() { return compareModeSetting; } public MetricsSetting getMetricsSetting() { return metricSetting; } public TimelineSetting getTimelineSetting() { return timelineSetting; } public SearchPathSetting getSearchPathSetting() { return searchPathSetting; } public PathMapSetting getPathMapSetting() { return pathMapSetting; } public CallTreeSetting getCallTreeSetting() { return callTreeSetting; } public ViewsSetting getViewsSetting() { return viewsSetting; } public TableSettings getTableSettings() { return tableSettings; } public LibraryVisibilitySetting getLibraryVisibilitySetting() { return libraryVisibilitySetting; } // Initialize GUI components private void initComponents() { JPanel panel; Dimension psize; int tabCount = 0; tabbedPane = new AnTabbedPane(); String txt = AnLocale.getString("Presentation Tabs"); AnUtility.setAccessibleContext(tabbedPane.getAccessibleContext(), txt); // Views viewsPanel = new AnJPanel(new GridBagLayout()); txt = AnLocale.getString("Views"); tabbedPane.addTab(txt, new AnJScrollPane(viewsPanel)); tabCount++; txt = AnLocale.getString("Select Tabs"); AnUtility.setAccessibleContext(viewsPanel.getAccessibleContext(), txt); settingsviewsIndex = tabCount - 1; // Metrics txt = AnLocale.getString("Metrics"); metricsPanel = new MetricsPanel(); tabbedPane.addTab(txt, metricsPanel); tabCount++; settingsMetricsIndex = tabCount - 1; // Timeline panel = new AnJPanel(new FlowLayout(FlowLayout.RIGHT, 0, 0)); edt_initTimeline(panel); // IPC! txt = AnLocale.getString("Timeline"); panel.setName(txt); panel.getAccessibleContext().setAccessibleName(txt); tabbedPane.addTab(txt, new AnJScrollPane(panel)); tabCount++; settingsTimelineIndex = tabCount - 1; // Source and Disassembly panel = new AnJPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); initSourceDisassembly(panel); tabbedPane.addTab(AnLocale.getString("Source/Disassembly"), new AnJScrollPane(panel)); tabCount++; settingsSourceDisassemblyIndex = tabCount - 1; // Call Tree callTreePanel = new CallTreePanel(); txt = AnLocale.getString("Call Tree"); tabbedPane.addTab(txt, new AnJScrollPane(callTreePanel)); tabCount++; txt = AnLocale.getString("Call Tree"); AnUtility.setAccessibleContext(callTreePanel.getAccessibleContext(), txt); settingsCalltreeIndex = tabCount - 1; // Formats tab_name_format = new AnList(false); initNameFormat(tab_name_format); AnUtility.setAccessibleContext(tab_name_format.getAccessibleContext(), FORMATS_STR); tabbedPane.addTab(FORMATS_STR, new AnJScrollPane(tab_name_format)); tabCount++; // Search Path searchPathPanel = new SearchPathPanel(this); txt = AnLocale.getString("Search Path"); tabbedPane.addTab(txt, searchPathPanel); tabCount++; // Path Mapping pathmapsPanel = new PathmapsPanel(this); txt = AnLocale.getString("Pathmaps"); tabbedPane.addTab(txt, pathmapsPanel); tabCount++; psize = tabbedPane.getPreferredSize(); if (psize.width < MIN_WIDTH) { psize.width = MIN_WIDTH; } tabbedPane.setPreferredSize(psize); } /** * Opens "Settings" dialog with the tab on top specified by parameter Available values: * presentation.timeline_index * * @param tabIndex */ public void showDialog(int tabIndex) { if (tabIndex >= 0) { if (tabIndex < tabbedPane.getComponentCount()) { tabbedPane.setSelectedIndex(tabIndex); } } showDialog(true); } public void showDialog(boolean show) { if (settingsDialog == null) { settingsDialog = new SettingsDialog(); } // Refresh the panel to get changes made in other views if (show) { settingsDialog.showDialog(true); } else { settingsDialog.showDialog(false); } } // Initialize components for the Source and Disassembly pane private void initSourceDisassembly(final JPanel annotate) { final JPanel panel; JPanel chk_panel, text_panel; final AnList list; JLabel label; int i; final String[] threshold_str; int[] defaultSettings = getSourceDisassemblySetting().getDefaultSourceDisassemblySetting(); vis_src = defaultSettings[0]; vis_dis = defaultSettings[1]; threshold_src = defaultSettings[2]; threshold_dis = defaultSettings[3]; src_visible = defaultSettings[4] == 0 ? false : true; src_metric = defaultSettings[5] == 0 ? false : true; hex_visible = defaultSettings[6] == 0 ? false : true; cmp_visible = defaultSettings[7] == 0 ? false : true; scope_only = defaultSettings[8] == 0 ? false : true; func_visible = defaultSettings[9] == 0 ? false : true; panel = new AnJPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); // Compiler Commentary list = new AnList(false); chk_panel = new AnJPanel(new GridLayout(1, 2)); chk_panel.add(AnUtility.getHeader(AnLocale.getString("Source"))); chk_panel.add(AnUtility.getHeader(AnLocale.getString("Disassembly"))); String txt = AnLocale.getString("Compiler Commentary"); list.add(AnUtility.getItem(txt), chk_panel); txt = AnLocale.getString("Compiler Commentary"); AnUtility.setAccessibleContext(list.getAccessibleContext(), txt); // Space for adding selecting choice src_chks = new JComponent[size_ccmv]; dis_chks = new JComponent[size_ccmv]; threshold = new JComponent[2]; for (i = 0; i < size_ccmv; i++) { chk_panel = new AnJPanel(new GridLayout(1, 2)); chk_panel.add(src_chks[i] = new AnUtility.AnCheckBox(" ", (vis_src & ccmv_type[i]) != 0)); ((AnUtility.AnCheckBox) src_chks[i]).addItemListener(this); chk_panel.add(dis_chks[i] = new AnUtility.AnCheckBox(" ", (vis_dis & ccmv_type[i]) != 0)); ((AnUtility.AnCheckBox) dis_chks[i]).addItemListener(this); label = (JLabel) AnUtility.getItem(ccmv_desc[i]); label.setDisplayedMnemonic(ccmv_mnem[i]); label.setLabelFor(src_chks[i]); AnUtility.setAccessibleContext(label.getAccessibleContext(), ccmv_desc[i]); list.add(label, chk_panel); } // Syncing states with GUI vis_src = 0; vis_dis = 0; for (int ii = 0; ii < size_ccmv; ii++) { if (((JCheckBox) src_chks[ii]).isSelected()) { vis_src |= ccmv_type[ii]; } if (((JCheckBox) dis_chks[ii]).isSelected()) { vis_dis |= ccmv_type[ii]; } } // Highlighting Threshold chk_panel = new AnJPanel(new GridLayout(1, 2)); threshold_str = new String[2]; threshold_str[0] = Integer.toString(threshold_src); threshold_str[1] = Integer.toString(threshold_dis); for (i = 0; i < 2; i++) { threshold[i] = AnUtility.getNumber(threshold_str[i], 3); ((JTextField) threshold[i]).setEditable(true); ((JTextField) threshold[i]).getDocument().addDocumentListener(this); chk_panel.add(text_panel = new AnJPanel()); text_panel.add(threshold[i]); } txt = AnLocale.getString("Hot Lines highlighting Threshold (%):"); label = (JLabel) AnUtility.getItem(txt); // label.setDisplayedMnemonic(AnLocale.getString('T', // "MNEM_PRESENT_HIGHLIGHTING_THRESHOLD")); label.setLabelFor(threshold[0]); AnUtility.setAccessibleContext(label.getAccessibleContext(), txt); list.add(label, chk_panel); list.setAlignmentX(); list.setAlignmentY(); panel.add(list); // Disassembly Listing AnList list2 = new AnList(false); list2.add(AnUtility.getItem(AnLocale.getString("Show in Disassembly Listing:")), null); list2.setAlignmentX(); list2.setAlignmentY(); panel.add(list2); dis_src = new AnUtility.AnCheckBox(AnLocale.getString("Source Code"), src_visible); // dis_src.setMnemonic(AnLocale.getString('r', "MNEM_PRESENT_SOURCE_CODE")); dis_src.addItemListener(this); dis_asrc = new AnUtility.AnCheckBox(AnLocale.getString("Metrics for Source Lines"), src_metric); // dis_asrc.setMnemonic(AnLocale.getString('e', // "MNEM_PRESENT_METRICS_FOR_SOURCE_LINES")); dis_asrc.addItemListener(this); dis_hex = new AnUtility.AnCheckBox(AnLocale.getString("Hexadecimal Instructions"), hex_visible); // dis_hex.setMnemonic(AnLocale.getString('x', "MNEM_PRESENT_HEXADECIMAL_INSTRUCTIONS")); dis_hex.addItemListener(this); dis_scope = new AnUtility.AnCheckBox( AnLocale.getString("Only Show Data of Current Function"), scope_only); // dis_scope.setMnemonic(AnLocale.getString('u', // "MNEM_PRESENT_ONLY_SHOW_DATA_OF_CURRENT_FUNCTION")); dis_scope.addItemListener(this); chk_panel = new AnJPanel(); chk_panel.setLayout(new BoxLayout(chk_panel, BoxLayout.Y_AXIS)); chk_panel.add(dis_src); chk_panel.add(dis_asrc); chk_panel.add(dis_hex); chk_panel.add(dis_scope); panel.add(chk_panel); // Disassembly Listing AnJPanel chk_panel2 = new AnJPanel(new FlowLayout(FlowLayout.LEFT, 0, 5)); panel.add(chk_panel2); // just a separator AnList list3 = new AnList(false); list3.add( AnUtility.getItem(AnLocale.getString("Show in Source and Disassembly Listing:")), null); list3.setAlignmentX(); list3.setAlignmentY(); panel.add(list3); cmp_line = new AnUtility.AnCheckBox( AnLocale.getString("Show compiler command-line flags"), cmp_visible); // cmp_line.setMnemonic(AnLocale.getString('s', "MNEM_PRESENT_SHOW_COMMAND_LINE_FLAGS")); cmp_line.addItemListener(this); func_line = new AnUtility.AnCheckBox(AnLocale.getString("Show function beginning line"), func_visible); // func_line.setMnemonic(AnLocale.getString('f', // "MNEM_PRESENT_SHOW_FUNCTION_SEPARATOR_LINE")); func_line.addItemListener(this); AnJPanel chk_panel3 = new AnJPanel(); chk_panel3.setLayout(new BoxLayout(chk_panel3, BoxLayout.Y_AXIS)); chk_panel3.add(cmp_line); chk_panel3.add(func_line); panel.add(chk_panel3); annotate.add(panel); } /** Sets display mode without enabling OK/Apply Called (indirectly) from outside Presentation */ private void updateGUIViewMode() { view_fmt.removeItemListener(this); view_expert_fmt.removeItemListener(this); view_machine_fmt.removeItemListener(this); ViewMode mode = getViewModeSetting().get(); view_fmt.setSelected(mode == ViewModeSetting.ViewMode.USER); view_expert_fmt.setSelected(mode == ViewModeSetting.ViewMode.EXPERT); view_machine_fmt.setSelected(mode == ViewModeSetting.ViewMode.MACHINE); view_fmt.addItemListener(this); view_expert_fmt.addItemListener(this); view_machine_fmt.addItemListener(this); } private void updateGUIViewModeVisible() { boolean set = getViewModeEnabledSetting().isViewModeEnabled(); viewModeLabel.setEnabled(set); view_fmt.setEnabled(set); view_expert_fmt.setEnabled(set); view_machine_fmt.setEnabled(set); } /** * Updates Name Format mode without enabling OK/Apply Called from within Presentations (clicking * on radio buttons) */ private void updateGUINameFormat() { short_fmt.removeItemListener(this); long_fmt.removeItemListener(this); mangled_fmt.removeItemListener(this); FormatSetting.Style style = getFormatSetting().getStyle(); boolean soName = getFormatSetting().getAppendSoName(); short_fmt.setSelected(style == FormatSetting.Style.SHORT); long_fmt.setSelected(style == FormatSetting.Style.LONG); mangled_fmt.setSelected(style == FormatSetting.Style.MANGLED); soname_chk.setSelected(soName); short_fmt.addItemListener(this); long_fmt.addItemListener(this); mangled_fmt.addItemListener(this); } /** * Sets display compare mode without enabling OK/Apply Called (indirectly) from outside * Presentation */ private void updateGUIDisplayCompareMode() { cmp_abs_value.removeItemListener(this); cmp_delta.removeItemListener(this); cmp_ratio.removeItemListener(this); CompareMode mode = getCompareModeSetting().get(); boolean enbl = (mode != CompareMode.CMP_DISABLE); cmpModeLabel.setEnabled(enbl); cmp_abs_value.setEnabled(enbl); cmp_delta.setEnabled(enbl); cmp_ratio.setEnabled(enbl); cmp_abs_value.setSelected(!enbl || (mode == CompareMode.CMP_ENABLE)); cmp_delta.setSelected(mode == CompareMode.CMP_DELTA); cmp_ratio.setSelected(mode == CompareMode.CMP_RATIO); cmp_abs_value.addItemListener(this); cmp_delta.addItemListener(this); cmp_ratio.addItemListener(this); } /** * Updates Name Format mode without enabling OK/Apply Called from within Presentations (clicking * on radio buttons) */ private void updateGUITableFormat() { wrapNameCheckBox.setSelected(getTableSettings().wrapMetricNames()); } /** * Sets SourceDisassembly settings without enabling OK/Apply Called (indirectly) from outside * Presentation */ private void updateGUISourceDisassembly() { final int[] anno_set = getSourceDisassemblySetting().get(); vis_src = anno_set[0]; vis_dis = anno_set[1]; threshold_src = anno_set[2]; threshold_dis = anno_set[3]; src_visible = (anno_set[4] == 0) ? false : true; src_metric = (anno_set[5] == 0) ? false : true; hex_visible = (anno_set[6] == 0) ? false : true; cmp_visible = (anno_set[7] == 0) ? false : true; scope_only = (anno_set[8] == 0) ? false : true; func_visible = (anno_set[9] == 0) ? false : true; for (int i = 0; i < size_ccmv; i++) { ((JCheckBox) src_chks[i]).setSelected((vis_src & ccmv_type[i]) != 0); ((JCheckBox) dis_chks[i]).setSelected((vis_dis & ccmv_type[i]) != 0); } ((JTextField) threshold[0]).setText("" + threshold_src); ((JTextField) threshold[1]).setText("" + threshold_dis); dis_src.setSelected(src_visible); dis_asrc.setSelected(src_metric); dis_hex.setSelected(hex_visible); cmp_line.setSelected(cmp_visible); dis_scope.setSelected(scope_only); func_line.setSelected(func_visible); } /** * Sets Timeline settings without enabling OK/Apply Called (indirectly) from outside Presentation */ private void updateGUITimeline() { boolean buttonsEnabled = settingsDialog.areButtonsEnabled(); tl_entity_button.get(getTimelineSetting().getTl_entity_selected_btn()).setSelected(true); tl_slider.setValue( getTimelineSetting().getTLStackFramePixels() - TIMELINE_STACK_FRAME_MAGNIFY_OFFSET); // tl_slider.setValue(getTimelineSetting().getTLStackDepth()); tldata_stack_depth = getTimelineSetting().getTLStackDepth(); tl_stack_align[0].setSelected( getTimelineSetting().getStack_align() == TLStack_align.TLSTACK_ALIGN_ROOT); tl_stack_align[1].setSelected( getTimelineSetting().getStack_align() == TLStack_align.TLSTACK_ALIGN_LEAF); tldata_show_states_cb.setSelected(getTimelineSetting().getShowEventStates()); tldata_show_states = tldata_show_states_cb.isSelected(); tldata_show_counts_cb.setSelected(getTimelineSetting().getShowEventDensity()); tldata_show_counts = tldata_show_counts_cb.isSelected(); settingsDialog.setButtonsEnabled(buttonsEnabled); } public static String getErRcTLDataCmdName(TLData_type tldata_type, String auxName) { if (tldata_type == TLData_type.TL_UNKNOWN) { return null; } String cmd = tldata_type.getTLDataBaseCmd(); if (auxName == null) { return cmd; } String tlDataCmd = cmd + "(" + auxName + ")"; return tlDataCmd; } public static String getErRcTLDataLongUName(String dataUName, String auxUName) { if (auxUName == null) { return dataUName; } String baseUName = "HW Counter"; // uname is _too_ long String longUName = baseUName + " (" + auxUName + ")"; return longUName; } private void updateGUITimelineData() { // translate metric selections to timeline DATA checkbox mask MetricsSetting metricsSetting = getMetricsSetting(); AnMetric[] anMetrics = metricsSetting.getAvailableAnMetrics(); Set allList = new HashSet(); Set enabledList = new HashSet(); for (int ii = 0; ii < anMetrics.length; ii++) { String dataType = anMetrics[ii].getDataTypeName(); if (dataType == null) { continue; // for example, derived metrics } String tlDataCmd = getErRcTLDataCmdName(TLData_type.find(dataType), anMetrics[ii].aux); if (tlDataCmd == null) { continue; // weird } allList.add(tlDataCmd); // boolean selected = metricsSetting.isSelected(ii); boolean selected = metricsSetting.isSelected(anMetrics[ii].getComd()); // if (selected != selected2) { // System.out.println("ERROR******************** updateGUITimelineData"); // } if (selected) { enabledList.add(tlDataCmd); } } Set disabledList = new HashSet(allList); for (String enabled : enabledList) { disabledList.remove(enabled); } edt_TLData_disable_only(allList, disabledList); } private boolean edt_TLData_disable_only(Set allData, Set disabledData) { long tldata_check_hidden_bitmask = timelineSetting.getTLDataHiddenMask(); long new_mask = timelineSetting.setTLDataVisibility_edt(allData, disabledData); boolean changed = new_mask != tldata_check_hidden_bitmask; if (changed) { for (int i = 0; i < tldata_checkBoxes.size(); i++) { long hidden = ((1L << i) & new_mask); tldata_checkBoxes.get(i).setSelected(hidden == 0); } tl_type_panel.repaint(); needsTimelineEvent = true; // FIXUP, is this correct? checkTimelineChanged(this); } return changed; } private void updateGUISearchPath() { searchPathPanel.updateGUI(); } private void updateGUIPathMap() { // pathMapPanel.updateGUI(); pathmapsPanel.updateGUI(); } private void updateGUICallTree() { callTreePanel.updateGUI(); } private void updateGUIMetrics() { metricsPanel.updateGUIElements(); } private void updateGUIViews(ViewsSetting.Setting oldSetting, ViewsSetting.Setting newSetting) { AnUtility.checkIfOnAWTThread(true); if (ViewsSetting.viewsChanged(oldSetting, newSetting)) { setViewComponents(); } } private JPanel get_space_panel() { // Create blank space for better grouping JPanel pnl = new JPanel(); pnl.setOpaque(false); pnl.setSize(20, 40); return pnl; } private JLabel get_JLabel(final String txt) { final JLabel lbl = (JLabel) AnUtility.getItem(txt); AnUtility.setAccessibleContext(lbl.getAccessibleContext(), txt); return lbl; } // Initialize components for the Name Formats pane private void initNameFormat(final AnList format) { // formatSetting.initialize(getNameFormat(), getSoName()); // IPC!!!!! ButtonGroup group = new ButtonGroup(); long_fmt = new AnUtility.AnRadioButton( AnLocale.getString("Long"), formatSetting.getStyle() == FormatSetting.Style.LONG); long_fmt.setMnemonic(AnLocale.getString('L', "MNEM_PRESENT_LONG")); long_fmt.addItemListener(this); group.add(long_fmt); format.add(get_JLabel(AnLocale.getString("Function Name Style:")), long_fmt); short_fmt = new AnUtility.AnRadioButton( AnLocale.getString("Short"), formatSetting.getStyle() == FormatSetting.Style.SHORT); short_fmt.setMnemonic(AnLocale.getString('t', "MNEM_PRESENT_SHORT")); short_fmt.addItemListener(this); group.add(short_fmt); format.add((JComponent) null, short_fmt); mangled_fmt = new AnUtility.AnRadioButton( AnLocale.getString("Mangled"), formatSetting.getStyle() == FormatSetting.Style.MANGLED); mangled_fmt.setMnemonic(AnLocale.getString('M', "MNEM_PRESENT_MANGLED")); mangled_fmt.addItemListener(this); group.add(mangled_fmt); format.add((JComponent) null, mangled_fmt); format.add((JComponent) null, get_space_panel()); soname_chk = new AnUtility.AnCheckBox(Blank); soname_chk.setSelected(formatSetting.getAppendSoName()); soname_chk.addItemListener(this); final JLabel so_label = get_JLabel(AnLocale.getString("Append SO name to Function name:")); char ch_mnem = AnLocale.getString('p', "MNEM_PRESENT_SONAME"); so_label.setDisplayedMnemonic(ch_mnem); so_label.setLabelFor(soname_chk); format.add(so_label, soname_chk); format.add((JComponent) null, get_space_panel()); // Add View mode: User/Expert/Machine // view_mode = JMODE_USER; // Don't ask IPC. Just use User mode for now, it will get set // correcly after loading experiments group = new ButtonGroup(); view_fmt = new AnUtility.AnRadioButton(AnLocale.getString("User", "PRESENT_USER"), true); view_fmt.setMnemonic(AnLocale.getString('U', "MNEM_PRESENT_USER")); view_fmt.addItemListener(this); group.add(view_fmt); viewModeLabel = AnUtility.getItem(AnLocale.getString("View Mode:")); format.add(viewModeLabel, view_fmt); view_expert_fmt = new AnUtility.AnRadioButton(AnLocale.getString("Expert"), false); view_expert_fmt.setMnemonic(AnLocale.getString('x', "MNEM_PRESENT_EXPERT")); view_expert_fmt.addItemListener(this); group.add(view_expert_fmt); format.add((JComponent) null, view_expert_fmt); view_machine_fmt = new AnUtility.AnRadioButton(AnLocale.getString("Machine", "PRESENT_MACHINE"), false); view_machine_fmt.setMnemonic(AnLocale.getString('n', "MNEM_PRESENT_MACHINE")); group.add(view_machine_fmt); format.add((JComponent) null, view_machine_fmt); format.add((JComponent) null, get_space_panel()); // Add compare mode. Don't ask IPC. // Just use CMP_DISABLE for now, it will get set correctly after loading experiments boolean enbl = false; cmpModeLabel = get_JLabel(AnLocale.getString("Comparison Style:")); cmpModeLabel.setEnabled(enbl); group = new ButtonGroup(); cmp_abs_value = new AnUtility.AnRadioButton(AnLocale.getString("Absolute Values"), true); cmp_abs_value.setMnemonic(AnLocale.getString('B', "MNEM_PRESENT_ABS_VALUE")); cmp_abs_value.addItemListener(this); cmp_abs_value.setEnabled(enbl); group.add(cmp_abs_value); format.add(cmpModeLabel, cmp_abs_value); cmp_delta = new AnUtility.AnRadioButton(AnLocale.getString("Deltas"), false); cmp_delta.setMnemonic(AnLocale.getString('D', "MNEM_PRESENT_DELTAS")); cmp_delta.addItemListener(this); cmp_delta.setEnabled(enbl); group.add(cmp_delta); format.add((JComponent) null, cmp_delta); cmp_ratio = new AnUtility.AnRadioButton(AnLocale.getString("Ratios"), false); cmp_ratio.setMnemonic(AnLocale.getString('R', "MNEM_PRESENT_RATIOS")); cmp_ratio.addItemListener(this); cmp_ratio.setEnabled(enbl); group.add(cmp_ratio); format.add((JComponent) null, cmp_ratio); // Wrap long metric names in table headers format.add((JComponent) null, get_space_panel()); JLabel wrapNameLabel = get_JLabel(AnLocale.getString("Wrap Long Metric Names in Table Headers:")); char mnChar = AnLocale.getString('W', "MNEM_PRESENT_WRAP_NAME"); wrapNameLabel.setDisplayedMnemonic(mnChar); wrapNameCheckBox = new AnUtility.AnCheckBox(Blank); wrapNameLabel.setLabelFor(wrapNameCheckBox); wrapNameCheckBox.addItemListener(this); format.add(wrapNameLabel, wrapNameCheckBox); } // Initialize components for the Timeline pane private void edt_initTimeline(final JPanel timeline_panel) { final JPanel border_panel; final JPanel center_panel; final JPanel east_panel; JLabel label; ButtonGroup buttonGroup; String txt; // --- border_panel (has border) contains main_panel border_panel = new AnJPanel(new BorderLayout()); border_panel.setBorder(AnVariable.boxBorder); timeline_panel.add(border_panel); // --- Center center_panel = new AnJPanel(); center_panel.setLayout(new BoxLayout(center_panel, BoxLayout.Y_AXIS)); // --- Center: Data Types Panels txt = AnLocale.getString("Data Types:"); label = new JLabel(txt); AnUtility.setAccessibleContext(label.getAccessibleContext(), txt); label.setBorder(AnVariable.boxBorder); center_panel.add(label); tl_type_panel = new AnJPanel(); tl_type_panel.setLayout(new BoxLayout(tl_type_panel, BoxLayout.Y_AXIS)); tl_type_panel.setBorder(AnVariable.boxBorder); center_panel.add(tl_type_panel); // --- Center: Additional Graphs Panels txt = AnLocale.getString("For enabled Data Types, also show: "); label = new JLabel(txt); AnUtility.setAccessibleContext(label.getAccessibleContext(), txt); label.setBorder(AnVariable.boxBorder); center_panel.add(label); final JPanel center_additional_graph_panel = new AnJPanel(); center_additional_graph_panel.setLayout( new BoxLayout(center_additional_graph_panel, BoxLayout.Y_AXIS)); center_additional_graph_panel.setBorder(AnVariable.boxBorder); { JCheckBox check; txt = AnLocale.getString("Event States"); check = new AnUtility.AnCheckBox(txt, true); // YXXX add this to .er.rc check.addItemListener(this); center_additional_graph_panel.add(check); tldata_show_states_cb = check; tldata_show_states = tldata_show_states_cb.isSelected(); // Keep states in sync.... txt = AnLocale.getString("Event Density"); check = new AnUtility.AnCheckBox(txt, false); // YXXX add this to .er.rc check.addItemListener(this); center_additional_graph_panel.add(check); tldata_show_counts_cb = check; tldata_show_counts = tldata_show_counts_cb.isSelected(); // Keep states in sync.... } center_panel.add(center_additional_graph_panel); // --- East east_panel = new AnJPanel(); east_panel.setLayout(new BoxLayout(east_panel, BoxLayout.Y_AXIS)); east_panel.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); // --- East, 1st row: tl_entity final JPanel east_entity_panel = new AnJPanel(new BorderLayout(4, 4)); east_entity_panel.setBorder(AnVariable.boxBorder); txt = AnLocale.getString("Group Data by:"); label = new JLabel(txt); AnUtility.setAccessibleContext(label.getAccessibleContext(), txt); east_entity_panel.add(label, BorderLayout.NORTH); final JPanel entity_button_panel = new AnJPanel(new GridLayout(1, 3)); buttonGroup = new ButtonGroup(); tl_entity_button = new ArrayList(); int tl_entity_selected_btn = getTimelineSetting().getTl_entity_selected_btn(); TimelineSetting.EntityProp entProp; for (int i = 0; null != (entProp = getTimelineSetting().getTl_entity_prop(i)); i++) { String uname = entProp.prop_uname; JRadioButton thisButton = new AnRadioButton(uname, i == tl_entity_selected_btn); thisButton.setOpaque(false); thisButton.addItemListener(this); tl_entity_button.add(thisButton); buttonGroup.add(thisButton); entity_button_panel.add(thisButton); } east_entity_panel.add(entity_button_panel, BorderLayout.CENTER); east_panel.add(east_entity_panel); east_panel.add(new JSeparator(SwingConstants.HORIZONTAL)); // --- East, 2nd row: Stack alignment final JPanel east_stack_align_panel = new AnJPanel(new BorderLayout(4, 4)); east_stack_align_panel.setBorder(AnVariable.boxBorder); txt = AnLocale.getString("Stack Alignment:"); label = new JLabel(txt); AnUtility.setAccessibleContext(label.getAccessibleContext(), txt); east_stack_align_panel.add(label, BorderLayout.NORTH); final JPanel alignment_button_panel = new AnJPanel(new GridLayout(1, 2)); buttonGroup = new ButtonGroup(); tl_stack_align = new AnRadioButton[2]; tl_stack_align[0] = new AnRadioButton( TLStack_align.TLSTACK_ALIGN_ROOT.toString(), getTimelineSetting().getStack_align() == TLStack_align.TLSTACK_ALIGN_ROOT); tl_stack_align[0].setMnemonic(AnLocale.getString('R', "MNEM_PRESENT_ROOT")); tl_stack_align[0].addItemListener(this); tl_stack_align[0].setOpaque(false); buttonGroup.add(tl_stack_align[0]); alignment_button_panel.add(tl_stack_align[0]); tl_stack_align[1] = new AnRadioButton( TLStack_align.TLSTACK_ALIGN_LEAF.toString(), getTimelineSetting().getStack_align() == TLStack_align.TLSTACK_ALIGN_LEAF); tl_stack_align[1].setMnemonic(AnLocale.getString('f', "MNEM_PRESENT_LEAF")); tl_stack_align[1].addItemListener(this); tl_stack_align[1].setOpaque(false); buttonGroup.add(tl_stack_align[1]); alignment_button_panel.add(tl_stack_align[1]); east_stack_align_panel.add(alignment_button_panel, BorderLayout.CENTER); east_panel.add(east_stack_align_panel); east_panel.add(new JSeparator(SwingConstants.HORIZONTAL)); // --- East, 3nd row: tl_stack_depth final JPanel east_stack_depth_panel = new AnJPanel(new BorderLayout(4, 4)); east_stack_depth_panel.setBorder(AnVariable.boxBorder); txt = AnLocale.getString("Call Stack Magnification Level"); label = new JLabel( AnLocale.getString("Call Stack Magnification: ") + getTimelineSetting().getTLStackFramePixels()); AnUtility.setAccessibleContext(label.getAccessibleContext(), txt); label.setDisplayedMnemonic(AnLocale.getString('C', "MNEM_CallStackMagnification")); label.setAlignmentX(JDialog.LEFT_ALIGNMENT); east_stack_depth_panel.add(label, BorderLayout.NORTH); tl_slider = new JSlider(); tl_slider.setOpaque(false); // tl_slider.setMinimum(0); // tl_slider.setMaximum(TIMELINE_MAX_STACK_DEPTH); tl_slider.setMinimum(TIMELINE_STACK_FRAME_MAGNIFY_MIN); tl_slider.setMaximum(TIMELINE_STACK_FRAME_MAGNIFY_MAX); // tl_slider.setValue(getTimelineSetting().getTLStackDepth()); tl_slider.setValue(getTimelineSetting().getTLStackFramePixels()); tl_slider.setPaintLabels(true); tl_slider.setPaintTicks(true); tl_slider.setPaintTrack(true); tl_slider.setSnapToTicks(false); tl_slider.setMinorTickSpacing(1); // tl_slider.setMajorTickSpacing(9); tl_slider.addChangeListener(new SliderLabelListener(label)); east_stack_depth_panel.add(tl_slider, BorderLayout.CENTER); label.setLabelFor(tl_slider); east_panel.add(east_stack_depth_panel); // add components to top-level panel border_panel.add(center_panel, BorderLayout.CENTER); border_panel.add(east_panel, BorderLayout.EAST); } /** Called every time experiments are loaded */ private void setViewComponents() { createTabSelectionPanel(); settingsDialog.setButtonsEnabled(false); } // Set components in the Tab selection panel private void createTabSelectionPanel() { // System.out.println("Settings.createTabSelectionPanel"); viewsPanel.removeAll(); // Left Panel AnList viewsList = new AnList(false); buildViewsList(viewsList); GridBagConstraints gridBagConstraints; JPanel standardPanel = new AnJPanel(); standardPanel.setLayout(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; JLabel standardLabel = new JLabel(AnLocale.getString("Standard Views")); standardLabel.getAccessibleContext().setAccessibleDescription(standardLabel.getText()); standardLabel.getAccessibleContext().setAccessibleName(standardLabel.getText()); standardLabel.setBackground(new Color(225, 220, 220)); standardLabel.setOpaque(true); standardLabel.setHorizontalAlignment(JLabel.CENTER); standardLabel.setFont(standardLabel.getFont().deriveFont(Font.BOLD)); standardLabel.setDisplayedMnemonic(AnLocale.getString('S', "SettingsViewsStandardLabelMN")); gridBagConstraints.insets = new Insets(3, 3, 0, 3); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; standardPanel.add(standardLabel, gridBagConstraints); standardPanel.setBorder( BorderFactory.createMatteBorder(1, 1, 1, 1, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); AnList stdlist = new AnList(false); buildStdTabList(stdlist); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.weighty = 1.0; standardPanel.add(stdlist, gridBagConstraints); if (standardObjectCheckBoxes.length > 0) { standardLabel.setLabelFor(standardObjectCheckBoxes[0]); } gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.VERTICAL; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(6, 4, 6, 4); viewsPanel.add(standardPanel, gridBagConstraints); // Center Panel indxlist = new AnList(false); buildIndxTabList(); JPanel indexObjectPanel = new AnJPanel(); indexObjectPanel.setLayout(new GridBagLayout()); JLabel indexObjectLabel = new JLabel(AnLocale.getString("Index Object Views")); indexObjectLabel.getAccessibleContext().setAccessibleDescription(standardLabel.getText()); indexObjectLabel.getAccessibleContext().setAccessibleName(standardLabel.getText()); indexObjectLabel.setBackground(new Color(225, 225, 225)); indexObjectLabel.setOpaque(true); indexObjectLabel.setHorizontalAlignment(JLabel.CENTER); indexObjectLabel.setFont(indexObjectLabel.getFont().deriveFont(Font.BOLD)); indexObjectLabel.setDisplayedMnemonic(AnLocale.getString('w', "SettingsViewsIndexLabelMN")); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(3, 3, 0, 3); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; indexObjectPanel.add(indexObjectLabel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; indexObjectPanel.add(indxlist, gridBagConstraints); indexObjectPanel.setBorder( BorderFactory.createMatteBorder(1, 1, 1, 1, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); if (indexObjectCheckBoxes.length > 0) { indexObjectLabel.setLabelFor(indexObjectCheckBoxes[0]); } // Custom button AnUtility.ResponseAction addCustomIViewButton = new AnUtility.ResponseAction( AnLocale.getString("Add Custom View"), null, AnLocale.getString('u', "MNEM_PRESENT_ADD_CUSTOM_INDXOBJECT"), this); addCustomIViewButton.setToolTipText(AnLocale.getString("Add Index Object Custom View")); // if (GUITesting.getInstance().isRunningUnderGUITesting()) { // addCustomIViewButton.setText("Add Custom Index Objects View"); // } addCustomIViewButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (tabs_custom_indx_dlg == null) { tabs_custom_indx_dlg = new CustomIndxDialog(0, frame); } tabs_custom_indx_dlg.setVisible(true); } }); addCustomIViewButton.setMargin(new Insets(0, 4, 0, 4)); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(4, 4, 4, 4); indexObjectPanel.add(addCustomIViewButton, gridBagConstraints); // Add the panel gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.VERTICAL; gridBagConstraints.insets = new Insets(6, 4, 6, 4); viewsPanel.add(indexObjectPanel, gridBagConstraints); // Right Panel memlist = new AnList(false); buildMemTabList(); JPanel memoryObjectPanel = new AnJPanel(); memoryObjectPanel.setBorder( BorderFactory.createMatteBorder(1, 1, 1, 1, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); memoryObjectPanel.setLayout(new GridBagLayout()); JLabel memoryObjectLabel = new JLabel(AnLocale.getString("Memory Object Views")); memoryObjectLabel.getAccessibleContext().setAccessibleDescription(standardLabel.getText()); memoryObjectLabel.getAccessibleContext().setAccessibleName(standardLabel.getText()); memoryObjectLabel.setBackground(new Color(225, 225, 225)); memoryObjectLabel.setOpaque(true); memoryObjectLabel.setHorizontalAlignment(JLabel.CENTER); memoryObjectLabel.setFont(memoryObjectLabel.getFont().deriveFont(Font.BOLD)); memoryObjectLabel.setDisplayedMnemonic(AnLocale.getString('y', "SettingsViewsMemoryLabelMN")); if (memoryObjectCheckBoxes.length > 0) { memoryObjectLabel.setLabelFor(memoryObjectCheckBoxes[0]); } gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(3, 3, 0, 3); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; memoryObjectPanel.add(memoryObjectLabel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; memoryObjectPanel.add(memlist, gridBagConstraints); // Custom button AnUtility.ResponseAction customMemoryObjectButton = new AnUtility.ResponseAction( AnLocale.getString("Add Custom View"), null, AnLocale.getString('m', "MNEM_PRESENT_ADD_CUSTOM_MEMOBJECT"), this); customMemoryObjectButton.setToolTipText(AnLocale.getString("Add Memory Object Custom View")); // if (GUITesting.getInstance().isRunningUnderGUITesting()) { // customMemoryObjectButton.setText("Add Custom Memory Objects View"); // } customMemoryObjectButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (tabs_custom_mem_dlg == null) { tabs_custom_mem_dlg = new CustomMemDialog(0, frame); } tabs_custom_mem_dlg.setVisible(true); } }); customMemoryObjectButton.setMargin(new Insets(0, 4, 0, 4)); customMemoryObjectButton.setAlignmentX(JButton.RIGHT_ALIGNMENT); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; // gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.insets = new Insets(4, 4, 0, 4); memoryObjectPanel.add(customMemoryObjectButton, gridBagConstraints); JLabel machineModelLabel = new JLabel(); AnUtility.setTextAndAccessibleContext(machineModelLabel, AnLocale.getString("Machine Model:")); machineModelLabel.setDisplayedMnemonic( AnLocale.getString('c', "MN_SETTINGS_VIEWS_Machine_Model")); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.insets = new Insets(4, 4, 0, 4); memoryObjectPanel.add(machineModelLabel, gridBagConstraints); final JComboBox machineModelComboBox = new JComboBox(); machineModelLabel.setLabelFor(machineModelComboBox); AnUtility.setAccessibleContext( machineModelComboBox.getAccessibleContext(), AnLocale.getString("Machine Models")); // add an emptry string machineModelComboBox.addItem(AnLocale.getString("(none)")); // loop over list from DBE String[] choices = getViewsSetting().getAvailableMachineMsodel(); for (int j = 0; j < choices.length; j++) { machineModelComboBox.addItem(choices[j]); } machineModelComboBox.setSelectedIndex(0); if (!((getViewsSetting().getMachineModel() == null) || (getViewsSetting().getMachineModel().equals("")))) { for (int i = 0; i < machineModelComboBox.getItemCount(); i++) { String mn = (String) machineModelComboBox.getItemAt(i); if (mn.equalsIgnoreCase(getViewsSetting().getMachineModel())) { machineModelComboBox.setSelectedIndex(i); break; } } } machineModelComboBox.addPopupMenuListener( new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { String machineModelName = (String) machineModelComboBox.getSelectedItem(); setMachineModel(machineModelComboBox, machineModelName); } @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.weighty = 1.0; memoryObjectPanel.add(machineModelComboBox, gridBagConstraints); // Align button widths int maxWidth = customMemoryObjectButton.getPreferredSize().width; if (machineModelLabel.getPreferredSize().width > maxWidth) { maxWidth = machineModelLabel.getPreferredSize().width; } if (machineModelComboBox.getPreferredSize().width > maxWidth) { maxWidth = machineModelComboBox.getPreferredSize().width; } Dimension dim = new Dimension(maxWidth, customMemoryObjectButton.getPreferredSize().height); customMemoryObjectButton.setPreferredSize(dim); machineModelLabel.setPreferredSize(dim); machineModelComboBox.setPreferredSize(dim); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.VERTICAL; gridBagConstraints.insets = new Insets(6, 4, 6, 4); viewsPanel.add(memoryObjectPanel, gridBagConstraints); // Align section widths maxWidth = standardLabel.getPreferredSize().width; if (indexObjectLabel.getPreferredSize().width > maxWidth) { maxWidth = indexObjectLabel.getPreferredSize().width; } if (memoryObjectLabel.getPreferredSize().width > maxWidth) { maxWidth = memoryObjectLabel.getPreferredSize().width; } dim = new Dimension(maxWidth + 30, standardLabel.getPreferredSize().height); standardLabel.setPreferredSize(dim); indexObjectLabel.setPreferredSize(dim); memoryObjectLabel.setPreferredSize(dim); // Sidepanel viewsPanel.validate(); // FIXUP ? viewsPanel.repaint(); // FIXUP ? } private void setMachineModel(final JComboBox comboBox, String machineModelName) { if ((machineModelName == null) || (machineModelName.equals(AnLocale.getString("(none)")))) { machineModelName = ""; } if (machineModelName.equals(getViewsSetting().getMachineModel())) { return; } final String machineModelName2 = machineModelName; AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { final String errorMessage = ViewsSetting.loadMachineModelIPC(machineModelName2); AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { if (errorMessage == null) { // Successfully loaded machine model, update gui addCustomIndxMemTab(); // anWindow.getViewPanels().removeAllViews(); // if // loading new machine model, the old machine model views should be removed settingsDialog.setButtonsEnabled(true); getViewsSetting().setMachineModel(machineModelName2); } else { AnUtility.showMessage(viewsPanel, errorMessage, JOptionPane.ERROR_MESSAGE); String machineModelName3 = getViewsSetting().getMachineModel(); if ((machineModelName3 == null) || (machineModelName3.equals(""))) { machineModelName3 = AnLocale.getString("(none)"); } for (int i = 0; i < comboBox.getItemCount(); i++) { String mn = (String) comboBox.getItemAt(i); if (mn.equalsIgnoreCase(machineModelName3)) { comboBox.setSelectedIndex(i); break; } } } } }); } }, "machinemodelcomboboxupdate"); } // Build the list of checkboxes for the Views private void buildViewsList(AnList list) { // System.out.println("Settings.buildViewsList"); JPanel chk_panel; String[] tab_names; char[] tab_mnems; // Add column header chk_panel = new AnJPanel(new GridLayout(1, 1)); list.add(AnUtility.getItem(AnLocale.getString("Views")), chk_panel); list.getAccessibleContext() .setAccessibleDescription(AnLocale.getString("List of views to choose from")); list.add((JComponent) null, new AnJPanel()); final JPanel sep_panel = new AnJPanel(new GridLayout(1, 1)); sep_panel.add(new JSeparator()); list.add((JComponent) null, sep_panel); List views_tablist = getViewsSetting().getStaticViews(); tab_names = new String[views_tablist.size()]; tab_mnems = new char[views_tablist.size()]; for (int i = 0; i < views_tablist.size(); i++) { tab_names[i] = views_tablist.get(i).getAnDispTab().getTName(); tab_mnems[i] = views_tablist.get(i).getAnDispTab().getTMnem(); } // Compose the list of checkboxes staticViewCheckBoxes = new AnUtility.AnCheckBox[tab_names.length]; // Compose standard tabs checklist for (int i = 0; i < staticViewCheckBoxes.length; i++) { chk_panel = new AnJPanel(new GridLayout(1, 2)); chk_panel.add(staticViewCheckBoxes[i] = new AnUtility.AnCheckBox(" ", true)); // <=== FIXUP ((AnUtility.AnCheckBox) staticViewCheckBoxes[i]).addItemListener(this); JLabel itemlabel = (JLabel) AnUtility.getItem(tab_names[i]); // itemlabel.setDisplayedMnemonic(tab_mnems[i]); itemlabel.setLabelFor(staticViewCheckBoxes[i]); AnUtility.setAccessibleContext(itemlabel.getAccessibleContext(), tab_names[i]); list.add(itemlabel, chk_panel); } // Sidepanel if (views_tablist != null) { for (ViewsSetting.View view : views_tablist) { anWindow.getViewsPanel().createView(anWindow, view.getAnDispTab(), View.Type.STATIC_VIEW); } } } // Build the list of checkboxes for the standard tabs private void buildStdTabList(AnList list) { JPanel chk_panel; String[] tab_names; char[] tab_mnems; JLabel itemlabel; // Add column header chk_panel = new AnJPanel(); list.getAccessibleContext() .setAccessibleDescription(AnLocale.getString("List of Views to choose from")); List standard_tablist = getViewsSetting().getStandardViews(); tab_names = new String[standard_tablist.size()]; tab_mnems = new char[standard_tablist.size()]; for (int i = 0; i < standard_tablist.size(); i++) { tab_names[i] = standard_tablist.get(i).getAnDispTab().getTName(); tab_mnems[i] = standard_tablist.get(i).getAnDispTab().getTMnem(); } if (tab_names == null) { return; } // Compose the list of checkboxes standardObjectCheckBoxes = new AnUtility.AnCheckBox[tab_names.length]; // Compose standard tabs checklist for (int i = 0; i < standardObjectCheckBoxes.length; i++) { ViewsSetting.View view = standard_tablist.get(i); chk_panel = new AnJPanel(new GridLayout(1, 2)); chk_panel.add(standardObjectCheckBoxes[i] = new AnUtility.AnCheckBox(" ", view.isSelected())); ((AnUtility.AnCheckBox) standardObjectCheckBoxes[i]).addItemListener(this); itemlabel = (JLabel) AnUtility.getItem(tab_names[i]); AnUtility.setAccessibleContext(itemlabel.getAccessibleContext(), tab_names[i]); AnUtility.setAccessibleContext( standardObjectCheckBoxes[i].getAccessibleContext(), tab_names[i]); list.add(itemlabel, chk_panel); } // Sidepanel if (standard_tablist != null) { for (ViewsSetting.View view : standard_tablist) { anWindow.getViewsPanel().createView(anWindow, view.getAnDispTab(), View.Type.STANDARD); } } } // Build the list of checkboxes for the memory object tabs private void buildMemTabList() { JLabel memlabel; memlist.removeAll(); // Add column header memchk_panel = new AnJPanel(new GridLayout(1, 1)); memlist .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("List of memory object Views to choose from")); List mem_tablist = getViewsSetting().getMemoryViews(); // Compose memory object tabs checklist memoryObjectCheckBoxes = new AnUtility.AnCheckBox[mem_tablist.size()]; for (int i = 0; i < memoryObjectCheckBoxes.length; i++) { ViewsSetting.View view = mem_tablist.get(i); memchk_panel = new AnJPanel(new GridLayout(1, 2)); memchk_panel.add( memoryObjectCheckBoxes[i] = new AnUtility.AnCheckBox(" ", view.isSelected())); memoryObjectCheckBoxes[i].addItemListener(this); memlabel = (JLabel) AnUtility.getItem(view.getAnDispTab().getTName()); AnUtility.setAccessibleContext( memlabel.getAccessibleContext(), view.getAnDispTab().getTName()); AnUtility.setAccessibleContext( memoryObjectCheckBoxes[i].getAccessibleContext(), view.getAnDispTab().getTName()); memlist.add(memlabel, memchk_panel); } memlist.revalidate(); // Sidepanel if (mem_tablist != null) { for (ViewsSetting.View view : mem_tablist) { anWindow.getViewsPanel().createView(anWindow, view.getAnDispTab(), View.Type.MEMORY); } } } // Build the list of checkboxes for the index object tabs private void buildIndxTabList() { JLabel indxlabel; indxlist.removeAll(); // Add column header indxchk_panel = new AnJPanel(new GridLayout(1, 1)); indxlist .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("List of index object Vews to choose from")); List indx_tablist = getViewsSetting().getIndexViews(); // Compose index object tabs checklist indexObjectCheckBoxes = new AnUtility.AnCheckBox[indx_tablist.size()]; for (int i = 0; i < indexObjectCheckBoxes.length; i++) { ViewsSetting.View view = indx_tablist.get(i); indxchk_panel = new AnJPanel(new GridLayout(1, 2)); indxchk_panel.add( indexObjectCheckBoxes[i] = new AnUtility.AnCheckBox(" ", view.isSelected())); indexObjectCheckBoxes[i].addItemListener(this); indxlabel = (JLabel) AnUtility.getItem(view.getAnDispTab().getTName()); AnUtility.setAccessibleContext( indxlabel.getAccessibleContext(), view.getAnDispTab().getTName()); AnUtility.setAccessibleContext( indexObjectCheckBoxes[i].getAccessibleContext(), view.getAnDispTab().getTName()); indxlist.add(indxlabel, indxchk_panel); } indxlist.revalidate(); // Sidepanel if (indx_tablist != null) { for (ViewsSetting.View view : indx_tablist) { anWindow.getViewsPanel().createView(anWindow, view.getAnDispTab(), View.Type.INDEX); } } } private void updateTLDataCheckBoxes() { tl_type_panel.removeAll(); tldata_checkBoxes = new ArrayList(); // Does listener result in leak? List tldata_unames = timelineSetting.getTLDataUNames(); long tldata_check_hidden_bitmask = timelineSetting.getTLDataHiddenMask(); for (int i = 0; i < tldata_unames.size(); i++) { long hidden = ((1L << i) & tldata_check_hidden_bitmask); JCheckBox check = new AnUtility.AnCheckBox(tldata_unames.get(i), (hidden == 0)); check.addItemListener(this); tl_type_panel.add(check); tldata_checkBoxes.add(check); } tl_type_panel.revalidate(); } // Update show source with/without metrics in disassembly display public void itemStateChanged(final ItemEvent event) { final Object source = event.getItemSelectable(); if (source == dis_src) { if (event.getStateChange() == ItemEvent.DESELECTED) { dis_asrc.setSelected(false); } } else if (source == dis_asrc) { if (event.getStateChange() == ItemEvent.SELECTED) { dis_src.setSelected(true); } } if (settingsDialog != null) { settingsDialog.setButtonsEnabled(true); } } // Action performed public void actionPerformed(final ActionEvent event) { final String cmd = event.getActionCommand(); if (cmd.equals(AnLocale.getString("OK")) || cmd.equals(AnLocale.getString("Apply"))) { apply(); } else if (cmd.equals(AnLocale.getString("Export..."))) { new ExportSettingsDialog(frame).setVisible(true); } else if (cmd.equals(AnLocale.getString("Import..."))) { new ImportSettingsDialog(frame).setVisible(true); } } private void updateMemTab() { Object[] memObjs = ViewsSetting.getMemObjectsIPC(); // IPC boolean[] memSelected = ViewsSetting.getMemTabSelectionStateIPC(); // IPC // Copy the check box states (may not yet be saved) for (int i = 0; i < memoryObjectCheckBoxes.length; i++) { JCheckBox checkBox = memoryObjectCheckBoxes[i]; if (i < memSelected.length) { memSelected[i] = checkBox.isSelected(); } } getViewsSetting().updateMemoryObjects(null, memObjs, memSelected); } private void addCustomMemTab() { // System.out.println("Settings.addCustomMemTab"); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { updateMemTab(); } }, "custommemtab"); } // Dialog to add custom memory object tab private class CustomMemDialog extends AnDialog { JTextField obj_name; AnUtility.AnTextArea formula_field; public CustomMemDialog(int win_id, final Frame frame) { super( anWindow, frame, AnLocale.getString("Add Memory Object"), false, null, null, AnVariable.HELP_CustomMemTab, true); initComponents(); } // Initialize GUI components private void initComponents() { setAccessory(setCustomPanel()); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); } // Action performed @Override public void actionPerformed(final ActionEvent event) { final String cmd = event.getActionCommand(); if (cmd.equals(AnLocale.getString("OK")) || cmd.equals(AnLocale.getString("Apply"))) { String formula = formula_field.getText(); String formula_str = formula.replaceAll("\n", " "); AnUtility.checkIPCOnWrongThread(false); String sts = ViewsSetting.defineMemObjIPC( obj_name.getText(), formula_str, null, null); // IPC // CXXX add descriptions AnUtility.checkIPCOnWrongThread(true); if (sts == null) { // Successfully added new object, repaint mem checkboxes // Clear the text fields getViewsSetting() .addCustomMemoryObject( obj_name.getText(), formula_str, null, null); // CXXX add descriptions formula_field.setText(""); obj_name.setText(""); addCustomMemTab(); settingsDialog.setButtonsEnabled(true); } else { // Don't clear the text fields, so the user can correct an error AnUtility.showMessage(tabs_custom_mem_dlg, sts, JOptionPane.ERROR_MESSAGE); } } } private JPanel setCustomPanel() { JPanel basePanel, namePanel, formulaPanel; JLabel name_label, formula_label; basePanel = new AnJPanel(new GridBagLayout()); // basePanel.setBorder(AnVariable.fieldBorder); // Add name panel namePanel = new AnJPanel(); namePanel.setLayout(new BorderLayout()); namePanel.setBorder(AnVariable.fieldBorder); name_label = (JLabel) AnUtility.getTitle(AnLocale.getString("Object Name:")); name_label.setDisplayedMnemonic(AnLocale.getString('O', "MNEM_CUSTOMOBJ_NAME")); namePanel.add(name_label, BorderLayout.NORTH); obj_name = new JTextField(15); name_label.setLabelFor(obj_name); AnUtility.setAccessibleContext(obj_name.getAccessibleContext(), name_label.getText()); namePanel.add(obj_name, BorderLayout.CENTER); // Add formula panel formulaPanel = new AnJPanel(); formulaPanel.setLayout(new BorderLayout()); formulaPanel.setBorder(AnVariable.fieldBorder); formula_label = (JLabel) AnUtility.getTitle(AnLocale.getString("Formula:")); formula_label.setDisplayedMnemonic(AnLocale.getString('F', "MNEM_CUSTOMOBJ_FORMULA")); formulaPanel.add(formula_label, BorderLayout.NORTH); formula_field = new AnUtility.AnTextArea("", true); AnUtility.setAccessibleContext(formula_field.getAccessibleContext(), formula_label.getText()); formula_field.setLineWrap(true); formula_field.setWrapStyleWord(true); // formula_field.setFont(CollectUtility.text_font); JScrollPane form_scroll = new AnJScrollPane( formula_field, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); form_scroll.setPreferredSize(new Dimension(getPreferredSize().width, 120)); form_scroll.setBorder(BorderFactory.createLineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR)); formula_label.setLabelFor(formula_field); formulaPanel.add(form_scroll, BorderLayout.CENTER); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; // gridBagConstraints.insets = new Insets(8, 8, 0, 8); basePanel.add(namePanel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; // gridBagConstraints.insets = new Insets(0, 8, 0, 8); basePanel.add(formulaPanel, gridBagConstraints); return basePanel; } } // class CustomMemDialog private void updateIndxTab() { Object[] indxObjs = ViewsSetting.getIndxObjDescriptionsIPC(); // IPC boolean[] indxSelected = ViewsSetting.getIndxTabSelectionStateIPC(); // IPC // Copy the check box states (may not yet be saved) for (int i = 0; i < indexObjectCheckBoxes.length; i++) { JCheckBox checkBox = indexObjectCheckBoxes[i]; if (i < indxSelected.length) { indxSelected[i] = checkBox.isSelected(); } } getViewsSetting().updateIndexObjects(null, indxObjs, indxSelected); // Will fire change event } private void addCustomIndxTab() { // System.out.println("Settings.addCustomIndxTab"); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { updateIndxTab(); } }, "customindxtab"); } private void updateIndxMemTab() { Object[] indxObjs = ViewsSetting.getIndxObjDescriptionsIPC(); // IPC boolean[] indxSelected = ViewsSetting.getIndxTabSelectionStateIPC(); // IPC // Copy the check box states (may not yet be saved) for (int i = 0; i < indexObjectCheckBoxes.length; i++) { JCheckBox checkBox = indexObjectCheckBoxes[i]; if (i < indxSelected.length) { indxSelected[i] = checkBox.isSelected(); } } Object[] memObjs = ViewsSetting.getMemObjectsIPC(); // IPC boolean[] memSelected = ViewsSetting.getMemTabSelectionStateIPC(); // IPC // Copy the check box states (may not yet be saved) for (int i = 0; i < memoryObjectCheckBoxes.length; i++) { JCheckBox checkBox = memoryObjectCheckBoxes[i]; if (i < memSelected.length) { memSelected[i] = checkBox.isSelected(); } } getViewsSetting().updateIndexMemoryObjects(null, indxObjs, indxSelected, memObjs, memSelected); } private void addCustomIndxMemTab() { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { updateIndxMemTab(); } }, "customindxmemtab"); } // Dialog to add custom index object tab private class CustomIndxDialog extends AnDialog { JTextField obj_name; AnUtility.AnTextArea formula_field; public CustomIndxDialog(int win_id, final Frame frame) { super( anWindow, frame, AnLocale.getString("Add Index Object"), false, null, null, AnVariable.HELP_CustomIndxTab, true); initComponents(); } // Initialize GUI components private void initComponents() { setAccessory(setCustomPanel()); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); } // Action performed @Override public void actionPerformed(final ActionEvent event) { final String cmd = event.getActionCommand(); if (cmd.equals(AnLocale.getString("OK")) || cmd.equals(AnLocale.getString("Apply"))) { String formula = formula_field.getText(); String formula_str = formula.replaceAll("\n", " "); AnUtility.checkIPCOnWrongThread(false); String sts = ViewsSetting.defineIndxObjIPC( obj_name.getText(), formula_str, null, null); // IPC // CXXX add descriptions AnUtility.checkIPCOnWrongThread(true); if (sts == null) { // Successfully added new object, repaint indx checkboxes getViewsSetting() .addCustomIndexObject( obj_name.getText(), formula_str, null, null); // CXXX add descriptions addCustomIndxTab(); // clear the fields for the next definition formula_field.setText(""); obj_name.setText(""); settingsDialog.setButtonsEnabled(true); } else { AnUtility.showMessage(tabs_custom_indx_dlg, sts, JOptionPane.ERROR_MESSAGE); } } } private JPanel setCustomPanel() { JPanel basePanel, namePanel, formulaPanel; JLabel name_label, formula_label; basePanel = new AnJPanel(new GridBagLayout()); // basePanel.setBorder(AnVariable.fieldBorder); // Add name panel namePanel = new AnJPanel(); namePanel.setLayout(new BorderLayout()); namePanel.setBorder(AnVariable.fieldBorder); name_label = (JLabel) AnUtility.getTitle(AnLocale.getString("Object Name:")); name_label.setDisplayedMnemonic(AnLocale.getString('O', "MNEM_CUSTOMOBJ_NAME")); namePanel.add(name_label, BorderLayout.NORTH); obj_name = new JTextField(15); name_label.setLabelFor(obj_name); AnUtility.setAccessibleContext(obj_name.getAccessibleContext(), name_label.getText()); namePanel.add(obj_name, BorderLayout.CENTER); // Add formula panel formulaPanel = new AnJPanel(); formulaPanel.setLayout(new BorderLayout()); formulaPanel.setBorder(AnVariable.fieldBorder); formula_label = (JLabel) AnUtility.getTitle(AnLocale.getString("Formula:")); formula_label.setDisplayedMnemonic(AnLocale.getString('F', "MNEM_CUSTOMOBJ_FORMULA")); formulaPanel.add(formula_label, BorderLayout.NORTH); formula_field = new AnUtility.AnTextArea("", true); AnUtility.setAccessibleContext(formula_field.getAccessibleContext(), formula_label.getText()); formula_field.setLineWrap(true); formula_field.setWrapStyleWord(true); // formula_field.setFont(CollectUtility.text_font); JScrollPane form_scroll = new AnJScrollPane( formula_field, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); form_scroll.setPreferredSize(new Dimension(getPreferredSize().width, 120)); form_scroll.setBorder(BorderFactory.createLineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR)); formula_label.setLabelFor(formula_field); formulaPanel.add(form_scroll, BorderLayout.CENTER); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; basePanel.add(namePanel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; basePanel.add(formulaPanel, gridBagConstraints); return basePanel; } } private void checkTimelineChanged(Object originalSource) { Object newTm = getTimelineSettings(needsTimelineEvent); needsTimelineEvent = false; getTimelineSetting() .set( originalSource, (List) newTm, newTm != null); // Will fire AnChangeEvent if settings have changed } public Object edt_getTimelineOptions() { Object obj = getTimelineSettings(true); return obj; } private void checkSearchPathChanged(Object originalSource) { searchPathPanel.checkSearchPathChanged(originalSource); } private void checkPathMapChanged(Object originalSource) { // pathMapPanel.checkPathMapChanged(originalSource); pathmapsPanel.checkPathMapChanged(originalSource); } private void checkCallTreeChanges(Object originalSource) { callTreePanel.checkChanges(originalSource); } private void checkViewsChanges(Object originalSource) { boolean[] values = new boolean [staticViewCheckBoxes.length + standardObjectCheckBoxes.length + indexObjectCheckBoxes.length + memoryObjectCheckBoxes.length]; int index = 0; for (int i = 0; i < staticViewCheckBoxes.length; i++) { values[index++] = ((JCheckBox) staticViewCheckBoxes[i]).isSelected(); } for (int i = 0; i < standardObjectCheckBoxes.length; i++) { values[index++] = ((JCheckBox) standardObjectCheckBoxes[i]).isSelected(); } for (int i = 0; i < indexObjectCheckBoxes.length; i++) { values[index++] = ((JCheckBox) indexObjectCheckBoxes[i]).isSelected(); } for (int i = 0; i < memoryObjectCheckBoxes.length; i++) { values[index++] = ((JCheckBox) memoryObjectCheckBoxes[i]).isSelected(); } getViewsSetting().set(originalSource, values); } // Update display private void applyChanges() { // Keep this order is mandatory; setVisible -> setSort -> setOrder. checkMetricsChanged(this); // Will fire AnChangeEvent if changed checkSourceDisassemblyChanged(this); // Will fire AnChangeEvent if changed checkCompareModeChanged(this); // Will fire AnChangeEvent if changed checkViewModeChanged(this); // Will fire AnChangeEvent if changed checkFormatChanged(this); // Will fire AnChangeEvent if changed checkWrapNameChanged(this); // Will fire AnChangeEvent if changed checkTimelineChanged(this); // Will fire AnChangeEvent if changed checkSearchPathChanged(this); // Will fire AnChangeEvent if changed checkPathMapChanged(this); // Will fire AnChangeEvent if changed checkCallTreeChanges(this); // Will fire AnChangeEvent if changed checkViewsChanges(this); // Will fire AnChangeEvent if changed } // Set annotated visibility & check whether recompute is needed or not private void checkSourceDisassemblyChanged(Object originalsource) { final int[] anno_set; int new_vis_src; int new_vis_dis; final int new_threshold_src; final int new_threshold_dis; final boolean new_src_visible; final boolean new_src_metric; final boolean new_hex_visible; final boolean new_cmp_visible; final boolean new_scope_only; final boolean new_func_visible; // Get new Compiler Commentary visibility new_vis_src = new_vis_dis = 0; for (int i = 0; i < size_ccmv; i++) { if (((JCheckBox) src_chks[i]).isSelected()) { new_vis_src |= ccmv_type[i]; } if (((JCheckBox) dis_chks[i]).isSelected()) { new_vis_dis |= ccmv_type[i]; } } if (vis_src != new_vis_src) { vis_src = new_vis_src; } if (vis_dis != new_vis_dis) { vis_dis = new_vis_dis; } // Get new Highlighting Threshold new_threshold_src = Integer.parseInt(((JTextField) threshold[0]).getText()); if (threshold_src != new_threshold_src) { threshold_src = new_threshold_src; } new_threshold_dis = Integer.parseInt(((JTextField) threshold[1]).getText()); if (threshold_dis != new_threshold_dis) { threshold_dis = new_threshold_dis; } // Get new Disassembly Listing visibility new_src_visible = dis_src.isSelected(); if (src_visible != new_src_visible) { src_visible = new_src_visible; } new_src_metric = dis_asrc.isSelected(); if (src_metric != new_src_metric) { src_metric = new_src_metric; } new_hex_visible = dis_hex.isSelected(); if (hex_visible != new_hex_visible) { hex_visible = new_hex_visible; } new_cmp_visible = cmp_line.isSelected(); if (cmp_visible != new_cmp_visible) { cmp_visible = new_cmp_visible; } new_func_visible = func_line.isSelected(); if (func_visible != new_func_visible) { func_visible = new_func_visible; } new_scope_only = dis_scope.isSelected(); if (scope_only != new_scope_only) { scope_only = new_scope_only; } anno_set = new int[10]; anno_set[0] = vis_src; anno_set[1] = vis_dis; anno_set[2] = threshold_src; anno_set[3] = threshold_dis; anno_set[4] = src_visible ? 1 : 0; anno_set[5] = src_metric ? 1 : 0; anno_set[6] = hex_visible ? 1 : 0; anno_set[7] = cmp_visible ? 1 : 0; anno_set[8] = scope_only ? 1 : 0; anno_set[9] = func_visible ? 1 : 0; getSourceDisassemblySetting() .set(originalsource, anno_set); // Will fire AnChangeevent if changes } private void checkCompareModeChanged(Object originalsource) { CompareMode newMode = !cmpModeLabel.isEnabled() ? CompareMode.CMP_DISABLE : cmp_abs_value.isSelected() ? CompareMode.CMP_ENABLE : cmp_delta.isSelected() ? CompareMode.CMP_DELTA : CompareMode.CMP_RATIO; getCompareModeSetting().set(originalsource, newMode); // Will fire AnChangeevent if changes } private void checkFormatChanged(Object originalsource) { FormatSetting.Style newStyle = mangled_fmt.isSelected() ? FormatSetting.Style.MANGLED : long_fmt.isSelected() ? FormatSetting.Style.LONG : FormatSetting.Style.SHORT; boolean newAppendSoName = soname_chk.isSelected(); formatSetting.set( originalsource, newStyle, newAppendSoName); // Will fire AnChangeevent if changes } private void checkWrapNameChanged(Object originalsource) { getTableSettings() .setWrapMetricNames( originalsource, wrapNameCheckBox.isSelected()); // Will fire AnChangeevent if changes } private void checkViewModeChanged(Object originalsource) { ViewMode newViewMode; if (view_fmt.isSelected()) { newViewMode = ViewMode.USER; } else if (view_expert_fmt.isSelected()) { newViewMode = ViewMode.EXPERT; } else { newViewMode = ViewMode.MACHINE; } getViewModeSetting().set(originalsource, newViewMode); // Will fire AnChangeevent if changes } // Set timeline whether recompute is needed or not public Object getTimelineSettings(boolean forceReturnState) { AnUtility.checkIfOnAWTThread(true); boolean new_tm = false; // tl_entity (CPU,LWP, etc) String new_tl_entity_prop_name = UserPref.getInstance().getTimelineGroupDataByButtonName(); int new_tl_entity_button_num = 0; for (int ii = 0; ii < tl_entity_button.size(); ii++) { if (tl_entity_button.get(ii).isSelected()) { TimelineSetting.EntityProp entityProp = getTimelineSetting().getTl_entity_prop(ii); if (entityProp != null) { new_tl_entity_prop_name = entityProp.prop_name; new_tl_entity_button_num = ii; } else { int xx = 1; // weird, could not find matching string. } break; } } if (getTimelineSetting().getTl_entity_selected_btn() != new_tl_entity_button_num) { new_tm = true; } boolean doShow = tldata_show_states_cb.isSelected(); if (tldata_show_states != doShow) { tldata_show_states = doShow; new_tm = true; } doShow = tldata_show_counts_cb.isSelected(); if (tldata_show_counts != doShow) { tldata_show_counts = doShow; new_tm = true; } // Stack mode final TLStack_align new_stack_align = (tl_stack_align[0].isSelected() ? TLStack_align.TLSTACK_ALIGN_ROOT : TLStack_align.TLSTACK_ALIGN_LEAF); if (getTimelineSetting().getStack_align() != new_stack_align) { new_tm = true; } // Stack depth // final int new_stack_depth = tl_slider.getValue(); // if (getTimelineSetting().getTLStackDepth() != new_stack_depth) { final int new_stack_depth = getTimelineSetting().getTLStackDepth(); // YXXX not sure if this is right... THP? if (tldata_stack_depth != new_stack_depth) { new_tm = true; } // Stack magnify final int new_stack_frame_pixels = tl_slider.getValue() + TIMELINE_STACK_FRAME_MAGNIFY_OFFSET; if (getTimelineSetting().getTLStackFramePixels() != new_stack_frame_pixels) { new_tm = true; } // synchronized (tldata_sync) { { // Data type int tldata_names_version = timelineSetting.getTLDataNamesVersion(); if (previous_tldata_names_version != tldata_names_version) { previous_tldata_names_version = tldata_names_version; new_tm = true; } long new_disable_mask; long tldata_check_hidden_bitmask = timelineSetting.getTLDataHiddenMask(); if (tldata_checkBoxes.isEmpty()) { new_disable_mask = tldata_check_hidden_bitmask; } else { new_disable_mask = 0; for (int i = 0; i < tldata_checkBoxes.size(); i++) { JCheckBox check = tldata_checkBoxes.get(i); if (!check.isSelected()) { long mask = (1L << i); new_disable_mask |= mask; } } if (tldata_check_hidden_bitmask != new_disable_mask) { timelineSetting.setTLDataHiddenMask(new_disable_mask); new_tm = true; } } // TBR? // if (new_tm) { // String tldata_cmd = timelineSetting.edt_update_tldata_cmd(); //// setTLValue(tldata_cmd, //YXXX does DBE really need to know this?? //// new_tl_entity_prop_id, new_stack_align.getValue(), //// new_stack_depth);// IPC!! // } if (new_tm) { needsTimelineEvent = true; } if (!forceReturnState && !new_tm) { return null; } // return values final ArrayList newtm_evt = new ArrayList(); // AnSettingChangeEvent.Type.TIMELINE event newtm_evt.add(new_tl_entity_prop_name); // 0 newtm_evt.add(new_tl_entity_button_num); // 1 newtm_evt.add(new_stack_align); // 2 newtm_evt.add(Integer.valueOf(new_stack_depth)); // 3 newtm_evt.add(Long.valueOf(new_disable_mask)); // 4 newtm_evt.add(timelineSetting.getTLDataCNames()); // 5 newtm_evt.add(timelineSetting.getTLDataUNames()); // 6 newtm_evt.add(Integer.valueOf(previous_tldata_names_version)); // 7 newtm_evt.add(Boolean.valueOf(tldata_show_states)); // 8 newtm_evt.add(Boolean.valueOf(tldata_show_counts)); // 9 newtm_evt.add(Integer.valueOf(new_stack_frame_pixels)); // 10 newtm_evt.add(timelineSetting.getTLDataCmd()); // 11 return newtm_evt; } // synchronized (tldata_sync) { } // Set visibility & check whether recompute is needed or not private void checkMetricsChanged(Object originalSource) { List list = metricsPanel.getMetricNameSelections(); getMetricsSetting().set(originalSource, list); // will fire AnChangeEvent if changed } // Apply changes made in Preferences dialog private void apply() { applyChanges(); settingsDialog.setButtonsEnabled(false); } // Show dialog for Save preferences public void saveAsDotErRc() { String homeDir; String workingDir = Analyzer.getInstance().getWorkingDirectory(); if (Analyzer.getInstance().isRemote()) { homeDir = AnWindow.getInstance().getHomeDir(); // IPC } else { homeDir = Analyzer.home_dir; } final Object[] options = {currentDirStr + workingDir, homeDirStr + homeDir}; Object result = JOptionPane.showInputDialog( tabbedPane, AnLocale.getString("Save Settings in:"), AnLocale.getString("Save Settings"), JOptionPane.OK_CANCEL_OPTION, null, options, options[0]); String resultString = (String) result; if (resultString == null) { // Nothing } else if (resultString.equals(options[0])) { save(workingDir); } else if (resultString.equals(options[1])) { save(homeDir); } } // Save preferences private void save(final String dir) { final String path = dir + "/.er.rc"; // apply changes before saving (CR 6387624) apply(); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { PrintWriter pw = null; // Check if file exists AnFile afile = anWindow.getAnFile(path); if (afile.exists()) { // Show confirmation dialog final String title = AnLocale.getString("Overwrite file?"); final String message = AnLocale.getString("File: ") + path + AnLocale.getString(" exists. Do you want to overwrite it?"); int res = JOptionPane.showConfirmDialog( tabbedPane, message, title, JOptionPane.YES_NO_OPTION); if (res != JOptionPane.YES_OPTION) { return; } } String localPath = path; if (Analyzer.getInstance().isRemote()) { localPath = AnWindow.tempFile().getAbsolutePath(); } try { pw = new PrintWriter(new BufferedWriter(new FileWriter(localPath))); write(pw); } catch (IOException e) { AnUtility.showMessage(tabbedPane, e.toString(), JOptionPane.ERROR_MESSAGE); } finally { if (pw != null) { pw.close(); } } if (Analyzer.getInstance().isRemote()) { int res = AnWindow.copyToRemote(localPath, path); if (res < 0) { System.err.println("Settings:copyToRemote failed: " + res); } } } }, "Presentation_thread"); } // Write preferences private void write(final PrintWriter pw) { AnMetric sortMetric; String abbr, comd, vstr; char stype, sort_stype; boolean visible, tvisible, pvisible, sort_visible; final List path; sortMetric = null; sort_stype = '\0'; sort_visible = true; // Write dmetrics pw.print("dmetrics "); // final AnMetric[] mlist = order_list.getMetrics(); final AnMetric[] mlist = getMetricsSetting().getMetricListByMType(0); int last = mlist.length - 1; String prevcmd = ""; int prevsubtype = -1; for (int i = 0; i < mlist.length; i++) { AnMetric mitem = mlist[i]; // YXXX quick/dirty workaround for adjacent duplicate items caused by comparison String thiscmd = mitem.getComd(); if (thiscmd.equalsIgnoreCase(prevcmd) && mitem.getSubType() == prevsubtype) { continue; } prevcmd = thiscmd; prevsubtype = mitem.getSubType(); // Subtype abbr = mitem.getAbbr(); // YXXX shouldn't we use getSubType() instead? if (mitem.getSubType() == AnMetric.EXCLUSIVE) { stype = 'e'; } else if (mitem.getSubType() == AnMetric.INCLUSIVE) { stype = 'i'; } else { stype = '\0'; } // Sort visible = mitem.isVVisible(); tvisible = mitem.isTVisible(); pvisible = mitem.isPVisible(); if (mitem.isSorted()) { sortMetric = mitem; sort_stype = stype; sort_visible = (visible || tvisible || pvisible); } // Visibility if (stype == '\0') { if (!visible) { pw.print('!'); } } else { pw.print(stype); vstr = ""; if (mitem.is_time_val()) { if (visible) { vstr += '+'; } if (tvisible) { vstr += '.'; } } else if (visible || tvisible) { vstr += '.'; } if (pvisible) { vstr += '%'; } if (vstr.equals("")) { pw.print('!'); } else { pw.print(vstr); } } // Type comd = mitem.getComd(); if (i == last) { pw.println(comd); } else { pw.print(comd + ":"); } } // Write dsort if (sortMetric != null) { pw.print("dsort "); if (sort_stype != '\0') { pw.print(sort_stype); pw.print(sort_visible ? '.' : '!'); } else if (!sort_visible) { pw.print('!'); } pw.println(sortMetric.getComd()); } // Write Compiler Commentary visibility pw.println("scc " + getCompComm(vis_src, false, false, false, false, false, false)); pw.println( "dcc " + getCompComm( vis_dis, !src_visible, src_visible, src_metric, hex_visible, cmp_visible, scope_only)); // Write the threshold pw.println("sthresh " + threshold_src); pw.println("dthresh " + threshold_dis); // Write name formats pw.println("name " + formatSetting.getStyle().name().toLowerCase()); // Write view mode pw.println("view " + getViewModeSetting().get().name().toLowerCase()); // TBR? // Write timeline mode // int btn = getTimelineSetting().getTl_entity_selected_btn(); // TimelineSetting.EntityProp entityProp = // getTimelineSetting().getTl_entity_prop(btn); // if(entityProp!=null){ // String modecmd = entityProp.prop_cmd; // pw.println("tlmode " + // modecmd // + ":" + getTimelineSetting().getStack_align().toString().toLowerCase() + // ":depth=" + getTimelineSetting().getTLStackDepth()); // } // synchronized (tldata_sync) { { // String tldata_cmd = timelineSetting.edt_update_tldata_cmd(); // pw.println("tldata all" + tldata_cmd); // tldata_unused_cnames.clear(); // dump unused baggage } // Write search path path = getSearchPathSetting().get(); last = path.size() - 1; if (last >= 0) { comd = "addpath "; for (int i = 0; i <= last; i++) { comd += path.get(i); if (i != last) { comd += ":"; } } pw.println(comd); } String[] from = AnWindow.getInstance().getSettings().getPathMapSetting().getPathMapFrom(); String[] to = AnWindow.getInstance().getSettings().getPathMapSetting().getPathMapTo(); if (from.length == to.length) { for (int i = 0; i < from.length; i++) { pw.println("pathmap " + from[i] + " " + to[i]); } } // Save the custom index object defines Object[] custom_list = ViewsSetting.getCustomIndxObjectsIPC(); if (custom_list != null) { String[] cnames = (String[]) custom_list[0]; // Names of custom index objects String[] expr = (String[]) custom_list[1]; // Formula for custom index object for (int i = 0; i < cnames.length; i++) { StringBuffer defineComd = new StringBuffer("indxobj_define "); defineComd.append(cnames[i] + " \"" + expr[i] + "\""); pw.println(defineComd); } } } // Get Compiler Commentary visibility command private static String getCompComm( final int vis_bits, final boolean no_src, final boolean show_src, final boolean show_asrc, final boolean show_hex, final boolean show_cmp, final boolean scope_only) { String str = ""; boolean first = true; for (int i = 0; i < size_ccmv; i++) { if ((vis_bits & ccmv_type[i]) != 0) { if (first) { first = false; } else { str += ":"; } str += ccmv_comd[i]; } } // Got nothing if (first) { str = "none"; } // Set source visibility for disasm if (no_src) { str += ":nosrc"; } if (show_src) { str += ":src"; } if (show_asrc) { str += ":asrc"; } // Set hexadecimal visibility of instruction if (show_hex) { str += ":hex"; } if (show_cmp) { str += ":cf"; } if (scope_only) { str += ":scope"; } return str; } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- public void toggleDisFuncScope() { scope_only = !scope_only; dis_scope.setSelected(scope_only); checkSourceDisassemblyChanged(this); // Will fire AnChangeEvent if changed } @Override public void stateChanged(final ChangeEvent e) { settingsDialog.setButtonsEnabled(true); } @Override public void insertUpdate(final DocumentEvent e) { settingsDialog.setButtonsEnabled(true); } @Override public void removeUpdate(final DocumentEvent e) { settingsDialog.setButtonsEnabled(true); } @Override public void changedUpdate(final DocumentEvent e) { settingsDialog.setButtonsEnabled(true); } // Native methods from liber_dbe.so public static AnMetric[] getMetricList(final Object[] ref_data) { final int msize = ((int[]) ref_data[0]).length; AnMetric[] mlist = new AnMetric[msize]; final int[] type = (int[]) ref_data[0]; final int[] subtype = (int[]) ref_data[1]; final int[] clock = (int[]) ref_data[2]; final int[] flavors = (int[]) ref_data[3]; final int[] value_styles = (int[]) ref_data[4]; final String[] user_name = (String[]) ref_data[5]; final String[] expr_spec = (String[]) ref_data[6]; final String[] aux = (String[]) ref_data[7]; final String[] name = (String[]) ref_data[8]; final String[] abbr = (String[]) ref_data[9]; final String[] comd = (String[]) ref_data[10]; final String[] unit = (String[]) ref_data[11]; final int[] vis = (int[]) ref_data[12]; final boolean[] sorted = (boolean[]) ref_data[13]; final String[] legend = (String[]) ref_data[14]; final int[] valtype = (int[]) ref_data[15]; final String[] data_type_name = (String[]) ref_data[16]; final String[] data_type_uname = (String[]) ref_data[17]; final String[] short_desc = (String[]) ref_data[18]; for (int i = 0; i < msize; i++) { AnMetric m = new AnMetric( type[i], subtype[i], clock[i], flavors[i], value_styles[i], user_name[i], expr_spec[i], aux[i], name[i], abbr[i], comd[i], unit[i], legend[i], vis[i], sorted[i], valtype[i], data_type_name[i], data_type_uname[i], short_desc[i]); mlist[i] = m; } return mlist; } /* * ------------------------------------- INNER CLASSES ---------------------------------------------------- */ // Slider listener for updating the value label final class SliderLabelListener implements ChangeListener { final JLabel label; public SliderLabelListener(final JLabel label) { this.label = label; } public void stateChanged(final ChangeEvent e) { final JSlider slider = (JSlider) e.getSource(); label.setText(AnLocale.getString("Call Stack Magnification: ") + slider.getValue()); if (settingsDialog != null) { settingsDialog.setButtonsEnabled(true); } } } protected void setMessageAreaVisible(boolean visible) { settingsDialog.setMessageAreaVisible(visible); } public final class SettingsDialog extends AnDialog implements AnChangeListener { private JTextArea messageArea; public SettingsDialog() { super(anWindow, frame, title, false, aux, mnemonic, help_id); JPanel settingsPanel = new JPanel(new BorderLayout()); settingsPanel.add(tabbedPane, BorderLayout.CENTER); messageArea = new JTextArea(); messageArea.setForeground(Color.red); messageArea.setOpaque(false); messageArea.setBorder(null); messageArea.setWrapStyleWord(true); messageArea.setEditable(false); messageArea.setLineWrap(true); messageArea.setText( AnLocale.getString( "Some settings have been modified that may require the experiment(s) to be reloaded" + " in order for the changes to take effect. An experiment can easily be reloaded" + " from Welcome view.")); messageArea.setVisible(false); messageArea.setBorder(BorderFactory.createEmptyBorder(6, 0, 0, 0)); settingsPanel.add(messageArea, BorderLayout.SOUTH); setAccessory(settingsPanel); setButtonsEnabled(false); // setModal(true); updateGUIViewMode(); updateGUIDisplayCompareMode(); updateGUINameFormat(); updateGUITableFormat(); AnEventManager.getInstance().addListener(this); setBackground(AnEnvironment.DEFAULT_DIALOG_BACKGROUND); } protected void setMessageAreaVisible(boolean visible) { if (messageArea != null) { messageArea.setVisible(visible); } } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a * different (worker) thread and not wait for it to finish. o It cannot spend significant time * handling the event. Significant work like doCompute needs to be dispatched to a worker * thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("Settings.SettingsDialog stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: case EXPERIMENTS_LOADED_FAILED: break; case EXPERIMENTS_LOADED: updateTLDataCheckBoxes(); if (messageArea != null) { messageArea.setVisible(false); } break; case FILTER_CHANGED: case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); Object originalSource = anSettingChangeEvent.getOriginalSource(); // System.out.println("Settings getOriginalSource: " + originalSource); if (originalSource == Settings.this) { return; } // System.out.println("Settings getOriginalSource: // doIt..............."); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE) { updateGUIViewMode(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE_ENABLED) { updateGUIViewModeVisible(); } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE) { updateGUIDisplayCompareMode(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT) { updateGUINameFormat(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.TABLE_FORMATS) { updateGUITableFormat(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.SRC_DIS) { updateGUISourceDisassembly(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.TIMELINE) { updateGUITimeline(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.SEARCH_PATH) { updateGUISearchPath(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.PATH_MAP) { updateGUIPathMap(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.CALL_TREE) { updateGUICallTree(); // update GUI } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { updateGUIMetrics(); // update GUI updateGUITimelineData(); metricsPanel.updateGUIValues(); } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEWS) { ViewsSetting.Setting oldSetting = (ViewsSetting.Setting) anSettingChangeEvent.getOldValue(); ViewsSetting.Setting newSetting = (ViewsSetting.Setting) anSettingChangeEvent.getNewValue(); updateGUIViews(oldSetting, newSetting); // update GUI } break; case DEBUG: // debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void actionPerformed(final ActionEvent event) { getDefault().actionPerformed(event); } public void showDialog(boolean show) { setVisible(show); } public void setButtonsEnabled(boolean set) { apply.setEnabled(set); ok.setEnabled(set); aux_actions[0].setEnabled(!set); // Export... aux_actions[1].setEnabled(!set); // Import... } public boolean areButtonsEnabled() { return apply.isEnabled(); } } /* * ------------------------------------- CONSTANTS -------------------------------------------------------- */ private static final String[] aux = { AnLocale.getString("Export..."), AnLocale.getString("Import...") }; private static final char[] mnemonic = { AnLocale.getString('o', "MNEM_SETTINGS_EXPORT"), AnLocale.getString('i', "MNEM_SETTINGS_IMPORT") }; private static final String help_id = AnVariable.HELP_Settings; private static final String title = AnLocale.getString("Settings"); private static final String homeDirStr = AnLocale.getString("Home directory: "); private static final String currentDirStr = AnLocale.getString("Current directory: "); public enum TLData_type { // Note: the cmd strings are used for .er.rc TL_SAMPLE("PROFDATA_TYPE_SAMPLE", "sample", AnUtility.samp_icon), TL_GCEVENT( "PROFDATA_TYPE_GCEVENT", "gcevent", AnUtility.del_icon), // CXXX Bug 20801848 - change icon TL_HEAPSZ("PROFDATA_TYPE_HEAPSZ", "heapsize", AnUtility.heap_icon), TL_CLOCK("PROFDATA_TYPE_CLOCK", "clock", AnUtility.prof_icon), TL_HWC("PROFDATA_TYPE_HWC", "hwc", AnUtility.hwc_icon), TL_SYNC("PROFDATA_TYPE_SYNCH", "synctrace", AnUtility.sync_icon), TL_HEAP("PROFDATA_TYPE_HEAP", "heaptrace", AnUtility.heap_icon), TL_MPI("PROFDATA_TYPE_MPI", "mpitrace", AnUtility.mpi_icon), TL_RACES("PROFDATA_TYPE_RACE", "datarace", AnUtility.races_icon), TL_DLCK("PROFDATA_TYPE_DLCK", "deadlock", AnUtility.races_icon), TL_IOTRACE("PROFDATA_TYPE_IOTRACE", "iotrace", AnUtility.iotrace_icon), TL_UNKNOWN(null, "unknown", null), TL_ALL(null, "all", null); private TLData_type(String dataIdName, String cmd, ImageIcon icon) { data_id_name = dataIdName; this.cmd = cmd; this.icon = icon; } public final String getTLDataBaseCmd() { return cmd; } public final String getTLDataIdName() { return data_id_name; } ; public final ImageIcon getIcon() { return icon; } ; @Override public String toString() { return data_id_name; } private final String data_id_name; // DATA_ID name (not user name) private final String cmd; // .er.rc command name private final ImageIcon icon; private static final TLData_type values[] = { // Note: must match order above. // However, values do not have to match DBE DATA_* enums TL_SAMPLE, TL_GCEVENT, TL_HEAPSZ, TL_CLOCK, TL_HWC, TL_SYNC, TL_HEAP, TL_MPI, TL_RACES, TL_DLCK, TL_IOTRACE }; // CXXX Bug 20801848 // public static final List VALUES // = Collections.unmodifiableList(Arrays.asList(values)); public static final TLData_type find(String _dataIdName) { String dataIdName = _dataIdName.toUpperCase(); for (TLData_type tmp : values) { if (tmp.data_id_name.equals(dataIdName)) { return tmp; } } return TL_UNKNOWN; } } public enum TLStack_align { // Note: these strings are used for .er.rc TLSTACK_MODE_UNKNOWN(0, AnLocale.getString("Unknown")), TLSTACK_ALIGN_ROOT(1, AnLocale.getString("root")), TLSTACK_ALIGN_LEAF(2, AnLocale.getString("leaf")); private TLStack_align(int v, String n) { value = v; name = n; } public final int getValue() { return value; } ; @Override public String toString() { return name; } private final String name; private final int value; private static final TLStack_align values[] = {TLSTACK_ALIGN_ROOT, TLSTACK_ALIGN_LEAF}; public static final List VALUES = Collections.unmodifiableList(Arrays.asList(values)); public static final TLStack_align find(int intVal) { for (TLStack_align tmp : values) { if (tmp.value == intVal) { return tmp; } } return TLSTACK_MODE_UNKNOWN; } } private static final int size_ccmv = 11; private static final int CCMV_BASIC = 0x400; // for default messages private static final int CCMV_VER = 0x001; // Versioning messages private static final int CCMV_WARN = 0x002; // Warning messages private static final int CCMV_PAR = 0x004; // Parallelization messages private static final int CCMV_QUERY = 0x008; // Compiler queries private static final int CCMV_LOOP = 0x010; // Loop detail messages private static final int CCMV_PIPE = 0x020; // Pipelining messages private static final int CCMV_INLINE = 0x040; // Inlining information private static final int CCMV_MEMOPS = 0x080; // Messages concerning memory op private static final int CCMV_FE = 0x100; // Front-end messages private static final int CCMV_CG = 0x200; // Code-generator messages static { ccmv_type = new int[size_ccmv]; ccmv_desc = new String[size_ccmv]; ccmv_comd = new String[size_ccmv]; ccmv_mnem = new char[size_ccmv]; ccmv_type[0] = CCMV_BASIC; ccmv_desc[0] = AnLocale.getString("Default", "PRESENT_DEFAULT"); ccmv_comd[0] = "basic"; ccmv_mnem[0] = AnLocale.getString('D', "MNEM_PRESENT_DEFAULT"); ccmv_type[1] = CCMV_VER; ccmv_desc[1] = AnLocale.getString("Versioning"); ccmv_comd[1] = "version"; // ccmv_mnem[1] = AnLocale.getString('V', "MNEM_PRESENT_VERSIONING"); ccmv_type[2] = CCMV_WARN; ccmv_desc[2] = AnLocale.getString("Warning", "PRESENT_WARNING"); ccmv_comd[2] = "warn"; // ccmv_mnem[2] = AnLocale.getString('W', "MNEM_PRESENT_WARNING"); ccmv_type[3] = CCMV_PAR; ccmv_desc[3] = AnLocale.getString("Parallelization"); ccmv_comd[3] = "parallel"; // ccmv_mnem[3] = AnLocale.getString('P', "MNEM_PRESENT_PARALLELIZATION"); ccmv_type[4] = CCMV_QUERY; ccmv_desc[4] = AnLocale.getString("Compiler queries"); ccmv_comd[4] = "query"; // ccmv_mnem[4] = AnLocale.getString('q', "MNEM_PRESENT_COMPILER_QUERIES"); ccmv_type[5] = CCMV_LOOP; ccmv_desc[5] = AnLocale.getString("Loop detail"); ccmv_comd[5] = "loop"; // ccmv_mnem[5] = AnLocale.getString('L', "MNEM_PRESENT_LOOP_DETAIL"); ccmv_type[6] = CCMV_PIPE; ccmv_desc[6] = AnLocale.getString("Pipelining"); ccmv_comd[6] = "pipe"; // ccmv_mnem[6] = AnLocale.getString('n', "MNEM_PRESENT_PIPELINING"); ccmv_type[7] = CCMV_INLINE; ccmv_desc[7] = AnLocale.getString("Inlining information"); ccmv_comd[7] = "inline"; // ccmv_mnem[7] = AnLocale.getString('I', "MNEM_PRESENT_INLINE_INFORMATION"); ccmv_type[8] = CCMV_MEMOPS; ccmv_desc[8] = AnLocale.getString("Memory operations"); ccmv_comd[8] = "memops"; // ccmv_mnem[8] = AnLocale.getString('M', "MNEM_PRESENT_MEMORY_OPERATIONS"); ccmv_type[9] = CCMV_FE; ccmv_desc[9] = AnLocale.getString("Front-end"); ccmv_comd[9] = "fe"; // ccmv_mnem[9] = AnLocale.getString('F', "MNEM_PRESENT_FRONT_END"); ccmv_type[10] = CCMV_CG; ccmv_desc[10] = AnLocale.getString("Code-generator"); ccmv_comd[10] = "cg"; // ccmv_mnem[10] = AnLocale.getString('g', "MNEM_PRESENT_CODE_GENERATOR"); } private static final int MIN_WIDTH = 800; private static final int TIMELINE_STACK_FRAME_MAGNIFY_MIN = 1; private static final int TIMELINE_STACK_FRAME_MAGNIFY_MAX = 7; private static final int TIMELINE_STACK_FRAME_MAGNIFY_OFFSET = 1 - TIMELINE_STACK_FRAME_MAGNIFY_MIN; public static final int TIMELINE_MAX_STACK_FRAME_PIXELS = TIMELINE_STACK_FRAME_MAGNIFY_MAX - TIMELINE_STACK_FRAME_MAGNIFY_MIN + 1; public static final int TIMELINE_DEFAULT_STACK_FRAME_PIXELS = 4; // private final static String excl_abbr = AnLocale.getString("Excl. "); // private final static String incl_abbr = AnLocale.getString("Incl. "); // private final static String attr_abbr = AnLocale.getString("Attr. "); // private final static String data_abbr = AnLocale.getString("Data. "); // private final static String indx_abbr = AnLocale.getString("Index. "); public static final String excl_name = AnLocale.getString("Exclusive "); public static final String incl_name = AnLocale.getString("Inclusive "); public static final String attr_name = AnLocale.getString("Attributed "); public static final String data_name = AnLocale.getString("Data-derived "); public static final String time_str = AnLocale.getString(" Time"); private static final String FORMATS_STR = AnLocale.getString("Formats"); private static final String SORT_STR = AnLocale.getString("Sort"); private static final String Blank = " "; } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricSelection.java0000644000175000017500000000370714517772113021540 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; public class MetricSelection { private boolean selected; private MetricAttributes attributes; public MetricSelection(boolean selected, MetricAttributes attributes) { this.selected = selected; this.attributes = attributes; } public void set(MetricSelection metricSelection) { selected = metricSelection.isSelected(); attributes = metricSelection.getAttributes(); } /** * @return deep copy */ public MetricSelection copy() { return new MetricSelection(isSelected(), getAttributes().copy()); } public boolean isSelected() { return selected; } public void setSelected(boolean selected) { this.selected = selected; } public void setAttributes(MetricAttributes attributes) { this.attributes = attributes; } public MetricAttributes getAttributes() { return attributes; } @Override public boolean equals(Object obj) { if (obj instanceof MetricSelection) { MetricSelection metricSelection = (MetricSelection) obj; if (selected != metricSelection.isSelected()) { return false; } else { return attributes.equals(metricSelection.getAttributes()); } } else { return super.equals(obj); // To change body of generated methods, choose Tools | Templates. } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricsSetting.java0000644000175000017500000020633414517772113021414 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnDouble; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnLong; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnObject; import org.gprofng.mpmt.AnString; import org.gprofng.mpmt.AnTable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.metrics.MetricAttr; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.metrics.MetricNode; import org.gprofng.mpmt.metrics.SelectableMetricNode; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JRadioButtonMenuItem; import javax.swing.JSeparator; import javax.swing.SwingConstants; public class MetricsSetting extends Setting { private AnMetric[] availableAnMetrics; // Static once experiment has been loaded private MetricStates metricStates; // the states public static final int MET_NORMAL = 0; public static final int MET_CALL = 1; public static final int MET_DATA = 2; public static final int MET_INDEX = 3; public static final int MET_CALL_AGR = 4; public static final int MET_COMMON = 5; public static final int MET_IO = 6; public static final int MET_SRCDIS = 7; public static final int MET_HEAP = 8; public static final int MET_LAST = 9; // Count of metrics; + 1 public MetricsSetting() {} public void setHotMetric(String name, boolean hot) { for (AnMetric anMetric : availableAnMetrics) { if (anMetric.getComd().equals(name)) { anMetric.setHot(hot); break; } } } /** Called from loadExperimentGroupsInternal when experiment has been loaded */ public synchronized void initMetricListsByMType() { metricStates = new MetricStates(); metricStates.resetMetricListsByMType(); } /** Called from loadExperimentGroupsInternal when experiment has been loaded */ public synchronized void init( Object originalSource, List metricsSelectionList, Object[] ref_data, MetricNode metricsRootNode, boolean metricsReversedSort, MetricType[] metricSortByMType, List[] metricOrderLists) { availableAnMetrics = Settings.getMetricList(ref_data); List metricStateList = constructMetricStates(metricsRootNode); metricStates.updateStates(metricsRootNode, metricStateList); init( originalSource, metricsSelectionList, metricsReversedSort, metricSortByMType, metricOrderLists); } private List constructMetricStates(MetricNode metricsRootNode) { List list = new ArrayList(); constructMetricStates(metricsRootNode, null, -1, list); // Add Name metric to the end AnMetric nameMetric = availableAnMetrics[availableAnMetrics.length - 1]; // Always last ? if (nameMetric.isNameMetric()) { MetricAttributes capableAttributes = new MetricAttributes(false, false, false, false, false, false); MetricAttributes factoryAttributes = new MetricAttributes(false, false, false, false, false, false); MetricSelection factorySelection = new MetricSelection(true, factoryAttributes); MetricSelection selection = factorySelection.copy(); list.add( new MetricState("Name", -1, nameMetric, capableAttributes, factorySelection, selection)); } else { System.err.println("METRICERROR: constructMetricStates: name metric is not last!"); } return list; } private void constructMetricStates( MetricNode node, String listDisplayName, int listId, List list) { if (node.getMetricType() == MetricNode.MetricType.PLAIN_LIST_CATEGORY) { listDisplayName = node.getMetricBasic().getDisplayName(); String listName = node.getMetricBasic().getName(); if (listName.contains("PROFDATA_TYPE_HEAP")) { // heap listId = MetricNode.HEAP_LIST_ID; } else if (listName.contains("PROFDATA_TYPE_IOTRACE")) { // io listId = MetricNode.IO_LIST_ID; } else if (listName.contains("Dataspace")) { // old name ??? listId = MetricNode.DATASPACE_HWC_LIST_ID; } else if (listName.contains("PROFDATA_TYPE_HWC_DSPACE")) { // memoryspace listId = MetricNode.DATASPACE_HWC_LIST_ID; } else { listId = MetricNode.ALL_LIST_ID; } } if (node instanceof SelectableMetricNode) { SelectableMetricNode selectableMetricNode = (SelectableMetricNode) node; String name = selectableMetricNode.getMetricBasic().getName(); AnMetric anMetric = null; for (AnMetric am : availableAnMetrics) { if (am.getComd().equals(name)) { anMetric = am; } } if (anMetric == null) { System.err.println("METRICERROR: constructMetricStates: can't find metric " + name); } // Capable MetricAttr exclusiveCapable = selectableMetricNode.getExclusive().getCapable(); MetricAttr inclusiveCapable = selectableMetricNode.getInclusive().getCapable(); MetricAttributes capableAttributes = new MetricAttributes( exclusiveCapable.isTime(), exclusiveCapable.isValue(), exclusiveCapable.isPercent(), inclusiveCapable.isTime(), inclusiveCapable.isValue(), inclusiveCapable.isPercent()); // Factory MetricAttr exclusiveDefault = selectableMetricNode.getExclusive().getDefaultAttrs(); MetricAttr inclusiveDefault = selectableMetricNode.getInclusive().getDefaultAttrs(); boolean defaultSelected = exclusiveDefault.hasVisibleAttrs() || inclusiveDefault.hasVisibleAttrs(); MetricAttributes factoryAttributes = new MetricAttributes( exclusiveDefault.isTime(), exclusiveDefault.isValue(), exclusiveDefault.isPercent(), inclusiveDefault.isTime(), inclusiveDefault.isValue(), inclusiveDefault.isPercent()); MetricSelection factorySelection = new MetricSelection(defaultSelected, factoryAttributes); // Selection MetricSelection selection = factorySelection.copy(); list.add( new MetricState( listDisplayName, listId, anMetric, capableAttributes, factorySelection, selection)); } for (MetricNode child : node.getChildren()) { constructMetricStates(child, listDisplayName, listId, list); } } /* * Called from Settings, Overview, ... */ public synchronized void set(Object originalSource, String metricName, boolean selected) { MetricStates metricStatesCopy = metricStates.copy(); metricStatesCopy.setSelection(metricName, selected); set(originalSource, metricStatesCopy); } /* * Called from Overview, ... */ public synchronized void setList( Object originalSource, List metricNameSelectedList) { MetricStates metricStatesCopy = metricStates.copy(); for (MetricNameSelected mns : metricNameSelectedList) { metricStatesCopy.setSelection(mns.getName(), mns.isSelected()); } set(originalSource, metricStatesCopy); } private void set(Object originalSource, MetricStates newMetricStates) { setValueAndFireChangeEvent(originalSource, this, newMetricStates); } private synchronized void set( Object originalSource, String metricName, MetricAttributes metricAttributes) { MetricStates metricStatesCopy = metricStates.copy(); MetricState metricState = metricStatesCopy.findMetricStateByName(metricName); if (metricState != null) { metricState.getSelection().setAttributes(metricAttributes.copy()); metricState.getSelection().setSelected(metricAttributes.anySelections()); set(originalSource, metricStatesCopy); } } /* * Not used in Dodona */ public synchronized void setExclusive( Object originalSource, String metricName, boolean eTimeSelected, boolean eValueSelected, boolean ePercentSelected) { MetricState metricState = metricStates.findMetricStateByName(metricName); if (metricState != null) { MetricAttributes metricAttributesCopy = metricState.getSelection().getAttributes().copy(); metricAttributesCopy.setETime(eTimeSelected); metricAttributesCopy.setEValue(eValueSelected); metricAttributesCopy.setEPercent(ePercentSelected); set(originalSource, metricName, metricAttributesCopy); } } /* * Not used in Dodona */ public synchronized void setInclusive( Object originalSource, String metricName, boolean iTimeSelected, boolean iValueSelected, boolean iPercentSelected) { MetricState metricState = metricStates.findMetricStateByName(metricName); if (metricState != null) { MetricAttributes metricAttributesCopy = metricState.getSelection().getAttributes().copy(); metricAttributesCopy.setITime(iTimeSelected); metricAttributesCopy.setIValue(iValueSelected); metricAttributesCopy.setIPercent(iPercentSelected); set(originalSource, metricName, metricAttributesCopy); } } /** Called from Settings */ public synchronized void set(Object originalSource, List list) { boolean changed = true; // for (int i = 0; i < metricStates.getSelections().length; i++) { // OK // if (metricStates.getSelections()[i] != newChksBoxValue[i]) { // OK // changed = true; // break; // } // } if (changed) { MetricStates metricStatesCopy = metricStates.copy(); // metricStatesCopy.setSelections(newChksBoxValue); metricStatesCopy.setSelection(list); setValueAndFireChangeEvent(originalSource, this, metricStatesCopy); } } /** Called when changing column order (old headers) */ private synchronized void setMetricOrder(Object originalSource, int from, int to, int mtype) { MetricStates metricStatesCopy = metricStates.copy(); metricStatesCopy.updateMetricOrder(from, to, mtype); setValueAndFireChangeEvent(originalSource, this, metricStatesCopy); } /** Called when changing column order (new headers) */ public synchronized void setMetricOrder( Object originalSource, String metricName, String metricRefName, boolean before) { setMetricOrder(originalSource, metricName, metricRefName, before, MET_NORMAL); } private synchronized void setMetricOrder( Object originalSource, String metricName, String metricRefName, boolean before, int mtype) { MetricStates metricStatesCopy = metricStates.copy(); metricStatesCopy.updateMetricOrder(metricName, metricRefName, before, mtype); setValueAndFireChangeEvent(originalSource, this, metricStatesCopy); } private synchronized void setSortMetric(Object originalSource, int index, int mtype) { MetricStates metricStatesCopy = metricStates.copy(); metricStatesCopy.updateSortMetric(index, mtype); setValueAndFireChangeEvent(originalSource, this, metricStatesCopy); } private void overrideMetricStates( MetricStates metricStates, List metricsSelectionList, boolean metricsReversedSort, MetricType[] metricSortByMType, List[] metricOrderLists) { // Override selection with saved metrics settings // if (metricsSelectionList != null) { // for (MetricNameSelection ms : metricsSelectionList) { // int baseIndex = findBaseIndex(ms.getName()); // if (baseIndex >= 0) { // for (int i = 0; i < 6; i++) { // metricStates.getSelections()[6 * baseIndex + i] = // ms.getExclusiveInclusive()[i]; // OK // } // } // } // } metricStates.setSelection(metricsSelectionList); // Override sort direction metricStates.setNewReverseSortDirection(metricsReversedSort); // Override sort metric (restore only MET_NORMAL) if (metricSortByMType != null) { metricStates.setNewSortMetric(metricSortByMType[MET_NORMAL]); } // Override metric order (restore only MET_NORMAL) if (metricOrderLists != null) { List newMetricOrderList = metricOrderLists[MET_NORMAL]; // MetricType[] newMetricOrderList = normalListOrder.toArray(new // MetricType[normalListOrder.size()]); metricStates.setNewMetricOrder(newMetricOrderList); } } /** Called from Import Settings */ public synchronized void set( Object originalSource, List metricsSelectionList, boolean metricsReversedSort, MetricType[] metricSortByMType, List[] metricOrderLists) { MetricStates metricStatesCopy = metricStates.copy(); overrideMetricStates( metricStatesCopy, metricsSelectionList, metricsReversedSort, metricSortByMType, metricOrderLists); setValueAndFireChangeEvent(originalSource, this, metricStatesCopy); } private void init( Object originalSource, List metricsSelectionList, boolean metricsReversedSort, MetricType[] metricSortByMType, List[] metricOrderLists) { overrideMetricStates( metricStates, metricsSelectionList, metricsReversedSort, metricSortByMType, metricOrderLists); updateBackend(); // IPC fireChangeEvent(originalSource, metricStates); } public AnMetric[] getAvailableAnMetrics() { return availableAnMetrics; } public AnMetric getAvailableAnMetric(String cmd) { for (AnMetric anMetric : availableAnMetrics) { if (anMetric.getComd().equals(cmd)) { return anMetric; } } return null; } @Override Type getType() { return AnSettingChangeEvent.Type.METRICS; } public synchronized MetricStates getMetricStates() { return metricStates; } public synchronized AnMetric[] getMetricListByMType(int mtype) { if (getMetricStates() == null) { return null; } return getMetricStates().getMetricListByMType(mtype); } public synchronized AnMetric[] getMetricListByDType(int dtype) { return getMetricListByMType(dtype2mtype(dtype)); } // Get index of sorting metric public static synchronized int getSortIndex(final AnMetric[] mlist) { for (int i = 0; i < mlist.length; i++) { if (mlist[i].isSorted()) { return i; } } return 0; } public synchronized int getSortColumnByDType(int dtype) { int mtype = dtype2mtype(dtype); return getSortIndex(mtype); } // Get index of sorting metric private int getSortIndex(final int mtype) { final AnMetric[] mlist = getMetricListByMType(mtype); return getSortIndex(mlist); } @Override Object getValue() { return metricStates; } @Override synchronized void setValue(Object newValue) { MetricStates newMetricStates = (MetricStates) newValue; metricStates = newMetricStates; updateBackend(); // IPC } public synchronized boolean isSelected(String metricName) { return getMetricStates().isSelected(metricName); } public synchronized List getMetricOrder() { List list = new ArrayList(); if (availableAnMetrics != null) { for (AnMetric anMetric : availableAnMetrics) { String name = anMetric.getComd(); MetricState metricState = metricStates.findMetricStateByName(name); if (metricState != null) { MetricNameSelection metricSetting = new MetricNameSelection(name, metricState.getSelection().copy()); list.add(metricSetting); } } } return list; } public static synchronized int getNameColumnIndex(final AnMetric[] mlist) { for (int i = 0; i < mlist.length; i++) { if (mlist[i].isNameMetric()) { return i; } } return -1; } public synchronized int getNameColumnIndexByDType(int dtype) { AnMetric[] list = getMetricListByDType(dtype); return getNameColumnIndex(list); } private int str_cmp(final String s1, final String s2) { if (s1 == null) { return s2 == null ? 0 : 1; } if (s2 == null) { return -1; } return s1.compareTo(s2); } private AnMetric[] reorder(List metricOrderTemplate, AnMetric[] mMetricList) { AnMetric[] newMMetricList = new AnMetric[mMetricList.length]; // If last entry in metricOrderTemplate is Name, remove this entry so all unmatched metrics get // added to the end of list but also to the left of Name (23332712) int lastEntryIndex = metricOrderTemplate.size() - 1; if (lastEntryIndex >= 0) { if (metricOrderTemplate.get(lastEntryIndex).getCommand().equals("name")) { metricOrderTemplate.remove(lastEntryIndex); } } int newIndex = 0; for (MetricType metricType : metricOrderTemplate) { for (int index = 0; index < mMetricList.length; index++) { if (mMetricList[index] != null) { if (mMetricList[index].getComd().equals(metricType.getCommand()) && mMetricList[index].getSubType() == metricType.getSubType()) { newMMetricList[newIndex++] = mMetricList[index]; mMetricList[index] = null; break; } } } } for (AnMetric anMetric : mMetricList) { if (anMetric != null) { newMMetricList[newIndex++] = anMetric; } } return newMMetricList; } private synchronized void updateBackend() { List sortColumnListChanged = metricStates.getChangedMetricSortColumns(); if (sortColumnListChanged.size() > 0) { metricStates.transferSortChangesToMetricStates(sortColumnListChanged); } List metricsWithSelections = new ArrayList(); List metricStatesList = getMetricStates().getMetricStateList(); if (metricStatesList != null) { for (MetricState metricState : metricStatesList) { AnMetric bm = metricState.getAnMetric(); MetricAttributes metricAttributes = metricState.getSelection().getAttributes(); if (bm.isNameMetric()) { AnMetric m = new AnMetric(bm); metricsWithSelections.add(m); m.setSubType(AnMetric.STATIC); m.set_vis_bits(false, true, false); continue; } if (bm.isStatic() && metricState.getSelection().isSelected()) { AnMetric m = new AnMetric(bm); metricsWithSelections.add(m); m.setSubType(AnMetric.STATIC); m.set_vis_bits(false, true, false); continue; } if (metricState.getSelection().isSelected() && (metricAttributes.isETime() || metricAttributes.isEValue() || metricAttributes.isEPercent())) { AnMetric m = new AnMetric(bm); metricsWithSelections.add(m); m.setSubType(AnMetric.EXCLUSIVE); m.set_vis_bits( metricAttributes.isETime(), metricAttributes.isEValue(), metricAttributes.isEPercent()); } if (metricState.getSelection().isSelected() && (metricAttributes.isITime() || metricAttributes.isIValue() || metricAttributes.isIPercent())) { AnMetric m = new AnMetric(bm); metricsWithSelections.add(m); m.setSubType(AnMetric.INCLUSIVE); m.set_vis_bits( metricAttributes.isITime(), metricAttributes.isIValue(), metricAttributes.isIPercent()); } } } boolean set_sort = false; List metricsWithSelectionsSorted = new ArrayList(); // populate sorted_mlist - start with items in the previous list AnMetric[] metrics; if (getMetricStates().getMetricListsByMType() != null) { metrics = getMetricStates().getMetricListsByMType()[MetricsSetting.MET_NORMAL].getmMetricList(); } else { metrics = getMetricListByMType(MetricsSetting.MET_NORMAL); } for (AnMetric m : metrics) { String expr_spec = m.expr_spec; m.expr_spec = null; int ind = m.indexIn(metricsWithSelections); m.expr_spec = expr_spec; if (ind >= 0) { metricsWithSelectionsSorted.add(metricsWithSelections.get(ind)); if (m.isSorted()) { metricsWithSelections.get(ind).setSorted(true); set_sort = true; } metricsWithSelections.remove(ind); } } // if the last metric in old was "name", save it for last in new if (!metricsWithSelectionsSorted.isEmpty()) { AnMetric last = metricsWithSelectionsSorted.get(metricsWithSelectionsSorted.size() - 1); if (last.isNameMetric()) { metricsWithSelections.add(last); metricsWithSelectionsSorted.remove(last); } } // add remaning items, they are newly enabled metrics metricsWithSelectionsSorted.addAll(metricsWithSelections); if (!set_sort) { metricsWithSelectionsSorted.get(0).setSorted(true); } AnMetric[] metricsWithSelectionsSortedArray = new AnMetric[metricsWithSelectionsSorted.size()]; metricsWithSelectionsSorted.toArray(metricsWithSelectionsSortedArray); // Override MET_NORMAL metric order (from init) List metricOrderTemplate = metricStates.getNewMetricOrder(); if (metricOrderTemplate != null) { metricsWithSelectionsSortedArray = reorder(metricOrderTemplate, metricsWithSelectionsSortedArray); metricStates.setNewMetricOrder(null); } // Override MET_NORMAL sort metric (from init) MetricType newSortmetric = metricStates.getNewSortMetric(); if (newSortmetric != null) { AnMetric sortMetric = null; for (AnMetric anMetric : metricsWithSelectionsSortedArray) { if (anMetric.getComd().equals(newSortmetric.getCommand()) && anMetric.getSubType() == newSortmetric.getSubType()) { sortMetric = anMetric; break; } } if (sortMetric != null) { for (AnMetric anMetric : metricsWithSelectionsSortedArray) { anMetric.setSorted(false); } sortMetric.setSorted(true); } metricStates.setNewSortMetric(null); } // Sort the metric list so excluded/included for the same metric are next to each other and // excluded is before included. // System.out.println("-----------------------------------------------"); // for (AnMetric anMetric : metricsWithSelectionsSortedArray) { // System.out.println(anMetric.getUserName() + " " + anMetric.getSubType()); // } // Sort so excluded/included for the same metric are next to each other List pairedList = new ArrayList(); int index1 = 0; while (index1 < metricsWithSelectionsSortedArray.length) { AnMetric anMetric = metricsWithSelectionsSortedArray[index1]; if (anMetric != null) { pairedList.add(anMetric); metricsWithSelectionsSortedArray[index1] = null; int index2 = index1; while (index2 < metricsWithSelectionsSortedArray.length) { if (metricsWithSelectionsSortedArray[index2] != null && metricsWithSelectionsSortedArray[index2].getComd().equals(anMetric.getComd())) { pairedList.add(metricsWithSelectionsSortedArray[index2]); metricsWithSelectionsSortedArray[index2] = null; break; } index2++; } } index1++; } pairedList.toArray(metricsWithSelectionsSortedArray); // System.out.println("----------"); // for (AnMetric anMetric : metricsWithSelectionsSortedArray) { // System.out.println(anMetric.getUserName() + " " + anMetric.getSubType()); // } // Sort so excluded is before included for (int index = 0; index < metricsWithSelectionsSortedArray.length; index++) { if (index + 1 < metricsWithSelectionsSortedArray.length) { AnMetric anMetric1 = metricsWithSelectionsSortedArray[index]; AnMetric anMetric2 = metricsWithSelectionsSortedArray[index + 1]; if (anMetric1.getComd().equals(anMetric2.getComd())) { if (anMetric1.getSubType() == 4 && anMetric2.getSubType() == 2) { metricsWithSelectionsSortedArray[index] = anMetric2; metricsWithSelectionsSortedArray[index + 1] = anMetric1; } } } } // System.out.println("----------"); // for (AnMetric anMetric : metricsWithSelectionsSortedArray) { // System.out.println(anMetric.getUserName() + " " + anMetric.getSubType()); // } // Set visible metrics and order setCurMetricsV2IPC( MET_NORMAL, metricsWithSelectionsSortedArray, AnWindow.getInstance().getSettings().getCompareModeSetting().get().value()); // IPC // Override sort direction (from init) Boolean newReverseSortDirection = metricStates.getNewReverseSortDirection(); if (newReverseSortDirection != null && newReverseSortDirection) { for (int index = 0; index < metricsWithSelectionsSortedArray.length; index++) { if (metricsWithSelectionsSortedArray[index].isSorted()) { setSort(index, MET_NORMAL, newReverseSortDirection); // IPC // System.out.println("SORT (new): " + index + " " + MET_NORMAL + " " + // metricStates.isReverseDirectionSorting()); break; } } } // Update sort column and sort direction (from clicking) if (sortColumnListChanged.size() > 0) { for (int[] sortColumnChanged : sortColumnListChanged) { setSort( sortColumnChanged[0], sortColumnChanged[1], metricStates.isReverseDirectionSorting()); // IPC // System.out.println("SORT: " + sortColumnChanged[0] + " " + // sortColumnChanged[1] + " " + metricStates.isReverseDirectionSorting()); } } // Reset and fill the cach metricStates.resetMetricListsByMType(); // IPC } public synchronized void setMetricOrderByDType( Object originalSource, int from, int to, int dtype) { int mtype = dtype2mtype(dtype); int functionsFrom = mapToFunctionsSortColumn(from, mtype); int functionsTo = mapToFunctionsSortColumn(to, mtype); setMetricOrder(originalSource, functionsFrom, functionsTo, MetricsSetting.MET_NORMAL); } private int mapToFunctionsSortColumn(int index, int mtype) { int ret = -1; if (mtype == MetricsSetting.MET_NORMAL) { return index; } AnMetric[] functionsMetricList = getMetricListByMType(MetricsSetting.MET_NORMAL); AnMetric[] metricList = getMetricListByMType(mtype); if (index < 0 || index >= metricList.length) { return -1; } String metricUserName = metricList[index].getUserName(); for (int ind = 0; ind < functionsMetricList.length; ind++) { if (metricUserName.equals(functionsMetricList[ind].getUserName())) { ret = ind; break; } } if (ret == -1) { ret = getSortColumnByDType(AnDisplay.DSP_Functions); } return ret; } public synchronized void setSortMetricByDType(Object originalSource, int index, int dtype) { int mtype = dtype2mtype(dtype); setSortMetric(this, index, mtype); } public synchronized void dumpMetricsByDType(int dtype) { int mtype = dtype2mtype(dtype); getMetricStates().dumpMetricListsByMType(mtype); } public synchronized void dump() { getMetricStates().dump(); } public static int dtype2mtype(final int dtype) { switch (dtype) { case AnDisplay.DSP_Callers: return MetricsSetting.MET_CALL; case AnDisplay.DSP_CallTree: case AnDisplay.DSP_CallFlame: return MetricsSetting.MET_CALL_AGR; case AnDisplay.DSP_SourceV2: case AnDisplay.DSP_DisassemblyV2: return MetricsSetting.MET_SRCDIS; case AnDisplay.DSP_Source: case AnDisplay.DSP_Disassembly: return MetricsSetting.MET_SRCDIS; case AnDisplay.DSP_IndexObject: return MetricsSetting.MET_INDEX; case AnDisplay.DSP_DataObjects: case AnDisplay.DSP_DataLayout: case AnDisplay.DSP_MemoryObject: return MetricsSetting.MET_DATA; case AnDisplay.DSP_IO: case AnDisplay.DSP_IOFileDescriptors: case AnDisplay.DSP_IOCallStacks: return MetricsSetting.MET_IO; case AnDisplay.DSP_Heap: return MetricsSetting.MET_HEAP; default: return MetricsSetting.MET_NORMAL; } } // Get metric label array for function list table title public synchronized MetricLabel[] getLabel( Object[][] data, Object[] total_max, int dtype, AnTable table) { final int mtype = dtype2mtype(dtype); final AnMetric[] mlist = getMetricListByMType(mtype); if (total_max == null) { total_max = AnObject.updateMaxValues(data, null); } return getLabel(data, total_max, mlist, dtype, table); } public synchronized MetricLabel[] getLabel( Object[][] data, Object[] total_max, AnMetric[] mlist, int dtype, AnTable table) { ImageIcon so_icon; AnObject max_obj = null; String name, unit; double pclock, ptotal; if ((data == null) || (total_max == null) || (mlist == null)) { return null; } // total and max are already sorted to show visible columns in order final Object[] total = (Object[]) total_max[0]; Object[] maximum = (Object[]) total_max[1]; final MetricLabel[] metricLabels = new MetricLabel[mlist.length]; try { // This loop is not reliable - it can cause different exceptions for (int i = 0; i < mlist.length; i++) { AnMetric m = mlist[i]; so_icon = (getMetricStates().isReverseDirectionSorting()) ? AnUtility.smallArrowUpIcon : AnUtility.smallArrowDownIcon; // so_icon = // (getMetricsSetting().getMetricStates().isReverseDirectionSorting()) ? // AnUtility.hollowArrowUpIcon : AnUtility.hollowArrowDownIcon; Object obj = maximum[i]; if (obj == null) { max_obj = null; so_icon = AnUtility.blankIcon; } else if (obj instanceof String) { String s = (String) obj; max_obj = new AnString(s); } else { max_obj = (AnObject) obj; } name = m.getName(); if (m.expr_spec != null) { name = name + "; (" + m.expr_spec + ")"; } // XXX Need to rewrite this code. unit = null; pclock = -1.0; if (m.is_time_val()) { if (m.isVVisible()) { unit = m.getUnit(); } if (m.isTVisible()) { int clock = m.getClock(); pclock = (clock != 0) ? 1.e-6 / clock : 0.0; } } else if (m.isTVisible() || m.isVVisible()) { unit = m.getUnit(); } // if (GUITesting.getInstance().isRunningUnderGUITesting()) { // FIXUP: to be // removed when headers are done. Causing golden files diffs... // if (unit != null && unit.length() > 0) { // unit = "(" + unit + ")"; // } // } if (m.isPVisible()) { if (total[i] == null) { ptotal = 0.0; } else if (!(total[i] instanceof AnDouble) && !(total[i] instanceof AnLong)) { // XXXX Why total[i] is AnLong for Cycles in Source/Disasm // in compare mode and AnDouble in the other cases ? ptotal = 0.0; } else { double d = ((AnObject) total[i]).doubleValue(); if (d == 0.0) { // Try to update the total value if necessary try { Object[][] tm = (Object[][]) AnWindow.getInstance().getFunctionsView().getTotalMax(); double t = ((AnObject) tm[0][i]).doubleValue(); final int mtype = dtype2mtype(dtype); if (mtype == MetricsSetting.MET_SRCDIS) { final AnMetric[] func_mlist = getMetricListByMType(dtype2mtype(AnDisplay.DSP_Functions)); for (int func_mlist_num = 0; func_mlist_num < func_mlist.length; func_mlist_num++) { int func_type = func_mlist[func_mlist_num].getType(); int srcdis_type = mlist[i].getType(); if (func_type == srcdis_type) { t = ((AnObject) tm[0][func_mlist_num]).doubleValue(); break; } } } if (d < t) { d = t; } } catch (Exception e) { // ignore it } } ptotal = (d != 0.0) ? 100.0 / d : 0.0; } } else { ptotal = -1.0; } metricLabels[i] = new MetricLabel(m, name, unit, pclock, ptotal, max_obj, so_icon); } // for (int i = 0; i < mlist.length; i++) { // if (mlist[i].isNameMetric()) { // name_col = i; // break; // } // } } catch (Exception internalErrorException) { // An internal error happened StackTraceElement[] se = internalErrorException.getStackTrace(); StringBuilder s = new StringBuilder(); s.append("*** internalErrorException ***\n"); s.append("Thread: " + Thread.currentThread().getName() + "\n"); for (int i = 0; i < se.length; i++) { s.append(se[i].toString() + "\n"); } AnLog.log(s.toString()); return null; } return metricLabels; } // Get index of sorting metric public synchronized String getSortColumnMetricDisplayName(final int mtype) { final AnMetric[] mlist = getMetricListByMType(mtype); if (mlist != null) { for (int i = 0; i < mlist.length; i++) { if (mlist[i].isSorted()) { return mlist[i].getName(); } } } return null; } // Get index of sorting metric public synchronized AnMetric getSortColumnMetric(final int mtype) { final AnMetric[] mlist = getMetricListByMType(mtype); if (mlist != null) { for (int i = 0; i < mlist.length; i++) { if (mlist[i].isSorted()) { return mlist[i]; } } } return null; } // Get index of sorting metric public synchronized void setSortColumnName(String name, final int mtype) { final AnMetric[] mlist = getMetricListByMType(mtype); for (int i = 0; i < mlist.length; i++) { if (mlist[i].getName().equals(name)) { setSortMetricByDType(this, i, mtype); } } } public static Object[] getRefMetricsV2() { synchronized (IPC.lock) { final IPC ipc = AnWindow.getInstance().IPC(); ipc.send("getRefMetricsV2"); return (Object[]) ipc.recvObject(); } } private static void sendMetricListV2(final int mtype, final AnMetric[] mlist) { final IPC ipc = AnWindow.getInstance().IPC(); final int msize = mlist.length; final int[] type = new int[msize]; final int[] subtype = new int[msize]; final boolean[] sort = new boolean[msize]; final int[] vis = new int[msize]; final String[] cmd = new String[msize]; final String[] expr_spec = new String[msize]; final String[] legend = new String[msize]; ipc.send(mtype); for (int i = 0; i < msize; i++) { AnMetric m = mlist[i]; type[i] = m.getType(); subtype[i] = m.getSubType(); sort[i] = m.isSorted(); vis[i] = m.get_vis_bits(); cmd[i] = m.getComd(); expr_spec[i] = m.expr_spec; legend[i] = m.legend; } ipc.send(type); ipc.send(subtype); ipc.send(sort); ipc.send(vis); ipc.send(cmd); ipc.send(expr_spec); ipc.send(legend); } public static void setCurMetricsV2IPC( final int mtype, final AnMetric[] mlist, final int cmp_mode) { synchronized (IPC.lock) { final IPC ipc = AnWindow.getInstance().IPC(); ipc.send("setCurMetricsV2"); ipc.send(0); ipc.send(cmp_mode); sendMetricListV2(mtype, mlist); ipc.recvVoid(); } } public static Object[] getCurMetricsV2IPC(final int mtype) { synchronized (IPC.lock) { final IPC ipc = AnWindow.getInstance().IPC(); ipc.send("getCurMetricsV2"); ipc.send(0); ipc.send(mtype); return (Object[]) ipc.recvObject(); } } /** * Send request to get Current Metrics. Non-blocking IPC call. Caller should call * ipcResult.getObjects() to get the result @Parameters: mtype - metric type * * @return IPCResult */ public static IPCResult SendRequest_getCurMetricsV2IPC(final int mtype) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getCurMetricsV2"); ipcHandle.append(0); ipcHandle.append(mtype); IPCResult ipcResult = ipcHandle.sendRequest(); // Object[] result = ipcResult.getObjects() // blocking return ipcResult; } private static void setSort(final int sort_ind, final int mtype, final boolean direction) { synchronized (IPC.lock) { AnWindow m_window = AnWindow.getInstance(); m_window.IPC().send("setSort"); m_window.IPC().send(0); m_window.IPC().send(sort_ind); m_window.IPC().send(mtype); m_window.IPC().send(direction); m_window.IPC().recvString(); // synchronize } } public synchronized void hotAction() { MetricStates metricStatesCopy = metricStates.copy(); List list = metricStatesCopy.getMetricStateList(); for (MetricState metricState : list) { metricState.getSelection().setSelected(metricState.getAnMetric().isHot()); // Make sure something is selected if (metricState.getSelection().isSelected()) { if (!metricState.getSelection().getAttributes().anySelections()) { metricState.getSelection().setAttributes(metricState.getFactory().getAttributes().copy()); } } } set(this, metricStatesCopy); } public synchronized void resetAction() { MetricStates metricStatesCopy = metricStates.copy(); List list = metricStatesCopy.getMetricStateList(); for (MetricState metricState : list) { metricState.getSelection().setSelected(metricState.getFactory().isSelected()); metricState.getSelection().setAttributes(metricState.getFactory().getAttributes().copy()); } set(this, metricStatesCopy); } public synchronized void clearAction() { MetricStates metricStatesCopy = metricStates.copy(); List list = metricStatesCopy.getMetricStateList(); for (MetricState metricState : list) { if (!metricState.getAnMetric().isNameMetric()) { metricState.getSelection().setSelected(false); } } set(this, metricStatesCopy); } public synchronized JPopupMenu addMetricsPopupMenus( JPopupMenu popup, final AnMetric anMetric, final AnTable anTable, JMenu sortByMenu) { // System.out.println(anTable.getType()); // Metric Options JLabel metricNameLabel = new JLabel(); metricNameLabel.setText(" " + AnLocale.getString("Options for " + anMetric.getUserName())); metricNameLabel.setFont(metricNameLabel.getFont().deriveFont(Font.BOLD)); metricNameLabel.setForeground(AnEnvironment.METRIC_MENU_SECTION_COLOR); popup.add(metricNameLabel); for (Component component : getMetricOptionsItems(anMetric, anTable, sortByMenu)) { popup.add(component); } // Other popup.add(new JSeparator(SwingConstants.HORIZONTAL)); JLabel otherLabel = new JLabel(" " + AnLocale.getString("Other Metric Options")); otherLabel.setFont(otherLabel.getFont().deriveFont(Font.BOLD)); otherLabel.setForeground(AnEnvironment.METRIC_MENU_SECTION_COLOR); popup.add(otherLabel); for (Component component : getOtherMetricItems(anTable)) { popup.add(component); } return popup; } private List getMetricOptionsItems( final AnMetric anMetric, final AnTable anTable, JMenu sortByMenu) { List componentList = new ArrayList(); final MetricState metricState = getMetricStates().findMetricStateByName(anMetric.getComd()); if (metricState != null) { if (!anMetric.isNameMetric() && !anMetric.isStatic()) { final MetricAttributes capableAttributes = metricState.getCapable(); final MetricSelection metricSelection = metricState.getSelection(); final MetricSelection factoryMetricSelection = metricState.getFactory(); final MetricAttributes selectedAttributes = metricSelection.getAttributes(); final JCheckBoxMenuItem exclusiveCheckBox = new IndentCheckBox(AnLocale.getString("Exclusive"), 1); final JCheckBoxMenuItem eTimeCheckBox = new IndentCheckBox(AnLocale.getString("Time"), 2); final JCheckBoxMenuItem eValueCheckBox = new IndentCheckBox(AnLocale.getString("Value"), 2); final JCheckBoxMenuItem ePercentCheckBox = new IndentCheckBox(AnLocale.getString("Percent"), 2); final JCheckBoxMenuItem inclusiveCheckBox = new IndentCheckBox(AnLocale.getString("Inclusive"), 1); final JCheckBoxMenuItem iTimeCheckBox = new IndentCheckBox(AnLocale.getString("Time"), 2); final JCheckBoxMenuItem iValueCheckBox = new IndentCheckBox(AnLocale.getString("Value"), 2); final JCheckBoxMenuItem iPercentCheckBox = new IndentCheckBox(AnLocale.getString("Percent"), 2); final JCheckBoxMenuItem timeCheckBox = new IndentCheckBox(AnLocale.getString("Time"), 1); final JCheckBoxMenuItem valueCheckBox = new IndentCheckBox(AnLocale.getString("Value"), 1); final JCheckBoxMenuItem percentCheckBox = new IndentCheckBox(AnLocale.getString("Percent"), 1); if (anTable.getAnParent().showOnlyValuesInTables() || anTable.getAnParent().showOnlyIncludedInTables() || anTable.getAnParent().showOnlyAttributedInTables()) { timeCheckBox.setSelected(selectedAttributes.isVTime()); timeCheckBox.setEnabled(capableAttributes.isVTime()); timeCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setVTime(timeCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); valueCheckBox.setSelected(selectedAttributes.isVValue()); valueCheckBox.setEnabled(capableAttributes.isVValue()); valueCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setVValue(valueCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); percentCheckBox.setSelected(selectedAttributes.isVPercent()); percentCheckBox.setEnabled(capableAttributes.isVPercent()); percentCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setVPercent(percentCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); componentList.add(timeCheckBox); componentList.add(valueCheckBox); componentList.add(percentCheckBox); } else { exclusiveCheckBox.setSelected(selectedAttributes.anyExclusiveSelections()); exclusiveCheckBox.setEnabled(capableAttributes.anyExclusiveSelections()); exclusiveCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); if (exclusiveCheckBox.isSelected()) { // Try factory first copySelectedAttributes.setETime( factoryMetricSelection.getAttributes().isETime()); copySelectedAttributes.setEValue( factoryMetricSelection.getAttributes().isEValue()); copySelectedAttributes.setEPercent( factoryMetricSelection.getAttributes().isEPercent()); if (!copySelectedAttributes.anyExclusiveSelections()) { // Set first capable if (capableAttributes.isETime()) { copySelectedAttributes.setETime(true); } else if (capableAttributes.isEValue()) { copySelectedAttributes.setEValue(true); } else if (capableAttributes.isEPercent()) { copySelectedAttributes.setEPercent(true); } } } else { // Clear all... copySelectedAttributes.setETime(false); copySelectedAttributes.setEValue(false); copySelectedAttributes.setEPercent(false); } set(this, anMetric.getComd(), copySelectedAttributes); } }); eTimeCheckBox.setSelected(selectedAttributes.isETime()); eTimeCheckBox.setEnabled(capableAttributes.isETime()); eTimeCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setETime(eTimeCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); eValueCheckBox.setSelected(selectedAttributes.isEValue()); eValueCheckBox.setEnabled(capableAttributes.isEValue()); eValueCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setEValue(eValueCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); ePercentCheckBox.setSelected(selectedAttributes.isEPercent()); ePercentCheckBox.setEnabled(capableAttributes.isEPercent()); ePercentCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setEPercent(ePercentCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); inclusiveCheckBox.setSelected(selectedAttributes.anyInclusiveSelections()); inclusiveCheckBox.setEnabled(capableAttributes.anyInclusiveSelections()); inclusiveCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); if (inclusiveCheckBox.isSelected()) { // Try factory first copySelectedAttributes.setITime( factoryMetricSelection.getAttributes().isITime()); copySelectedAttributes.setIValue( factoryMetricSelection.getAttributes().isIValue()); copySelectedAttributes.setIPercent( factoryMetricSelection.getAttributes().isIPercent()); if (!copySelectedAttributes.anyInclusiveSelections()) { // Set first capable if (capableAttributes.isITime()) { copySelectedAttributes.setITime(true); } else if (capableAttributes.isIValue()) { copySelectedAttributes.setIValue(true); } else if (capableAttributes.isIPercent()) { copySelectedAttributes.setIPercent(true); } } } else { // Clear all... copySelectedAttributes.setITime(false); copySelectedAttributes.setIValue(false); copySelectedAttributes.setIPercent(false); } set(this, anMetric.getComd(), copySelectedAttributes); } }); iTimeCheckBox.setSelected(selectedAttributes.isITime()); iTimeCheckBox.setEnabled(capableAttributes.isITime()); iTimeCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setITime(iTimeCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); iValueCheckBox.setSelected(selectedAttributes.isIValue()); iValueCheckBox.setEnabled(capableAttributes.isIValue()); iValueCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setIValue(iValueCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); iPercentCheckBox.setSelected(selectedAttributes.isIPercent()); iPercentCheckBox.setEnabled(capableAttributes.isIPercent()); iPercentCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { MetricAttributes copySelectedAttributes = selectedAttributes.copy(); copySelectedAttributes.setIPercent(iPercentCheckBox.isSelected()); set(this, anMetric.getComd(), copySelectedAttributes); } }); componentList.add(exclusiveCheckBox); componentList.add(eTimeCheckBox); componentList.add(eValueCheckBox); componentList.add(ePercentCheckBox); componentList.add(inclusiveCheckBox); componentList.add(iTimeCheckBox); componentList.add(iValueCheckBox); componentList.add(iPercentCheckBox); } AnMetric auxMetric = null; String aux = anMetric.getAux(); if (aux != null && anMetric.getComd().equals(aux)) { for (AnMetric am : availableAnMetrics) { // Look for metrcis with aux equal comd if (am.getAux() != null && am.getAux().equals(anMetric.getComd()) && !am.getComd().equals(am.getAux())) { auxMetric = am; break; } } } else if (aux != null && !anMetric.getComd().equals(aux)) { for (AnMetric am : availableAnMetrics) { // Look for metrcis with aux equal comd if (am.getComd().equals(aux)) { auxMetric = am; break; } } } if (auxMetric != null) { MetricState auxMetricState = getMetricStates().findMetricStateByName(auxMetric.getComd()); if (auxMetricState != null) { JLabel filler = new JLabel(); Dimension dim = new Dimension(5, 5); filler.setPreferredSize(dim); componentList.add(filler); final JCheckBoxMenuItem auxCheckBox = new IndentCheckBox(auxMetric.getUserName(), 1); auxCheckBox.setSelected(auxMetricState.getSelection().isSelected()); componentList.add(auxCheckBox); final AnMetric finalAuxMetric = auxMetric; auxCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { set(this, finalAuxMetric.getComd(), auxCheckBox.isSelected()); } }); } } JMenuItem removeMemyItem = new JMenuItem(AnLocale.getString("Remove This Metric")); removeMemyItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { set(this, metricState.getAnMetric().getComd(), false); } }); componentList.add(removeMemyItem); } if (sortByMenu != null) { componentList.add(sortByMenu); } List list = getMetricStates().getSelectedMetricsByMType(dtype2mtype(anTable.getType())); JMenu reorderMenu = new JMenu(AnLocale.getString("Move This Metric To")); // Before... JMenu beforeMenu = new JMenu(AnLocale.getString("Before Metric")); for (AnMetric s : list) { final AnMetric refMetric = s; JMenuItem menuItem = new JMenuItem(refMetric.getUserName()); if (s.getComd().equals(anMetric.getComd())) { menuItem.setEnabled(false); } menuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setMetricOrder(this, anMetric.getComd(), refMetric.getComd(), true, MET_NORMAL); } }); beforeMenu.add(menuItem); } reorderMenu.add(beforeMenu); // After... JMenu toAfterMenu = new JMenu(AnLocale.getString("After Metric")); for (AnMetric s : list) { final AnMetric refMetric = s; JMenuItem menuItem = new JMenuItem(refMetric.getUserName()); if (s.getComd().equals(anMetric.getComd())) { menuItem.setEnabled(false); } menuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setMetricOrder(this, anMetric.getComd(), refMetric.getComd(), false, MET_NORMAL); } }); toAfterMenu.add(menuItem); } reorderMenu.add(toAfterMenu); componentList.add(reorderMenu); } return componentList; } public synchronized List getOtherMetricItems(AnTable anTable) { List list = new ArrayList(); // Table format JMenu formatMenuItem = new JMenu(AnLocale.getString("Format")); final JCheckBoxMenuItem wrapCheckBoxMenuItem = new JCheckBoxMenuItem(AnLocale.getString("Wrap Long Metric Names in Table Headers")); wrapCheckBoxMenuItem.setSelected( AnWindow.getInstance().getSettings().getTableSettings().wrapMetricNames()); wrapCheckBoxMenuItem.setEnabled(anTable.wrapMetricNames()); wrapCheckBoxMenuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance() .getSettings() .getTableSettings() .setWrapMetricNames(MetricsSetting.this, wrapCheckBoxMenuItem.isSelected()); } }); formatMenuItem.add(wrapCheckBoxMenuItem); list.add(formatMenuItem); // Compare mode CompareModeSetting.CompareMode mode = AnWindow.getInstance().getSettings().getCompareModeSetting().get(); JMenu compareMenuItem = new JMenu(AnLocale.getString("Compare Mode")); if (mode != CompareModeSetting.CompareMode.CMP_DISABLE) { JRadioButtonMenuItem absoluteRadioButtonMenuItem = new JRadioButtonMenuItem(AnLocale.getString("Absolute")); JRadioButtonMenuItem deltaRadioButtonMenuItem = new JRadioButtonMenuItem(AnLocale.getString("Delta")); JRadioButtonMenuItem ratioRadioButtonMenuItem = new JRadioButtonMenuItem(AnLocale.getString("Ratio")); absoluteRadioButtonMenuItem.setSelected(mode == CompareModeSetting.CompareMode.CMP_ENABLE); deltaRadioButtonMenuItem.setSelected(mode == CompareModeSetting.CompareMode.CMP_DELTA); ratioRadioButtonMenuItem.setSelected(mode == CompareModeSetting.CompareMode.CMP_RATIO); absoluteRadioButtonMenuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance() .getSettings() .getCompareModeSetting() .set(this, CompareModeSetting.CompareMode.CMP_ENABLE); } }); deltaRadioButtonMenuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance() .getSettings() .getCompareModeSetting() .set(this, CompareModeSetting.CompareMode.CMP_DELTA); } }); ratioRadioButtonMenuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance() .getSettings() .getCompareModeSetting() .set(this, CompareModeSetting.CompareMode.CMP_RATIO); } }); compareMenuItem.add(absoluteRadioButtonMenuItem); compareMenuItem.add(deltaRadioButtonMenuItem); compareMenuItem.add(ratioRadioButtonMenuItem); formatMenuItem.add(compareMenuItem); } // More metrics JMenu moreMetricsMenuItem = new JMenu(AnLocale.getString("More Metrics")); addMetricMenuSelector(moreMetricsMenuItem, anTable.getType(), true); list.add(moreMetricsMenuItem); // Settings for (JComponent component : createMetricSettingsSelector()) { list.add(component); } return list; } public synchronized JPopupMenu addMetricsPopupSelector( JPopupMenu popup, int dtype, boolean addMetricActions) { List list = createMetricsSelector(dtype, addMetricActions); for (JComponent component : list) { popup.add(component); } // popup.add(new JSeparator(SwingConstants.HORIZONTAL)); // for (JComponent component : createMetricSettingsSelector()) { // popup.add(component); // } return popup; } public synchronized JMenu addMetricMenuSelector(JMenu menu, int dtype, boolean addMetricActions) { for (JComponent component : createMetricsSelector(dtype, addMetricActions)) { menu.add(component); } return menu; } public synchronized List createMetricSettingsSelector() { List componentList = new ArrayList(); componentList.add(AnWindow.getInstance().getMetricsSettingsAction().getMenuItem()); return componentList; } private List createMetricsSelector(int dtype, boolean addMetricActions) { List componentList = new ArrayList(); List metricStateList = AnWindow.getInstance() .getSettings() .getMetricsSetting() .getMetricStates() .getMetricStateList(); boolean anyHot = false; String listName = null; int numberAdded = 0; int metricListID = AnWindow.getInstance().getSettings().getViewsSetting().getViewMetricListIdMapping(dtype); // System.out.println("------------------------- " + dtype + " " + metricListID); for (MetricState metricState : metricStateList) { if (metricState.getAnMetric().isNameMetric()) { continue; } if (metricState.getAnMetric().isStatic() && dtype2mtype(dtype) != MET_NORMAL) { continue; } if (metricListID != MetricNode.ALL_LIST_ID && metricListID != metricState.getListId()) { continue; } String ln = metricState.getListName(); if (ln != null && !ln.equals(listName)) { // System.out.println(ln); if (listName != null) { JLabel filler = new JLabel(" "); filler.setPreferredSize(new Dimension(4, 4)); componentList.add(filler); // JSeparator separator = new JSeparator(SwingConstants.HORIZONTAL); // // separator.setForeground(AnEnvironment.METRIC_SELCTOR_MENU_SEPARATOR_COLOR); // separator.setBorder(null); // separator.setPreferredSize(new // Dimension(separator.getPreferredSize().width, 1)); // componentList.add(separator); } JLabel label = new JLabel(" " + ln); label = new JLabel(" " + ln); label.setFont(label.getFont().deriveFont(Font.BOLD)); label.setForeground(AnEnvironment.METRIC_MENU_SECTION_COLOR); componentList.add(label); listName = ln; } MetricCheckBox checkBox = new MetricCheckBox( metricState.getAnMetric(), metricState.getSelection().isSelected(), metricState.getAnMetric().isHot() ? AnUtility.hot_icon : null); componentList.add(checkBox); if (metricState.getAnMetric().isHot()) { anyHot = true; } numberAdded++; } if (numberAdded > 0) { if (addMetricActions) { componentList.add(new JSeparator(SwingConstants.HORIZONTAL)); JMenuItem settingsItem; settingsItem = new MetricMenuItem(AnLocale.getString("Select Hot Metrics"), AnUtility.hot_icon); settingsItem.setEnabled(anyHot); settingsItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().getSettings().getMetricsSetting().hotAction(); } }); componentList.add(settingsItem); settingsItem = new JMenuItem(AnLocale.getString("Reset All Metrics")); settingsItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().getSettings().getMetricsSetting().resetAction(); } }); componentList.add(settingsItem); settingsItem = new JMenuItem(AnLocale.getString("Remove All Metrics")); settingsItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().getSettings().getMetricsSetting().clearAction(); } }); componentList.add(settingsItem); } } else { JLabel label = new JLabel(" " + AnLocale.getString("No metrics available for this view")); // label.setIcon(AnUtility.blankIcon); // label.setFont(label.getFont().deriveFont(Font.BOLD)); // label.setForeground(AnEnvironment.METRIC_SELCTOR_MENU_GROUP_COLOR); componentList.add(label); } return componentList; } public synchronized List createTableColumnMenuItems(AnTable table) { int dtype = table.getType(); int mtype = dtype2mtype(dtype); List anMetricList = metricStates.getAnMetricsByMTypeTrimmed(mtype); List componentList = new ArrayList(); for (AnMetric anMetric : anMetricList) { JMenu metricMenu = new JMenu(anMetric.getUserName()); JPopupMenu popupMenu = new JPopupMenu(); addMetricsPopupMenus(popupMenu, anMetric, table, null); List metricOptionList = getMetricOptionsItems(anMetric, table, null); for (Component comp : metricOptionList) { metricMenu.add(comp); } componentList.add(metricMenu); } return componentList; } private static class IndentCheckBox extends JCheckBoxMenuItem { public IndentCheckBox(String text, int indent) { this.setText(text); setBorder(BorderFactory.createMatteBorder(1, 1 + 16 * indent, 1, 1, getBackground())); } } public static class MetricCheckBox extends JCheckBoxMenuItem { private ImageIcon icon; private AnMetric anMetric; public MetricCheckBox(final AnMetric anMetric, boolean selected, ImageIcon icon) { this.setText(anMetric.getUserName()); this.anMetric = anMetric; this.icon = icon; setBorder(BorderFactory.createMatteBorder(1, 16, 1, 1, getBackground())); setSelected(selected); addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance() .getSettings() .getMetricsSetting() .set(MetricCheckBox.this, anMetric.getComd(), isSelected()); } }); } @Override public void paint(Graphics g) { super.paint(g); // To change body of generated methods, choose Tools | Templates. if (icon != null) { g.drawImage(icon.getImage(), 4, 3, this); } } /** * @return the anMetric */ public AnMetric getAnMetric() { return anMetric; } } private static class MetricMenuItem extends JMenuItem { private ImageIcon icon; public MetricMenuItem(String text, ImageIcon icon) { this.setText(text); this.icon = icon; setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, getBackground())); } @Override public void paint(Graphics g) { super.paint(g); // To change body of generated methods, choose Tools | Templates. if (icon != null) { g.drawImage(icon.getImage(), 4, 4, this); } } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/MMetric.java0000644000175000017500000000600014517772113017774 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnMetric; public class MMetric { private AnMetric[] mMetricList; private int sortIndex; private boolean reverseSortDirection; public MMetric(AnMetric[] mMetricList, boolean reverseSortDirection) { this.mMetricList = mMetricList; this.reverseSortDirection = reverseSortDirection; refreshStates(); } private void refreshStates() { int index = 0; for (AnMetric anMetric : mMetricList) { if (anMetric.isSorted()) { sortIndex = index; break; } index++; if (index >= mMetricList.length) { mMetricList[0].setSorted(true); sortIndex = 0; } } } public MMetric copy() { AnMetric[] copyMMetricList = new AnMetric[getmMetricList().length]; int i = 0; for (AnMetric anMetric : getmMetricList()) { copyMMetricList[i++] = anMetric; } MMetric copyMMetric = new MMetric(copyMMetricList, isReverseSortDirection()); return copyMMetric; } public AnMetric[] getmMetricList() { return mMetricList; } public void setmMetricList(AnMetric[] mMetricList) { this.mMetricList = mMetricList; } public int getIndex(AnMetric am) { int index = 0; for (AnMetric anMetric : mMetricList) { if (anMetric == am) { return index; } index++; } return -1; } public int getSortIndex() { return sortIndex; } public AnMetric getSortMetric() { return mMetricList[sortIndex]; } public boolean isReverseSortDirection() { return reverseSortDirection; } public void setSortIndex(int sortIndex) { if (sortIndex >= 0 && sortIndex < mMetricList.length) { this.sortIndex = sortIndex; } } /** * @param reverseSortDirection the reverseSortDirection to set */ public void setReverseSortDirection(boolean reverseSortDirection) { this.reverseSortDirection = reverseSortDirection; } protected void dump() { if (mMetricList != null) { int n = 0; for (AnMetric anMetric : mMetricList) { System.out.print(" " + n++ + ": " + anMetric.getName()); if (anMetric.isSorted()) { System.out.print(" <== " + "SORT"); } System.out.println(); } } System.out.println(" sortIndex: " + sortIndex); System.out.println(" reverseSortDirection: " + reverseSortDirection); } } gprofng-gui-1.0/org/gprofng/mpmt/settings/TimelineSetting.java0000644000175000017500000005242114517772113021550 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.experiment_props.DataDescriptor; import org.gprofng.mpmt.experiment_props.ExperimentProperties; import org.gprofng.mpmt.experiment_props.Experiments; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; import org.gprofng.mpmt.settings.Settings.TLStack_align; import org.gprofng.mpmt.timeline2.TimelineDraw; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; public class TimelineSetting extends Setting { public class EntityProp { public final int prop_id; // PROP_* value public final String prop_name; // PROP_* name public final String prop_uname; // user name public final String prop_cmd; // .er.rc command public EntityProp(int id, String name, String uname, String cmd) { prop_id = id; prop_name = name; prop_uname = uname; prop_cmd = cmd; } } private static final String default_prop_name = "THRID"; // Default // FIXUP: UGLY!!!! private List tl_entity_props = new ArrayList(); private List settings; private long tldata_hidden_bitmask; // states of checkboxes private List tldata_unames; // names shown for checkboxes private List tldata_cnames; // .er.rc tldata cmds for checkboxes private Set tldata_unused_hidden; // not-yet-used .er.rc fields private int tldata_names_version; // tracks changes to timeline Data option updates private String tldata_cmd; // .er.rc command line, not including "tldata" private static String tldata_cmd_default = "all"; public TimelineSetting() { // XXX: why are PROP_* values hard coded here? // tl_entity_prop_* should be set only // once per gp-display-text connect List tl_entity_prop_ids = Arrays.asList( Settings.PROP_NONE, Settings.PROP_NONE, Settings.PROP_NONE, Settings.PROP_NONE); // dbe property ID for above entities List tl_entity_prop_names = Arrays.asList("LWPID", "THRID", "CPUID", "EXPID"); // names for above entities (???) List tl_entity_prop_unames = Arrays.asList("LWP", "Thread", "CPU", "Process"); // user-visible names for above entities List tl_entity_prop_cmd_names = Arrays.asList( "lwp", "thread", "cpu", "experiment"); // .er.rc command name for above entities for (int ii = 0; ii < tl_entity_prop_ids.size(); ii++) { tl_entity_props.add( new EntityProp( tl_entity_prop_ids.get(ii), tl_entity_prop_names.get(ii), tl_entity_prop_unames.get(ii), tl_entity_prop_cmd_names.get(ii))); } tldata_hidden_bitmask = 0; tldata_unames = new ArrayList(); tldata_cnames = new ArrayList(); tldata_unused_hidden = new HashSet(); tldata_names_version = 0; tldata_cmd = tldata_cmd_default; } private void init(Object originalSource, List settings) { // if called externally, add code to update tldata_* state this.settings = settings; fireChangeEvent(originalSource, settings); } /** Called from Settings Save */ public void set(Object originalSource, List newSettings, boolean changed) { if (changed) { setValueAndFireChangeEvent(originalSource, this, newSettings); } } /* * Called from import settings */ public void set( Object originalSource, String groupDataByButtonName, int stackAlignNo, int stackDepth, int stackFramePixels, boolean showEventStates, boolean showEventDensity) { List settingsCopy = (List) AnWindow.getInstance().getSettings().getTimelineSettings(true); // setProps(tl_entprops); // tldata_unused_hidden = parseTLDataCmd(in_tldata_cmd); // resetTLDataNames(); // relies on tldata_unused_hidden // Find the button number int groupDataByButtonNum = 1; // FIXUP: why 1? for (int i = 0; i < tl_entity_props.size(); i++) { if (tl_entity_props.get(i).prop_name.equalsIgnoreCase(groupDataByButtonName)) { groupDataByButtonNum = i; break; } } // Construct the StackAlign Settings.TLStack_align stackAlign = Settings.TLStack_align.find(stackAlignNo); settingsCopy.set(0, groupDataByButtonName); settingsCopy.set(1, groupDataByButtonNum); settingsCopy.set(2, stackAlign); settingsCopy.set(3, stackDepth); settingsCopy.set(4, Long.valueOf(getTLDataHiddenMask())); settingsCopy.set(5, getTLDataCNames()); settingsCopy.set(6, getTLDataUNames()); settingsCopy.set(7, Integer.valueOf(getTLDataNamesVersion())); settingsCopy.set(8, showEventStates); settingsCopy.set(9, showEventDensity); settingsCopy.set(10, stackFramePixels); settingsCopy.set(11, tldata_cmd); set(originalSource, settingsCopy, true); } /** Called when new experiment has been loaded (after processing .er.rc) */ private void setProps(Object[] tl_entprops) { int[] tl_entprop_ids; String[] tl_entprop_names; String[] tl_entprop_unames; String[] tl_entprop_cnames; tl_entprop_ids = (int[]) tl_entprops[0]; tl_entprop_names = (String[]) tl_entprops[1]; tl_entprop_unames = (String[]) tl_entprops[2]; tl_entprop_cnames = (String[]) tl_entprops[3]; // first item in list is "unknown" propId==0; skip it tl_entity_props = new ArrayList(); for (int i = 1; tl_entprop_ids != null && i < tl_entprop_ids.length; i++) { int thisId = tl_entprop_ids[i]; String thisName = tl_entprop_names[i]; String thisUname = tl_entprop_unames[i]; String thisCname = tl_entprop_cnames[i]; tl_entity_props.add(new EntityProp(thisId, thisName, thisUname, thisCname)); } } /** Called once right after new experiment has been loaded (after processing .er.rc) */ private boolean resetTLDataNames() { Experiments experiments = AnWindow.getInstance().getExperimentProperties(); // determine unique "data types" shown in Presentation Timeline Tab final HashSet uniqueNames = new HashSet(); final ArrayList dataCNames = new ArrayList(); final ArrayList dataUNames = new ArrayList(); for (ExperimentProperties exp : experiments.getAllExperimentProperties()) { for (DataDescriptor dataD : exp.getTstampDataDescriptors()) { int auxmax = dataD.getAuxCount(); if (auxmax == 0) { auxmax = 1; // loop only once } for (int aux = 0; aux < auxmax; aux++) { String cname_tmp = dataD.getErRcTLDataCmdName(aux); String uname_tmp = dataD.getLongUName(aux); if (cname_tmp == null || cname_tmp.isEmpty()) { continue; } if (uname_tmp == null || uname_tmp.isEmpty()) { continue; } if (uniqueNames.add(uname_tmp)) { dataCNames.add(cname_tmp); dataUNames.add(uname_tmp); } } } } boolean names_changed = resetTLDataNames(dataCNames, dataUNames); return names_changed; } private boolean resetTLDataNames( final ArrayList newCmdNames, final ArrayList newUserNames) { boolean namesUpdated = false; { if (tldata_cnames.size() != newCmdNames.size()) { namesUpdated = true; } else { // old and new sizes are the same, maybe we have a perfect match for (int ii = 0; ii < newCmdNames.size(); ii++) { String newname = newCmdNames.get(ii); String oldname = tldata_cnames.get(ii); if (!newname.equals(oldname)) { // something changed namesUpdated = true; break; } } } final boolean bitmaskNeedsUpdate; if (tldata_hidden_bitmask == 0 && tldata_unused_hidden.isEmpty()) { bitmaskNeedsUpdate = false; } else if (!namesUpdated) { bitmaskNeedsUpdate = false; } else { bitmaskNeedsUpdate = true; } if (bitmaskNeedsUpdate) { // update tldata_unused_cnames in include all disabled items for (int jj = 0; jj < tldata_cnames.size(); jj++) { String currCmd = tldata_cnames.get(jj); long currBit = (tldata_hidden_bitmask & (1L << jj)); if (currBit != 0) { tldata_unused_hidden.add(currCmd); } } // scan new names to see which should be disabled long new_hidden_mask = 0; for (int ii = 0; ii < newCmdNames.size(); ii++) { String newCname = newCmdNames.get(ii); for (String disabledName : tldata_unused_hidden) { if (newCname.equals(disabledName)) { new_hidden_mask |= (1L << ii); tldata_unused_hidden.remove(disabledName); break; } } } tldata_hidden_bitmask = new_hidden_mask; } if (namesUpdated) { tldata_cnames = Collections.unmodifiableList(newCmdNames); tldata_unames = Collections.unmodifiableList(newUserNames); tldata_names_version++; } if (namesUpdated || bitmaskNeedsUpdate) { updateTLDataCmd(tldata_hidden_bitmask); } } return namesUpdated; } private static Set parseTLDataCmd(String new_tldata_cmd) { // == text that follows the .er.rc "tldata" command Set cnamesToHide = new HashSet(); { if (new_tldata_cmd == null || new_tldata_cmd.length() == 0) { return cnamesToHide; } new_tldata_cmd = new_tldata_cmd.toLowerCase(); String mcmds[] = new_tldata_cmd.split(":"); if (mcmds == null) { return cnamesToHide; } for (int ii = 0; ii < mcmds.length; ii++) { String this_cmd = mcmds[ii]; if (this_cmd.equals(Settings.TLData_type.TL_ALL.getTLDataBaseCmd())) { // nothing to do (only saving "!" items in list) } else if (this_cmd.startsWith("!")) { this_cmd = this_cmd.substring(1); // remove ! if (this_cmd.length() > 0) { cnamesToHide.add(this_cmd); } } } } return cnamesToHide; } public long setTLDataVisibility_edt(Set allCmds, Set disabledCmds) { long specified_mask = 0; long new_mask = 0; int num_disabled = 0; for (int jj = 0; jj < tldata_cnames.size(); jj++) { String currCmd = tldata_cnames.get(jj); if (allCmds.contains(currCmd)) { specified_mask |= (1L << jj); } } for (int jj = 0; jj < tldata_cnames.size(); jj++) { String currCmd = tldata_cnames.get(jj); if (disabledCmds.contains(currCmd)) { new_mask |= (1L << jj); num_disabled++; } } if (num_disabled != disabledCmds.size()) { int ii = 0; // weird! } long original_bitmask = tldata_hidden_bitmask; tldata_hidden_bitmask &= ~specified_mask; tldata_hidden_bitmask |= new_mask; if (original_bitmask != tldata_hidden_bitmask) { updateTLDataCmd(tldata_hidden_bitmask); } return tldata_hidden_bitmask; } public long getTLDataHiddenMask() { return tldata_hidden_bitmask; } public void setTLDataHiddenMask(long newMask) { long old_mask = tldata_hidden_bitmask; tldata_hidden_bitmask = newMask; if (old_mask != newMask) { updateTLDataCmd(tldata_hidden_bitmask); } } public int getTLDataNamesVersion() { return tldata_names_version; } public List getTLDataUNames() { return tldata_unames; } public List getTLDataCNames() { return tldata_cnames; } // only called when there is a change: private String updateTLDataCmd(long hidden_mask) { // update tldata_cmd String new_tldata_cmd = tldata_cmd_default; for (int ii = 0; ii < tldata_cnames.size(); ii++) { long disable = ((1L << ii) & hidden_mask); if (disable != 0) { new_tldata_cmd += ":!" + tldata_cnames.get(ii); } } tldata_cmd = new_tldata_cmd; return tldata_cmd; } /* * Called when new experiment has been loaded (after processing .er.rc) */ public void init( Object originalSource, Object[] tl_entprops, String in_tldata_cmd, String groupDataByButtonName, int stackAlignNo, int stackDepth, int stackFramePixels, boolean showEventStates, boolean showEventDensity) { List settingsCopy = (List) AnWindow.getInstance().getSettings().getTimelineSettings(true); setProps(tl_entprops); tldata_unused_hidden = parseTLDataCmd(in_tldata_cmd); resetTLDataNames(); // relies on tldata_unused_hidden // Find the button number int groupDataByButtonNum = 1; // FIXUP: why 1? for (int i = 0; i < tl_entity_props.size(); i++) { if (tl_entity_props.get(i).prop_name.equalsIgnoreCase(groupDataByButtonName)) { groupDataByButtonNum = i; break; } } // Construct the StackAlign Settings.TLStack_align stackAlign = Settings.TLStack_align.find(stackAlignNo); settingsCopy.set(0, groupDataByButtonName); settingsCopy.set(1, groupDataByButtonNum); settingsCopy.set(2, stackAlign); settingsCopy.set(3, stackDepth); settingsCopy.set(4, Long.valueOf(getTLDataHiddenMask())); settingsCopy.set(5, getTLDataCNames()); settingsCopy.set(6, getTLDataUNames()); settingsCopy.set(7, Integer.valueOf(getTLDataNamesVersion())); settingsCopy.set(8, showEventStates); settingsCopy.set(9, showEventDensity); settingsCopy.set(10, stackFramePixels); settingsCopy.set(11, tldata_cmd); init(originalSource, settingsCopy); } private List getSettings() { return settings; } @Override Type getType() { return AnSettingChangeEvent.Type.TIMELINE; } @Override Object getValue() { return settings; } @Override void setValue(Object newValue) { // might not be EDT!! this.settings = (List) newValue; } public TLStack_align getStack_align() { if (settings != null) { return (TLStack_align) settings.get(2); } else { return getDefaultStack_align(); } } public int getTLStackDepth() { if (settings != null) { int stackDepth = (Integer) settings.get(3); return stackDepth; } else { return getDefaultStackDepth(); } } public int getTLStackFramePixels() { if (settings != null) { int stackDepth = (Integer) settings.get(10); return stackDepth; } else { return getDefaultStackFramePixels(); } } public int getStackAlign() { int value = getStack_align().getValue(); return value; } public boolean getShowEventStates() { if (settings != null) { Boolean show = (Boolean) settings.get(8); return show; } else { return getTimelineShowEventStatesDefault(); } } public boolean getShowEventDensity() { if (settings != null) { Boolean show = (Boolean) settings.get(9); return show; } else { return getTimelineShowEventDensityDefault(); } } public static int getDefaultStackDepth() { return TimelineDraw.TIMELINE_DEFAULT_VZOOM_LEVEL; // Default } public static int getDefaultStackFramePixels() { return Settings.TIMELINE_DEFAULT_STACK_FRAME_PIXELS; // Default } public static boolean getTimelineShowEventStatesDefault() { return true; // Default } public static boolean getTimelineShowEventDensityDefault() { return false; // Default } public void setTLStackDepth(Object originalSource, int stackDepth) { List settingsCopy = (List) AnWindow.getInstance().getSettings().getTimelineSettings(true); if (stackDepth > TimelineDraw.TIMELINE_MAX_VZOOM_LEVEL) { stackDepth = TimelineDraw.TIMELINE_MAX_VZOOM_LEVEL; } boolean changed = false; if ((Integer) (settingsCopy.get(3)) != stackDepth) { changed = true; } settingsCopy.set(3, stackDepth); set(originalSource, settingsCopy, changed); } public void setTLStackFramePixels(Object originalSource, int stackFramePixels) { List settingsCopy = (List) AnWindow.getInstance().getSettings().getTimelineSettings(true); boolean changed = false; if ((Integer) (settingsCopy.get(10)) != stackFramePixels) { changed = true; } settingsCopy.set(10, stackFramePixels); set(originalSource, settingsCopy, changed); } public void setTLGroupDataBySelectedButtonIndex( Object originalSource, int new_tl_entity_button_num) { List settingsCopy = (List) AnWindow.getInstance().getSettings().getTimelineSettings(true); if (new_tl_entity_button_num < 0 || new_tl_entity_button_num >= tl_entity_props.size()) { return; // weird } String tl_entity_prop_name = tl_entity_props.get(new_tl_entity_button_num).prop_name; boolean changed = false; String oldName = (String) (settingsCopy.get(0)); if (!(tl_entity_prop_name.equalsIgnoreCase(oldName))) { changed = true; } else if ((Integer) (settingsCopy.get(1)) != new_tl_entity_button_num) { changed = true; } settingsCopy.set(0, tl_entity_prop_name); settingsCopy.set(1, new_tl_entity_button_num); set(originalSource, settingsCopy, changed); } public static String getDefaultGroupDataByButtonName() { return default_prop_name; } public static String getDefaultTLDataCmd() { return tldata_cmd_default; } public static int getDefaultStackAlign() { return getDefaultStack_align().getValue(); } private static TLStack_align getDefaultStack_align() { return TLStack_align.TLSTACK_ALIGN_ROOT; } public String getGroupDataByButtonName() { if (settings != null) { return (String) (settings.get(0)); } else { return getDefaultGroupDataByButtonName(); } } public String getTLDataCmd() { if (settings != null) { return tldata_cmd; // tldata_cmd gets updated dynamically... // YXXX FIXUP, not sure what to do - should we update tldata_cmd whenever an TL event updates // settings.get(11)? // String tmp_tldata_cmd = (String)settings.get(11); // return tmp_tldata_cmd; } else { return getDefaultTLDataCmd(); } } public String getFullTLDataCmd() { // include old settings previously seen, but not applicable to this experiment String fullCmd = tldata_cmd; for (String unused_cname : tldata_unused_hidden) { fullCmd += ":!" + unused_cname; } return fullCmd; } public int getTl_entity_selected_btn() { if (settings != null) { return (Integer) (settings.get(1)); } else { return 1; // Default // FIXUP: UGLY!!!! } } public EntityProp getTl_entity_prop(int buttonIdx) { if (buttonIdx < 0 || buttonIdx >= tl_entity_props.size()) { return null; // weird } return tl_entity_props.get(buttonIdx); } public static Object[] ipcGetTLValue() { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("getTLValue"); window.IPC().send(0); return (Object[]) window.IPC().recvObject(); } } /** * Send request to get TLValue. Non-blocking IPC call. Caller should call ipcResult.getObjects() * to get the result * * @return IPCResult */ public static IPCResult ipcGetTLValueRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getTLValue"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // Object[] result = ipcResult.getObjects() // blocking return ipcResult; } // YXXX TBR? Remember to clean back-end. private static void ipcSetTLValue( final String tldata_cmd, int entity_prop_id, int align, int depth) { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("setTLValue"); window.IPC().send(0); window.IPC().send(tldata_cmd); window.IPC().send(entity_prop_id); window.IPC().send(align); window.IPC().send(depth); window.IPC().recvString(); // synchronize } } public static Object[] ipcGetEntityProps() { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("getEntityProps"); window.IPC().send(0); return (Object[]) window.IPC().recvObject(); } } /** * Send request to get EntityProps. Non-blocking IPC call. Caller should call * ipcResult.getObjects() to get the result * * @return IPCResult */ public static IPCResult ipcGetEntityPropsRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getEntityProps"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // Object[] result = ipcResult.getObjects() // blocking return ipcResult; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/ImportSettingsDialog.java0000644000175000017500000001326414517772113022561 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnDialog2; import java.awt.Frame; import java.util.List; public class ImportSettingsDialog extends AnDialog2 { ImportSettingsPanel importSettingsPanel; public ImportSettingsDialog(Frame owner) { super(owner, owner, AnLocale.getString("Import Settings")); importSettingsPanel = new ImportSettingsPanel(this); setCustomPanel(importSettingsPanel); // setHelpTag(AnVariable.HELP_ImportSettings); getOKButton().setText(AnLocale.getString("Import")); getOKButton().setToolTipText(AnLocale.getString("Import selected settings")); } @Override protected void setStatus(Status status) { super.setStatus(status); if (status == Status.OK) { UserPref existingUserpref = UserPref.getInstance(); UserPref userPref = importSettingsPanel.getUserPref(); Settings settings = AnWindow.getInstance().getSettings(); List whatList = importSettingsPanel.getWhat(); if (whatList.contains(UserPref.What.VIEWS)) { AnWindow.getInstance() .getSettings() .getViewsSetting() .set( this, userPref.getViewPanelOrder(), userPref.getMachineModel(), userPref.getCustomIndexObjects(), userPref.getCustomMemoryObjects()); } if (whatList.contains(UserPref.What.METRICS)) { AnWindow.getInstance() .getSettings() .getMetricsSetting() .set( this, userPref.getMetricSelectionList(), userPref.getMetricReversedSort(), userPref.getMetricSortByMTypeList(), userPref.getMetricOrderLists()); } if (whatList.contains(UserPref.What.TIMELINE)) { AnWindow.getInstance() .getSettings() .getTimelineSetting() .set( this, userPref.getTimelineGroupDataByButtonName(), userPref.getTimelineStackAlign(), userPref.getTimelineStackDepth(), userPref.getTimelineStackFramePixels(), userPref.getTimelineShowEventStates(), userPref.getTimelineShowEventDensity()); } if (whatList.contains(UserPref.What.SOURCEDISASSEMBLY)) { settings.getSourceDisassemblySetting().set(this, userPref.getSourceDisassemblySettings()); } if (whatList.contains(UserPref.What.CALLTREE)) { settings.getCallTreeSetting().setThreshold(this, userPref.getCallStackThreshold()); } if (whatList.contains(UserPref.What.FORMATS)) { settings .getViewModeSetting() .set(this, ViewModeSetting.ViewMode.fromValue(userPref.getFormatsViewMode())); settings .getFormatSetting() .set( this, FormatSetting.Style.fromValue(userPref.getFormatsStyle()), userPref.getFormatsAppendSoName()); settings .getCompareModeSetting() .set(this, CompareModeSetting.CompareMode.fromValue(userPref.getFormatsCompareMode())); settings.getTableSettings().setWrapMetricNames(this, userPref.wrapMetricNamesInTables()); } if (whatList.contains(UserPref.What.SEARCHPATH)) { settings .getSearchPathSetting() .set( this, userPref.getSearchPath().toArray(new String[userPref.getSearchPath().size()])); } if (whatList.contains(UserPref.What.PATHMAP)) { settings.getPathMapSetting().set(this, userPref.getPathmap()); } if (whatList.contains(UserPref.What.FUNCTIONCOLORS)) { AnWindow.getInstance() .getColorChooser() .getColorMap() .initRules(userPref.getActiveColorRules(), true); } if (whatList.contains(UserPref.What.LIBRARYVISIBILITY)) { settings .getLibraryVisibilitySetting() .setFromStrings(this, userPref.getLibraryVisibilitySettings()); AnWindow.getInstance() .getLibraryVisibilityDialog() .initStates( userPref.getLibraryVisibilityJava(), userPref.getLibraryVisibilitySettings(), userPref.getLibraryVisibilityIncludePickList(), userPref.getLibraryVisibilityIncludeFilter(), userPref.getLibraryVisibilityExcludePickList(), userPref.getCurrenLibraryVisibilityExcludeFilter()); } if (whatList.contains(UserPref.What.MISC)) { existingUserpref.setFindPickList(userPref.getFindPickList()); AnWindow.getInstance() .getToolBarPanel() .getFindTextPanel() .initializeFindTexts(userPref.getFindPickList(), null); // Find text } // Save configuration file path existingUserpref.setLastExportImportConfPath(importSettingsPanel.getConfigurationPath()); } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricAttributes.java0000644000175000017500000000737414517772113021745 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; public class MetricAttributes { private boolean eTime; private boolean eValue; private boolean ePercent; private boolean iTime; private boolean iValue; private boolean iPercent; public MetricAttributes( boolean eTime, boolean eValue, boolean ePercent, boolean iTime, boolean iValue, boolean iPercent) { this.eTime = eTime; this.eValue = eValue; this.ePercent = ePercent; this.iTime = iTime; this.iValue = iValue; this.iPercent = iPercent; } public boolean isETime() { return eTime; } public void setETime(boolean eTime) { this.eTime = eTime; } public boolean isEValue() { return eValue; } /** * @param eValue the eValue to set */ public void setEValue(boolean eValue) { this.eValue = eValue; } public boolean isEPercent() { return ePercent; } public void setEPercent(boolean ePercent) { this.ePercent = ePercent; } public boolean isITime() { return iTime; } public void setITime(boolean iTime) { this.iTime = iTime; } public boolean isIValue() { return iValue; } public void setIValue(boolean iValue) { this.iValue = iValue; } public boolean isIPercent() { return iPercent; } public void setIPercent(boolean iPercent) { this.iPercent = iPercent; } public boolean isVTime() { if (eTime || eValue || ePercent) { return eTime; } else { return iTime; } } public void setVTime(boolean time) { if (eTime || eValue || ePercent) { eTime = time; } else { iTime = time; } } public boolean isVValue() { if (eTime || eValue || ePercent) { return eValue; } else { return iValue; } } public void setVValue(boolean value) { if (eTime || eValue || ePercent) { eValue = value; } else { iValue = value; } } public boolean isVPercent() { if (eTime || eValue || ePercent) { return ePercent; } else { return iPercent; } } public void setVPercent(boolean percent) { if (eTime || eValue || ePercent) { ePercent = percent; } else { iPercent = percent; } } /** * @return deep copy */ public MetricAttributes copy() { return new MetricAttributes(eTime, eValue, ePercent, iTime, iValue, iPercent); } @Override public boolean equals(Object obj) { if (obj instanceof MetricAttributes) { MetricAttributes ma = (MetricAttributes) obj; return ma.isETime() == eTime && ma.isEValue() == eValue && ma.isEPercent() == ePercent && ma.isITime() == iTime && ma.isIValue() == iValue && ma.isIPercent() == iPercent; } else { return super.equals(obj); // To change body of generated methods, choose Tools | Templates. } } public boolean anyExclusiveSelections() { return eTime || eValue || ePercent; } public boolean anyInclusiveSelections() { return iTime || iValue || iPercent; } public boolean anySelections() { return anyExclusiveSelections() || anyInclusiveSelections(); } } gprofng-gui-1.0/org/gprofng/mpmt/settings/TableSettings.java0000644000175000017500000000305314517772113021211 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; public class TableSettings extends Setting { private Boolean wrapMetricNames = wrapMetricNamesDefault(); public TableSettings() {} public void setWrapMetricNames(Object originalSource, boolean wrap) { if (wrap != wrapMetricNames) { setValueAndFireChangeEvent(originalSource, this, wrap); } } public void initWrapMetricNames(boolean wrap) { wrapMetricNames = wrap; } public Boolean wrapMetricNames() { return wrapMetricNames; } public static Boolean wrapMetricNamesDefault() { return true; } @Override Type getType() { return AnSettingChangeEvent.Type.TABLE_FORMATS; } @Override Object getValue() { return wrapMetricNames; } @Override void setValue(Object newValue) { Boolean wrap = (Boolean) newValue; wrapMetricNames = wrap; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/ViewModeEnabledSetting.java0000644000175000017500000000445714517772113023002 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; public class ViewModeEnabledSetting extends Setting { private boolean enabled = false; // Default public ViewModeEnabledSetting() {} public void init(Object originalSource, boolean newValue) { if (enabled != newValue) { this.enabled = newValue; fireChangeEvent(originalSource, newValue); } } public void init(boolean newValue) { enabled = newValue; } public boolean isViewModeEnabled() { return enabled; } @Override Type getType() { return AnSettingChangeEvent.Type.VIEW_MODE_ENABLED; } @Override Object getValue() { return enabled; } @Override void setValue(Object newValue) { enabled = (Boolean) newValue; } public static boolean getViewModeEnabledIPC() { boolean viewModeEnabled; synchronized (IPC.lock) { AnWindow.getInstance().IPC().send("getViewModeEnable"); viewModeEnabled = AnWindow.getInstance().IPC().recvBoolean(); } return viewModeEnabled; } /** * Send request to get View Mode Enabled. Non-blocking IPC call. Caller should call * ipcResult.getBoolean() to get the result * * @return IPCResult */ public static IPCResult getViewModeEnabledIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getViewModeEnable"); IPCResult ipcResult = ipcHandle.sendRequest(); // boolean result = ipcResult.getBoolean() // blocking return ipcResult; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricStates.java0000644000175000017500000004053114517772113021052 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import static org.gprofng.mpmt.settings.Settings.getMetricList; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.metrics.MetricNode; import java.util.ArrayList; import java.util.List; public class MetricStates { private List metricStateList; // Current selection. Capable and factory settings. private MMetric[] metricListsByMType; // Selected and ordered private boolean reverseSortDirection = false; private MetricNode metricsRootNode; private List newMetricOrder = null; private MetricType newSortMetric = null; private Boolean newReverseSortDirection = null; public MetricStates() {} public MetricStates(boolean reverseSortDirection) { this.reverseSortDirection = reverseSortDirection; } public MetricState findMetricStateByName(String name) { for (MetricState metricState : metricStateList) { if (metricState.getAnMetric().getComd().equals(name)) { return metricState; } } // System.err.println("METRICERROR: MetricStates.findMetricStateByName Can't find " + // name); return null; } public void setSelection(String name, boolean selected) { MetricState metricState = findMetricStateByName(name); if (metricState != null) { metricState.getSelection().setSelected(selected); // make sure something is selected if (!metricState.getSelection().getAttributes().anySelections()) { metricState.getSelection().setAttributes(metricState.getFactory().getAttributes().copy()); } } } public void setSelection(List metricNameSelectionList) { if (metricNameSelectionList != null) { for (MetricNameSelection metricNameSelection : metricNameSelectionList) { setSelection(metricNameSelection); } } } public void setSelection(MetricNameSelection metricNameSelection) { MetricState metricState = findMetricStateByName(metricNameSelection.getName()); if (metricState != null) { metricState.getSelection().set(metricNameSelection.getMetricSelection()); } } public boolean isSelected(String metricName) { MetricState metricState = findMetricStateByName(metricName); if (metricState != null) { return metricState.getSelection().isSelected(); } return false; } public void updateStates(MetricNode metricsRootNode, List metricStateList) { this.metricsRootNode = metricsRootNode; this.metricStateList = metricStateList; } public List getMetricStateList() { return metricStateList; } public void resetMetricListsByMType() { // System.out.println("resetMetricListsByMType"); metricListsByMType = new MMetric[MetricsSetting.MET_LAST]; // Use "async" IPC calls to minimize the "high latency" effect IPCResult[] ipcrs = new IPCResult[MetricsSetting.MET_LAST + 1]; for (int mtype = 0; mtype < MetricsSetting.MET_LAST; mtype++) { ipcrs[mtype] = MetricsSetting.SendRequest_getCurMetricsV2IPC(mtype); // ASYNC IPC } for (int mtype = 0; mtype < MetricsSetting.MET_LAST; mtype++) { Object[] ref_data = ipcrs[mtype].getObjects(); // Get IPC result if (ref_data != null && ref_data.length > 0) { metricListsByMType[mtype] = new MMetric(getMetricList(ref_data), reverseSortDirection); } else { metricListsByMType[mtype] = null; } } // Old code used "sync" IPC calls // for (int mtype = 0; mtype < MetricsSetting.MET_LAST; mtype++) { // Object[] ref_data = MetricsSetting.getCurMetricsV2IPC(mtype); // IPC // if (ref_data != null && ref_data.length > 0) { // metricListsByMType[mtype] = new MMetric(getMetricList(ref_data), // reverseSortDirection); // } else { // metricListsByMType[mtype] = null; // } // } } /** * @return Returns a deep copy */ protected MetricStates copy() { MetricStates copy = new MetricStates(reverseSortDirection); MMetric[] copyMetricListsByMType = new MMetric[metricListsByMType.length]; int index = 0; for (MMetric mMetric : metricListsByMType) { copyMetricListsByMType[index++] = mMetric.copy(); } copy.setMetricListsByMType(copyMetricListsByMType); List copyMetricStateList = new ArrayList(); for (MetricState metricState : metricStateList) { copyMetricStateList.add(metricState.copy()); } copy.updateStates(metricsRootNode, copyMetricStateList); return copy; } /** * @return list of changed metrics. Assume old and new lists contains same metrics in same order. */ public static List getChangedMetrics( MetricStates oldMetricsStates, MetricStates newMetricsStates) { if (oldMetricsStates == null) { // Just copy the 'new' list List changes = new ArrayList(); for (MetricState metricState : newMetricsStates.getMetricStateList()) { changes.add( new MetricNameSelection( metricState.getAnMetric().getComd(), metricState.getSelection().copy())); // FIXUP: copy necessary? } return changes; } List oldMetricStateList = oldMetricsStates.getMetricStateList(); List newMetricStateList = newMetricsStates.getMetricStateList(); boolean okToCheck = true; if (oldMetricStateList.size() != newMetricStateList.size()) { okToCheck = false; } if (okToCheck) { for (int i = 0; i < oldMetricStateList.size(); i++) { AnMetric oldAnMetric = oldMetricStateList.get(i).getAnMetric(); AnMetric newAnMetric = newMetricStateList.get(i).getAnMetric(); if (oldAnMetric != newAnMetric) { okToCheck = false; } } } if (!okToCheck) { System.err.println( "METRICERROR: MetricStates.getChangedMetrics: old and new lists are different"); } List changes = new ArrayList(); for (int i = 0; i < oldMetricStateList.size(); i++) { MetricState oldMetricState = oldMetricStateList.get(i); MetricState newMetricState = newMetricStateList.get(i); if (!oldMetricState.getSelection().equals(newMetricState.getSelection())) { changes.add( new MetricNameSelection( newMetricState.getAnMetric().getComd(), newMetricState.getSelection().copy())); // FIXUP: copy necessary? } } return changes; } public List getChangedMetricSortColumns() { List list = new ArrayList(); // Check change in sort column index for (int mtype = 0; mtype < MetricsSetting.MET_LAST; mtype++) { MMetric mMetric = metricListsByMType[mtype]; // Sort column changed? AnMetric[] anMetricList = mMetric.getmMetricList(); int oldSortIndex = -1; int index = 0; for (AnMetric anMetric : anMetricList) { if (anMetric.isSorted()) { oldSortIndex = index; break; } index++; } int newSortIndex = metricListsByMType[mtype].getSortIndex(); if (oldSortIndex != newSortIndex) { list.add(new int[] {mMetric.getSortIndex(), mtype}); } } // Check change to sort direction for (int mtype = 0; mtype < MetricsSetting.MET_LAST; mtype++) { MMetric mMetric = metricListsByMType[mtype]; boolean newReverseSortDirection = mMetric.isReverseSortDirection(); if (reverseSortDirection != newReverseSortDirection) { list.add(new int[] {mMetric.getSortIndex(), mtype}); } } return list; } public void transferSortChangesToMetricStates(List list) { for (int[] l : list) { int index = l[0]; int mtype = l[1]; MMetric mMetric = metricListsByMType[mtype]; for (int i = 0; i < mMetric.getmMetricList().length; i++) { mMetric.getmMetricList()[i].setSorted(false); } mMetric.getmMetricList()[index].setSorted(true); reverseSortDirection = mMetric.isReverseSortDirection(); } } public void updateSortMetric(int index, int mtype) { if (mtype < 0 || mtype >= metricListsByMType.length) { return; } MMetric mMetric = metricListsByMType[mtype]; int currentIndex = mMetric.getSortIndex(); if (index != currentIndex) { mMetric.setSortIndex(index); mMetric.setReverseSortDirection(false); } else { mMetric.setReverseSortDirection(!mMetric.isReverseSortDirection()); } } public void updateMetricOrder(int from, int to, int mtype) { if (from == to) { return; } if (mtype < 0 || mtype >= metricListsByMType.length) { return; } MMetric mMetric = metricListsByMType[mtype]; AnMetric[] mlist = mMetric.getmMetricList(); if (from < 0 || from >= mlist.length || to < 0 || to >= mlist.length) { return; } AnMetric m = mlist[from]; mlist[from] = mlist[to]; mlist[to] = m; // update sort index if (mMetric.getSortIndex() == from) { mMetric.setSortIndex(to); } else if (mMetric.getSortIndex() == to) { mMetric.setSortIndex(from); } // updateMetricOrder(mlist[from].getComd(), mlist[to].getComd(), from > to, mtype); } public void updateMetricOrder( String metricName, String metricRefName, boolean before, int mtype) { if (mtype < 0 || mtype >= metricListsByMType.length) { return; } MMetric mMetric = metricListsByMType[mtype]; AnMetric sortMetric = mMetric.getSortMetric(); AnMetric[] mlist = mMetric.getmMetricList(); List metricsToMove = new ArrayList(); List metricsNotToMove = new ArrayList(); for (int i = 0; i < mlist.length; i++) { if (mlist[i].getComd().equals(metricName)) { metricsToMove.add(mlist[i]); } else { metricsNotToMove.add(mlist[i]); } } int insertionIndex = -1; for (int i = 0; i < metricsNotToMove.size(); i++) { if (metricsNotToMove.get(i).getComd().equals(metricRefName)) { insertionIndex = i; if (before) { break; } } } if (insertionIndex != -1) { List newList = new ArrayList(); if (before) { for (int i = 0; i <= insertionIndex - 1; i++) { newList.add(metricsNotToMove.get(i)); } newList.addAll(metricsToMove); for (int i = insertionIndex; i < metricsNotToMove.size(); i++) { newList.add(metricsNotToMove.get(i)); } } else { for (int i = 0; i <= insertionIndex; i++) { newList.add(metricsNotToMove.get(i)); } newList.addAll(metricsToMove); for (int i = insertionIndex + 1; i < metricsNotToMove.size(); i++) { newList.add(metricsNotToMove.get(i)); } } if (newList.size() != mlist.length) { System.err.println("ERROR: MetricStates.UpdateMetricOrder newList.size() != mlist.length"); } else { newList.toArray(mlist); } int newSortIndex = mMetric.getIndex(sortMetric); mMetric.setSortIndex(newSortIndex); // // update sort index // if (mMetric.getSortIndex() == from) { // mMetric.setSortIndex(to); // } else if (mMetric.getSortIndex() == to) { // mMetric.setSortIndex(from); // } } } public List getSelectedMetricsByMType(int mType) { List list = new ArrayList(); String lastName = null; MMetric mList = metricListsByMType[mType]; for (AnMetric m : mList.getmMetricList()) { if (lastName == null || !lastName.equals(m.getComd())) { list.add(m); lastName = m.getComd(); } } return list; } public int getSortIndex(int mtype) { int sortIndex = -1; if (metricListsByMType != null && mtype >= 0 && mtype < metricListsByMType.length) { AnMetric[] mlist = metricListsByMType[mtype].getmMetricList(); for (int index = 0; index < mlist.length; index++) { if (mlist[index].isSorted()) { sortIndex = index; break; } } } return sortIndex; } public void dump() { System.out.println("--------------------------metricStates"); for (MetricState metricState : metricStateList) { metricState.dump(); } } protected void dumpMetricStates() { if (metricListsByMType != null) { for (int mtype = 0; mtype < metricListsByMType.length; mtype++) { dumpMetricListsByMType(mtype); } } System.out.println("reverseSortDirection: " + reverseSortDirection); } protected void dumpMetricListsByMType(int mtype) { System.out.println("State mtype: " + mtype); metricListsByMType[mtype].dump(); } public boolean isReverseDirectionSorting() { return reverseSortDirection; } public void setReverseDirectionSorting(boolean reverseDirectionSorting) { this.reverseSortDirection = reverseDirectionSorting; for (MMetric mMetric : metricListsByMType) { mMetric.setReverseSortDirection(reverseSortDirection); } } public MetricType[] getMetricSortByMType() { MetricType[] metricSortByMType = new MetricType[MetricsSetting.MET_LAST]; int index = 0; for (MMetric mMetric : metricListsByMType) { AnMetric sortMetric = mMetric.getSortMetric(); metricSortByMType[index] = new MetricType(sortMetric.getComd(), sortMetric.getSubType()); index++; } return metricSortByMType; } public List[] getMetricOrderLists() { List[] lists = (ArrayList[]) new ArrayList[MetricsSetting.MET_LAST]; for (int mtype = 0; mtype < MetricsSetting.MET_LAST; mtype++) { List orderList = new ArrayList(); MMetric metricList = metricListsByMType[mtype]; for (AnMetric anMetric : metricList.getmMetricList()) { orderList.add(new MetricType(anMetric.getComd(), anMetric.getSubType())); } lists[mtype] = orderList; } return lists; } public MMetric[] getMetricListsByMType() { return metricListsByMType; } public AnMetric[] getMetricListByMType(int mtype) { if (metricListsByMType == null) { return null; } if (mtype < 0 || mtype >= metricListsByMType.length) { return null; } return metricListsByMType[mtype].getmMetricList(); } public List getAnMetricsByMTypeTrimmed(int mtype) { AnMetric[] anMetricList = getMetricListByMType(mtype); List list = new ArrayList(); if (anMetricList != null) { String last = null; for (AnMetric anMetric : anMetricList) { if (!anMetric.getComd().equals(last)) { list.add(anMetric); last = anMetric.getComd(); } } } return list; } public void setMetricListsByMType(MMetric[] metricListsByMType) { this.metricListsByMType = metricListsByMType; } public List getNewMetricOrder() { return newMetricOrder; } public void setNewMetricOrder(List newMetricOrder) { this.newMetricOrder = newMetricOrder; } public MetricType getNewSortMetric() { return newSortMetric; } public void setNewSortMetric(MetricType newSortMetric) { this.newSortMetric = newSortMetric; } public Boolean getNewReverseSortDirection() { return newReverseSortDirection; } public void setNewReverseSortDirection(Boolean newReverseSortDirection) { this.newReverseSortDirection = newReverseSortDirection; setReverseDirectionSorting(newReverseSortDirection); } /** * @return the metricsRootNode */ public MetricNode getMetricsRootNode() { return metricsRootNode; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/AnSettingChangeEvent.java0000644000175000017500000000510214517772113022442 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import java.util.EventObject; public class AnSettingChangeEvent extends EventObject { public enum Type { VIEW_MODE, // fired when there is a change to "View Mode" setting VIEW_MODE_ENABLED, // fired when there is a change to "View Mode" visibility FORMAT, // fired when there are a changes to "Function Name Style" or "Append SO name to // Function name" settings COMPARE_MODE, // fired when there is a change to "Compare Mode" setting METRICS, // fired when there is a change to "Metrics" (visibility) settings TIMELINE, // fired when there is a change to "Timeline" settings SRC_DIS, // fired when there is a change to "Source/Disassembly" settings SEARCH_PATH, // fired when there is a change to "Search Path" settings PATH_MAP, // fired when there is a change to "Path Map" settings CALL_TREE, // fired when there is a change to "Call Tree" settings VIEWS, // fired when there is a change to "Views" settings LIBRARY_VISIBILITY, // fired when there is a change to "Library Visibility" settings TABLE_FORMATS, // fired when there is a change to Table Formats } private final Object originalSource; private final Type type; private final Object oldValue; private final Object newValue; public AnSettingChangeEvent( Object originalSource, Object source, Type type, Object oldValue, Object newValue) { super(source); this.type = type; this.originalSource = originalSource; this.oldValue = oldValue; this.newValue = newValue; } /** * @return the originalSource */ public Object getOriginalSource() { return originalSource; } /** * @return the type */ public Type getType() { return type; } /** * @return the oldValue */ public Object getOldValue() { return oldValue; } /** * @return the newValue */ public Object getNewValue() { return newValue; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/ViewModeSetting.java0000644000175000017500000000757514517772113021533 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; public class ViewModeSetting extends Setting { private static final ViewMode defaultViewMode = ViewMode.USER; public enum ViewMode { MACHINE(0, AnLocale.getString("Machine")), USER(1, AnLocale.getString("User")), EXPERT(2, AnLocale.getString("Expert")); private final int value; private final String name; private ViewMode(int value, String name) { this.value = value; this.name = name; } public int value() { return value; } public static ViewMode fromValue(int val) { for (ViewMode rt : ViewMode.values()) { if (rt.value() == val) { return rt; } } return null; } @Override public String toString() { return name; } }; private ViewMode viewMode = ViewMode.USER; // Default public ViewModeSetting() {} public void init(Object originalSource, ViewMode newViewMode) { viewMode = newViewMode; fireChangeEvent(originalSource, newViewMode); } public void set(Object originalSource, ViewMode newViewMode) { if (newViewMode != viewMode) { setValueAndFireChangeEvent(originalSource, this, newViewMode); } } // View Mode public ViewMode get() { return viewMode; } public String getStackName() { if (get() == ViewMode.MACHINE) { return "MSTACK"; } if (get() == ViewMode.EXPERT) { return "XSTACK"; } return "USTACK"; } public static ViewMode getDefaultViewMode() { return defaultViewMode; } @Override Type getType() { return AnSettingChangeEvent.Type.VIEW_MODE; } @Override Object getValue() { return viewMode; } @Override void setValue(Object newValue) { ViewMode newViewMode = (ViewMode) newValue; this.viewMode = newViewMode; setViewModeIPC(newViewMode.value()); // IPC } public static int getViewModeIPC() { synchronized (IPC.lock) { int viewMode; AnWindow.getInstance().IPC().send("getViewMode"); AnWindow.getInstance().IPC().send(0); viewMode = AnWindow.getInstance().IPC().recvInt(); return viewMode; } } /** * Send request to get View Mode. Non-blocking IPC call. Caller should call ipcResult.getInt() to * get the result * * @return IPCResult */ public static IPCResult getViewModeIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getViewMode"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // int result = ipcResult.getInt() // blocking return ipcResult; } /** * Set View Mode * * @param set 0 = Machine, 1 = User, 2 = Expert */ private static void setViewModeIPC(final int set) { synchronized (IPC.lock) { // System.out.println("setViewModeIPC: " + set); AnWindow.getInstance().IPC().send("setViewMode"); AnWindow.getInstance().IPC().send(0); AnWindow.getInstance().IPC().send(set); AnWindow.getInstance().IPC().recvString(); } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/ExportSettingsPanel.form0000644000175000017500000005755014517772113022460 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/settings/PathmapsPanel.java0000644000175000017500000006243414517772113021206 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnFile; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Component; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; public class PathmapsPanel extends javax.swing.JPanel { private static Color shadedBackground = new Color(249, 249, 249); private static Color listLabelBackground = new Color(241, 241, 241); private List dataFrom; private List dataTo; private PMListSelectionListener fromListSelectionListener; private PMDocumentListener pmDocumentListener; private Settings settings; public PathmapsPanel(Settings settings) { this.settings = settings; initComponents(); setBorder(BorderFactory.createMatteBorder(12, 12, 12, 10, (Color) null)); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); AnUtility.setTextAndAccessibleContext(topLabel, AnLocale.getString("Map the following path:")); AnUtility.setTextAndAccessibleContext(fromLabel, AnLocale.getString("From Path:")); fromLabel.setDisplayedMnemonic(AnLocale.getString('F', "PathmapFromPathLabelMnemonic")); fromLabel.setLabelFor(fromTextField); AnUtility.setTextAndAccessibleContext(toLabel, AnLocale.getString("To Path:")); toLabel.setDisplayedMnemonic(AnLocale.getString('T', "PathmapToPathLabelMnemonic")); toLabel.setLabelFor(toTextField); appendButton.setText(AnLocale.getString("Append")); appendButton.setToolTipText(AnLocale.getString("Append the mapping to the pathmap list")); appendButton.setMnemonic(AnLocale.getString('P', "PathMapPanelBrowseAppend_MN")); updateButton.setText(AnLocale.getString("Update")); updateButton.setMnemonic(AnLocale.getString('e', "PathMapPanelBrowseUpdate_MN")); updateButton.setToolTipText(AnLocale.getString("Update the selected pathmap with the changes")); upButton.setText(AnLocale.getString("Up")); upButton.setMnemonic(AnLocale.getString('u', "PathMapPanelBrowseUp_MN")); upButton.setToolTipText(AnLocale.getString("Move the selected pathmap up")); downButton.setText(AnLocale.getString("Down")); downButton.setMnemonic(AnLocale.getString('d', "PathMapPanelBrowseDown_MN")); downButton.setToolTipText(AnLocale.getString("Move theselected pathmap down")); removeButton.setText(AnLocale.getString("Remove")); removeButton.setMnemonic(AnLocale.getString('r', "PathMapPanelBrowseRemove_MN")); removeButton.setToolTipText(AnLocale.getString("Remove the selected pathmap")); fromButton.setToolTipText(AnLocale.getString("Browse for From Path (ALT B)")); fromButton.setMnemonic(AnLocale.getString('B', "PathMapPanelBrowseFromPathButtonMN")); toButton.setToolTipText(AnLocale.getString("Browse for To Path (ALT W)")); toButton.setMnemonic(AnLocale.getString('W', "PathMapPanelBrowsToPathButtonMN")); AnUtility.setTextAndAccessibleContext(listLabel, AnLocale.getString("Pathmaps:")); listLabel.setDisplayedMnemonic(AnLocale.getString('m', "PathmapPathmapsLabelMnemonic")); listLabel.setLabelFor(listTo); AnUtility.setTextAndAccessibleContext(fromListLabel, AnLocale.getString("From Path")); fromListLabel.setHorizontalAlignment(JLabel.CENTER); AnUtility.setTextAndAccessibleContext(toListLabel, AnLocale.getString("To Path")); toListLabel.setHorizontalAlignment(JLabel.CENTER); listPanelInner.setBackground(listLabelBackground); listPanel.setBorder( BorderFactory.createLineBorder(AnEnvironment.NAVIGATION_PANEL_BORDER_COLOR, 1)); fromListLabel.setBorder( BorderFactory.createMatteBorder(0, 0, 0, 1, AnEnvironment.NAVIGATION_PANEL_BORDER_COLOR)); listFromScrollPane.setBorder( BorderFactory.createMatteBorder(0, 0, 0, 1, AnEnvironment.NAVIGATION_PANEL_BORDER_COLOR)); listFrom.setCellRenderer(new LCR()); AnUtility.setTTAndAccessibleContext(listFrom, AnLocale.getString("Pathmap list")); listTo.setCellRenderer(new LCR()); fromListSelectionListener = new PMListSelectionListener(); pmDocumentListener = new PMDocumentListener(); listFrom.addListSelectionListener(fromListSelectionListener); listTo.addListSelectionListener(fromListSelectionListener); fromTextField.getDocument().addDocumentListener(pmDocumentListener); toTextField.getDocument().addDocumentListener(pmDocumentListener); updateStates(); } private class LCR extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JLabel label = (JLabel) super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus); // To change body of generated methods, choose Tools | Templates. label.setText(" " + label.getText()); if (index % 2 == 1 && !isSelected) { label.setBackground(shadedBackground); } return label; } } private void refreshPanel(int selectedIndex) { listFrom.setListData(dataFrom.toArray()); listTo.setListData(dataTo.toArray()); if (dataFrom.size() == 0) { return; } if (selectedIndex >= 0 && selectedIndex <= dataFrom.size()) { listFrom.setSelectedIndex(selectedIndex); listFrom.ensureIndexIsVisible(selectedIndex); listTo.setSelectedIndex(selectedIndex); listTo.ensureIndexIsVisible(selectedIndex); } } /** Called when there are changes to pathmaps settings */ public void updateGUI() { String[] from = AnWindow.getInstance().getSettings().getPathMapSetting().getPathMapFrom(); String[] to = AnWindow.getInstance().getSettings().getPathMapSetting().getPathMapTo(); dataFrom = new ArrayList(Arrays.asList(from)); dataTo = new ArrayList(Arrays.asList(to)); refreshPanel(0); } private void madeChanges() { settings.setMessageAreaVisible(true); settings.stateChanged(null); } /** Called from Save button in Settings panel */ public void checkPathMapChanged(Object originalSource) { String[] from = (String[]) dataFrom.toArray(new String[dataFrom.size()]); String[] to = (String[]) dataTo.toArray(new String[dataTo.size()]); String[][] pathMap = new String[2][]; pathMap[0] = from; pathMap[1] = to; AnWindow.getInstance().getSettings().getPathMapSetting().set(originalSource, pathMap); } class PMDocumentListener implements DocumentListener { @Override public void removeUpdate(DocumentEvent e) { updateStates(); } @Override public void insertUpdate(DocumentEvent e) { updateStates(); } @Override public void changedUpdate(DocumentEvent e) { updateStates(); } } class PMListSelectionListener implements javax.swing.event.ListSelectionListener { @Override public void valueChanged(ListSelectionEvent event) { if (event.getValueIsAdjusting()) { return; } // Synchronize selection listFrom.removeListSelectionListener(this); listTo.removeListSelectionListener(this); if (event.getSource() == listFrom) { listTo.setSelectedIndex(listFrom.getSelectedIndex()); } else { listFrom.setSelectedIndex(listTo.getSelectedIndex()); } listFrom.addListSelectionListener(this); listTo.addListSelectionListener(this); fromTextField.setText((String) listFrom.getSelectedValue()); toTextField.setText((String) listTo.getSelectedValue()); updateStates(); } } private void updateStates() { appendButton.setEnabled(false); updateButton.setEnabled(false); upButton.setEnabled(false); downButton.setEnabled(false); removeButton.setEnabled(false); if (dataFrom != null && dataFrom.size() > 0) { if (listFrom.getSelectedIndex() >= 0) { removeButton.setEnabled(true); } if (listFrom.getSelectedIndex() > 0) { upButton.setEnabled(true); } if (listFrom.getSelectedIndex() < dataFrom.size() - 1) { downButton.setEnabled(true); } } if (fromTextField.getText().length() > 0 && toTextField.getText().length() > 0) { appendButton.setEnabled(true); if (dataFrom != null && dataFrom.size() > 0) { int index = listFrom.getSelectedIndex(); if (index >= 0) { String from = dataFrom.get(index); String to = dataTo.get(index); if (!from.equals(fromTextField.getText()) || !to.equals(toTextField.getText())) { updateButton.setEnabled(true); } } } } } private String browse(String feed, String title) { String filePath = null; if (!Analyzer.getInstance().isRemote()) { // Local File feedFile = new File(feed); if (!feedFile.exists()) { feedFile = null; } JFileChooser fileChooser = new JFileChooser(); // Always local file chooser fileChooser.setDialogTitle(title); if (feedFile != null) { fileChooser.setCurrentDirectory(feedFile); } fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { filePath = fileChooser.getSelectedFile().getAbsolutePath(); } } else { // Remote AnFile feedFile = new AnFile(feed); if (!feedFile.exists()) { feedFile = null; } AnChooser fileChooser = AnWindow.getInstance() .getAnChooser(AnLocale.getString("To path"), AnChooser.DIR_FILE_CHOOSER, feed); // JFileChooser fileChooser = new JFileChooser(); // Always local file chooser if (feedFile != null) { fileChooser.setCurrentDirectory(feedFile); } fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { filePath = fileChooser.getSelectedFile().getAbsolutePath(); } } return filePath; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; topLabel = new javax.swing.JLabel(); fromLabel = new javax.swing.JLabel(); fromTextField = new javax.swing.JTextField(); fromButton = new javax.swing.JButton(); toLabel = new javax.swing.JLabel(); toTextField = new javax.swing.JTextField(); toButton = new javax.swing.JButton(); listLabel = new javax.swing.JLabel(); listPanel = new javax.swing.JPanel(); listPanelInner = new javax.swing.JPanel(); fromListLabel = new javax.swing.JLabel(); listFromScrollPane = new javax.swing.JScrollPane(); listFrom = new javax.swing.JList(); toListLabel = new javax.swing.JLabel(); listToScrollPane = new javax.swing.JScrollPane(); listTo = new javax.swing.JList(); topButtonPanel = new javax.swing.JPanel(); appendButton = new javax.swing.JButton(); updateButton = new javax.swing.JButton(); buttomButtonPanel = new javax.swing.JPanel(); upButton = new javax.swing.JButton(); downButton = new javax.swing.JButton(); removeButton = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); topLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; add(topLabel, gridBagConstraints); fromLabel.setText("From:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(fromLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); add(fromTextField, gridBagConstraints); fromButton.setText("..."); fromButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { fromButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); add(fromButton, gridBagConstraints); toLabel.setText("To:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; add(toLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(toTextField, gridBagConstraints); toButton.setText("..."); toButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { toButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(toButton, gridBagConstraints); listLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(listLabel, gridBagConstraints); listPanel.setLayout(new java.awt.GridBagLayout()); listPanelInner.setLayout(new java.awt.GridBagLayout()); fromListLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; listPanelInner.add(fromListLabel, gridBagConstraints); listFromScrollPane.setBorder(null); listFromScrollPane.setViewportView(listFrom); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 0.5; gridBagConstraints.weighty = 1.0; listPanelInner.add(listFromScrollPane, gridBagConstraints); toListLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; listPanelInner.add(toListLabel, gridBagConstraints); listToScrollPane.setBorder(null); listToScrollPane.setViewportView(listTo); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 0.5; gridBagConstraints.weighty = 1.0; listPanelInner.add(listToScrollPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; listPanel.add(listPanelInner, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(listPanel, gridBagConstraints); topButtonPanel.setLayout(new java.awt.GridBagLayout()); appendButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { appendButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; topButtonPanel.add(appendButton, gridBagConstraints); updateButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { updateButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); topButtonPanel.add(updateButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 1; gridBagConstraints.gridheight = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 0); add(topButtonPanel, gridBagConstraints); buttomButtonPanel.setLayout(new java.awt.GridBagLayout()); upButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { upButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; buttomButtonPanel.add(upButton, gridBagConstraints); downButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { downButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); buttomButtonPanel.add(downButton, gridBagConstraints); removeButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { removeButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); buttomButtonPanel.add(removeButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(buttomButtonPanel, gridBagConstraints); } // //GEN-END:initComponents private void appendButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_appendButtonActionPerformed dataFrom.add(fromTextField.getText()); dataTo.add(toTextField.getText()); refreshPanel(dataFrom.size() - 1); madeChanges(); } // GEN-LAST:event_appendButtonActionPerformed private void updateButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_updateButtonActionPerformed int index = listFrom.getSelectedIndex(); if (index >= 0) { dataFrom.remove(index); dataTo.remove(index); dataFrom.add(index, fromTextField.getText()); dataTo.add(index, toTextField.getText()); refreshPanel(index); madeChanges(); } } // GEN-LAST:event_updateButtonActionPerformed private void removeButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_removeButtonActionPerformed int index = listFrom.getSelectedIndex(); if (index >= 0) { dataFrom.remove(index); dataTo.remove(index); if (index < dataFrom.size()) { refreshPanel(index); } else { refreshPanel(index - 1); } madeChanges(); } } // GEN-LAST:event_removeButtonActionPerformed private void upButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_upButtonActionPerformed int index = listFrom.getSelectedIndex(); if (index > 0) { String from = dataFrom.get(index); String to = dataTo.get(index); dataFrom.remove(index); dataTo.remove(index); dataFrom.add(index - 1, from); dataTo.add(index - 1, to); refreshPanel(index - 1); madeChanges(); } } // GEN-LAST:event_upButtonActionPerformed private void downButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_downButtonActionPerformed int index = listFrom.getSelectedIndex(); if (index < dataFrom.size()) { String from = dataFrom.get(index); String to = dataTo.get(index); dataFrom.remove(index); dataTo.remove(index); dataFrom.add(index + 1, from); dataTo.add(index + 1, to); refreshPanel(index + 1); madeChanges(); } } // GEN-LAST:event_downButtonActionPerformed private void fromButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_fromButtonActionPerformed String feed = fromTextField.getText(); String res = browse(feed, AnLocale.getString("From Path")); fromTextField.setText(res); } // GEN-LAST:event_fromButtonActionPerformed private void toButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_toButtonActionPerformed String feed = toTextField.getText(); String res = browse(feed, AnLocale.getString("To Path")); toTextField.setText(res); } // GEN-LAST:event_toButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton appendButton; private javax.swing.JPanel buttomButtonPanel; private javax.swing.JButton downButton; private javax.swing.JButton fromButton; private javax.swing.JLabel fromLabel; private javax.swing.JLabel fromListLabel; private javax.swing.JTextField fromTextField; private javax.swing.JList listFrom; private javax.swing.JScrollPane listFromScrollPane; private javax.swing.JLabel listLabel; private javax.swing.JPanel listPanel; private javax.swing.JPanel listPanelInner; private javax.swing.JList listTo; private javax.swing.JScrollPane listToScrollPane; private javax.swing.JButton removeButton; private javax.swing.JButton toButton; private javax.swing.JLabel toLabel; private javax.swing.JLabel toListLabel; private javax.swing.JTextField toTextField; private javax.swing.JPanel topButtonPanel; private javax.swing.JLabel topLabel; private javax.swing.JButton upButton; private javax.swing.JButton updateButton; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/settings/ViewsSetting.java0000644000175000017500000010407114517772113021076 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.AnWindow.AnDispTab; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.MemoryIndexObjectView; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.metrics.MetricNode; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; import org.gprofng.mpmt.util.gui.AnUtility; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; public class ViewsSetting extends Setting { public class View { private AnDispTab anDispTab; private boolean selected; private View(AnDispTab anDispTab, boolean selected) { this.anDispTab = anDispTab; this.selected = selected; } /** * @return the anDispTab */ public AnDispTab getAnDispTab() { return anDispTab; } /** * @return the selected */ public boolean isSelected() { return selected; } /** * @param selected the selected to set */ private void setSelected(boolean selected) { this.selected = selected; } } public class Setting { private List viewList; private String preferredViewName; private Setting() { reset(); } private void reset() { viewList = new ArrayList(); preferredViewName = null; } private void addView(AnDispTab anDispTab, boolean selected) { View view = new View(anDispTab, selected); getViewList().add(view); } private void addViews(List list, boolean[] selected) { for (int i = 0; i < list.size(); i++) { addView(list.get(i), selected[i]); } } private void addViews(List list) { viewList.addAll(list); } private void setPreferredViewName(String selectedView) { this.preferredViewName = selectedView; } public String getPreferredViewName() { return preferredViewName; } private List getViewList() { return viewList; } private void setSelected(String name, boolean selected) { View view = findView(name); if (view != null) { view.setSelected(selected); } } private View findView(String name) { for (View view : viewList) { if (view.getAnDispTab().getTCmd().equals(name)) { return view; } } return null; } private View findView(int type) { for (View view : viewList) { if (view.getAnDispTab().getTType() == type) { return view; } } return null; } private void toggleTab(String cmd) { View view = findView(cmd); if (view != null) { view.setSelected(!view.isSelected()); } } private Setting copy() { Setting settingCopy = new Setting(); for (View view : viewList) { settingCopy.addView(view.getAnDispTab(), view.isSelected()); } settingCopy.setPreferredViewName(getPreferredViewName()); return settingCopy; } private List getSelectedViews() { List list = new ArrayList(); for (View view : viewList) { if (view.isSelected()) { list.add(view); } } return list; } private List getStaticViews() { List list = new ArrayList(); for (View view : viewList) { if (view.getAnDispTab().getTType() == AnDisplay.DSP_Welcome || view.getAnDispTab().getTType() == AnDisplay.DSP_Overview) { list.add(view); } } return list; } private List getStandardViews() { List list = new ArrayList(); for (View view : viewList) { if (view.getAnDispTab().getTType() != AnDisplay.DSP_Welcome && view.getAnDispTab().getTType() != AnDisplay.DSP_Overview && view.getAnDispTab().getTType() != AnDisplay.DSP_IndexObject && view.getAnDispTab().getTType() != AnDisplay.DSP_MemoryObject) { list.add(view); } } return list; } private List getIndexViews() { List list = new ArrayList(); for (View view : viewList) { if (view.getAnDispTab().getTType() == AnDisplay.DSP_IndexObject) { list.add(view); } } return list; } private List getMemoryViews() { List list = new ArrayList(); for (View view : viewList) { if (view.getAnDispTab().getTType() == AnDisplay.DSP_MemoryObject) { list.add(view); } } return list; } public View getFirstDataView() { View dataView = null; for (View view : viewList) { if (view.getAnDispTab().getTComp().getType() > 0 && view.getAnDispTab().getTComp().getType() != AnDisplay.DSP_Overview) { // <==== FIXUP: Is this the best check if (view.isSelected()) { dataView = view; break; } } } return dataView; } public void debug() { System.out.println("\nViewsSetting:"); System.out.println("PreferredViewName: " + getPreferredViewName()); int c = 0; for (View view : viewList) { System.out.println( c++ + ": " + view.getAnDispTab().getTName() + " " + view.getAnDispTab().getTType() + " " + view.isSelected()); } } } public static class CustomObject { private String name; private String formula; private String shortDesc; private String longDesc; public CustomObject(String name, String formula, String shortDesc, String longDesc) { this.name = name; this.formula = formula; this.shortDesc = shortDesc; this.longDesc = longDesc; } public String getName() { return name; } public String getFormula() { return formula; } public String getShortDesc() { return shortDesc; } public String getLongDesc() { return longDesc; } } private Setting setting = new Setting(); private List savedViewOrderList; private String[] availableMachineModels = null; private String machineModel = null; private List customIndexObjects = null; private List customMemoryObjects = null; private int[] viewMetricListIdMap; public ViewsSetting() { // FIXUP: hardcode the table for now. Should come from backend viewMetricListIdMap = new int[AnDisplay.DSP_MAX + 1]; for (int i = 0; i < viewMetricListIdMap.length; i++) { viewMetricListIdMap[i] = MetricNode.ALL_LIST_ID; } viewMetricListIdMap[AnDisplay.DSP_MemoryObject] = MetricNode.DATASPACE_HWC_LIST_ID; viewMetricListIdMap[AnDisplay.DSP_DataObjects] = MetricNode.DATASPACE_HWC_LIST_ID; viewMetricListIdMap[AnDisplay.DSP_DataLayout] = MetricNode.DATASPACE_HWC_LIST_ID; viewMetricListIdMap[AnDisplay.DSP_IO] = MetricNode.IO_LIST_ID; viewMetricListIdMap[AnDisplay.DSP_Heap] = MetricNode.HEAP_LIST_ID; } public int getViewMetricListIdMapping(int dtype) { if (dtype >= 0 && dtype <= AnDisplay.DSP_MAX) { return viewMetricListIdMap[dtype]; } else { return MetricNode.ALL_LIST_ID; } } public void debug() { setting.debug(); } private void set(Object originalSource, Setting newSetting) { boolean changed = false; List oldList = setting.getViewList(); List newList = newSetting.getViewList(); if (oldList.size() != newList.size()) { changed = true; } else { for (int i = 0; i < oldList.size(); i++) { if (oldList.get(i).isSelected() != newList.get(i).isSelected()) { changed = true; } } } if (changed) { setValueAndFireChangeEvent(originalSource, this, newSetting); } } /* * Called when custom index/memory objects added */ public void init( Object originalSource, List list, boolean[] selected, String preferredViewName) { Setting newSetting = new Setting(); newSetting.addViews(list, selected); newSetting.setPreferredViewName(preferredViewName); setting = newSetting; } /* * Called when experiment(s) loaded */ public void init( Object originalSource, List viewOrderList, String[][] groups, Object[] standardViews, boolean[] standardViewsSelected, Object[] indexViews, boolean[] indexViewsSelected, Object[] memoryViews, boolean[] memoryViewsSelected, String[] availableMachineModels, String machineModel, List customIndexObjects, List customMemoryObjects) { AnWindow window = AnWindow.getInstance(); this.savedViewOrderList = viewOrderList; this.availableMachineModels = availableMachineModels; this.machineModel = machineModel; this.customIndexObjects = customIndexObjects; this.customMemoryObjects = customMemoryObjects; String preferredViewName; AnDispTab[] staticObjs; boolean[] staticSelected; List listStatic; List listStandard; List listIndex; List listMemory; if (groups.length == 0) { staticObjs = new AnDispTab[] {window.new AnDispTab(AnDisplay.DSP_Welcome, "welcome", null, null)}; staticSelected = new boolean[] {true}; listStatic = addStaticObjects(staticObjs); listStandard = new ArrayList(); standardViewsSelected = new boolean[0]; listIndex = new ArrayList(); indexViewsSelected = new boolean[0]; listMemory = new ArrayList(); memoryViewsSelected = new boolean[0]; preferredViewName = staticObjs[0].getTCmd(); } else { staticObjs = new AnDispTab[] { window.new AnDispTab(AnDisplay.DSP_Welcome, "welcome", null, null), window.new AnDispTab(AnDisplay.DSP_Overview, "overview", null, null) }; staticSelected = new boolean[] {true, true}; listStatic = addStaticObjects(staticObjs); listStandard = addStandardObjects(standardViews); listIndex = addIndexObjects(indexViews); listMemory = addMemoryObjects(memoryViews); preferredViewName = staticObjs[1].getTCmd(); } // Hack to enable Heap view if available. Should be done in the backend. int index = 0; for (AnDispTab adt : listStandard) { if (adt.getTType() == AnDisplay.DSP_Heap) { if (!standardViewsSelected[index]) { standardViewsSelected[index] = true; } break; } index++; } // Hack end Setting newSetting = new Setting(); newSetting.addViews(listStatic, staticSelected); newSetting.addViews(listStandard, standardViewsSelected); newSetting.addViews(listIndex, indexViewsSelected); newSetting.addViews(listMemory, memoryViewsSelected); newSetting.setPreferredViewName(preferredViewName); if (viewOrderList != null) { for (UserPref.ViewPanelOrder viewPanelOrder : viewOrderList) { newSetting.setSelected(viewPanelOrder.getName(), viewPanelOrder.isShown()); } } setting = newSetting; fireChangeEvent(originalSource, setting); // for (AnDispTab adt : listStandard) { // int dtype = adt.getTType(); // int mtype = MetricsSetting.dtype2mtype(dtype); // System.out.println(String.format("%2d", dtype) + " " + mtype + " " + // adt.getTName() + " " + adt.getTCmd()); // } } /** Called from import settings... */ public void set( final Object originalSource, final List viewOrderList, final String machineModel, final List customIndexObjects, final List customMemoryObjects) { AnUtility.checkIfOnAWTThread(true); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { synchronized (AnVariable.mainFlowLock) { if (machineModel == null) { if (ViewsSetting.this.machineModel != null) { ViewsSetting.loadMachineModelIPC(""); } } else if (!machineModel.equals(ViewsSetting.this.machineModel)) { ViewsSetting.this.machineModel = machineModel; ViewsSetting.loadMachineModelIPC(machineModel); } if (customIndexObjects != null) { for (CustomObject customObject : customIndexObjects) { ViewsSetting.defineIndxObjIPC( customObject.getName(), customObject.getFormula(), customObject.getShortDesc(), customObject.getLongDesc()); } } if (customMemoryObjects != null) { for (CustomObject customObject : customMemoryObjects) { ViewsSetting.defineMemObjIPC( customObject.getName(), customObject.getFormula(), customObject.getShortDesc(), customObject.getLongDesc()); } } final Object[] standardViews = getTabListInfoIPC(); final boolean[] standardViewsSelected = ViewsSetting.getTabSelectionStateIPC(); final Object[] indexViews = ViewsSetting.getIndxObjDescriptionsIPC(); final boolean[] indexViewsSelected = ViewsSetting.getIndxTabSelectionStateIPC(); final Object[] memoryViews = ViewsSetting.getMemObjectsIPC(); final boolean[] memoryViewsSelected = ViewsSetting.getMemTabSelectionStateIPC(); AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { init( originalSource, viewOrderList, AnWindow.getInstance().getExperimentGroups(), standardViews, standardViewsSelected, indexViews, indexViewsSelected, memoryViews, memoryViewsSelected, availableMachineModels, machineModel, customIndexObjects, customMemoryObjects); } }); } } }, "Set Views Thread"); } public void set(Object originalSource, boolean[] selected) { Setting settingCopy = setting.copy(); List list = settingCopy.getViewList(); assert selected.length == list.size(); for (int i = 0; i < list.size(); i++) { list.get(i).setSelected(selected[i]); } settingCopy.setPreferredViewName(AnWindow.getInstance().getViews().getCurrentViewName()); set(originalSource, settingCopy); } public void toggleTab(String cmd, String preferredViewName) { Setting settingCopy = setting.copy(); settingCopy.toggleTab(cmd); settingCopy.setPreferredViewName(preferredViewName); set(this, settingCopy); } public String getPreferredViewName() { return setting.getPreferredViewName(); } public List getSavedViewOrderList() { return savedViewOrderList; } public String[] getAvailableMachineMsodel() { return availableMachineModels; } public String getMachineModel() { return machineModel; } public void setMachineModel(String loadedMachineModel) { this.machineModel = loadedMachineModel; } public void addCustomIndexObject(String name, String command, String shortDesc, String ldesc) { if (customIndexObjects == null) { customIndexObjects = new ArrayList(); } customIndexObjects.add(new CustomObject(name, command, shortDesc, ldesc)); } public List getCustomIndexObjects() { return customIndexObjects; } public void addCustomMemoryObject( String name, String command, String shortDesc, String longDesc) { if (customMemoryObjects == null) { customMemoryObjects = new ArrayList(); } customMemoryObjects.add(new CustomObject(name, command, shortDesc, longDesc)); } public List getCustomMemoryObjects() { return customMemoryObjects; } private List addStaticObjects(AnDispTab[] staticObjs) { List list = new ArrayList(); for (int i = 0; i < staticObjs.length; i++) { AnDispTab anDispTab = staticObjs[i]; list.add(anDispTab); } return list; } private List addStandardObjects(Object[] tabObjs) { List list = new ArrayList(); AnWindow window = AnWindow.getInstance(); int[] ids = (int[]) tabObjs[0]; String[] cmds = (String[]) tabObjs[1]; String[] shortDescs = null; // FIXUP: need short/long descr from gp-display-text String[] longDescs = null; // FIXUP: need short/long descr from gp-display-text for (int i = 0; i < ids.length; i++) { AnDispTab anDispTab = window .new AnDispTab(ids[i], cmds[i], null, null); // FIXUP: need short/long descr from gp-display-text list.add(anDispTab); } return list; } private List addIndexObjects(Object[] indxObjs) { List list = new ArrayList(); AnWindow window = AnWindow.getInstance(); int[] ids = (int[]) indxObjs[0]; String[] cmds = (String[]) indxObjs[1]; char[] mnemonics = (char[]) indxObjs[2]; String[] i18nids = (String[]) indxObjs[3]; String[] shortDescs = (String[]) indxObjs[6]; String[] longDescs = (String[]) indxObjs[7]; for (int i = 0; i < ids.length; i++) { String s = (i18nids[i] == null) ? cmds[i] : i18nids[i]; String shortDesc = shortDescs[i]; String longDesc = longDescs[i]; AnDispTab anDispTab = window .new AnDispTab( AnDisplay.DSP_IndexObject, ids[i], s, mnemonics[i], cmds[i], shortDesc, longDesc); list.add(anDispTab); } return list; } private List addMemoryObjects(Object[] memObjs) { List list = new ArrayList(); AnWindow window = AnWindow.getInstance(); int[] ids = (int[]) memObjs[0]; String[] cmds = (String[]) memObjs[1]; char[] mnemonics = (char[]) memObjs[2]; String[] i18nids = (String[]) memObjs[3]; String[] shortDescs = (String[]) memObjs[6]; String[] longDescs = (String[]) memObjs[7]; for (int i = 0; i < ids.length; i++) { String shortDesc = shortDescs[i]; String longDesc = longDescs[i]; AnDispTab anDispTab = window .new AnDispTab( AnDisplay.DSP_MemoryObject, ids[i], cmds[i], mnemonics[i], cmds[i], shortDesc, longDesc); list.add(anDispTab); } return list; } public void updateIndexObjects(Object originalSource, Object[] indxObjs, boolean[] indxSelected) { List staticList2 = setting.getStaticViews(); List standardList2 = setting.getStandardViews(); List indexList2 = setting.getIndexViews(); List memoryList2 = setting.getMemoryViews(); cleanUpOldObjects2(indexList2); List indxList = addIndexObjects(indxObjs); Setting settingCopy = new Setting(); settingCopy.addViews(staticList2); settingCopy.addViews(standardList2); settingCopy.addViews(indxList, indxSelected); settingCopy.addViews(memoryList2); settingCopy.setPreferredViewName(AnWindow.getInstance().getViews().getCurrentViewName()); set(originalSource, settingCopy); } public void updateMemoryObjects(Object originalSource, Object[] memObjs, boolean[] memSelected) { List staticList2 = setting.getStaticViews(); List standardList2 = setting.getStandardViews(); List indexList2 = setting.getIndexViews(); List memoryList2 = setting.getMemoryViews(); cleanUpOldObjects2(memoryList2); List memList = addMemoryObjects(memObjs); Setting settingCopy = new Setting(); settingCopy.addViews(staticList2); settingCopy.addViews(standardList2); settingCopy.addViews(indexList2); settingCopy.addViews(memList, memSelected); settingCopy.setPreferredViewName(AnWindow.getInstance().getViews().getCurrentViewName()); set(originalSource, settingCopy); } public void updateIndexMemoryObjects( Object originalSource, Object[] indxObjs, boolean[] indxSelected, Object[] memObjs, boolean[] memSelected) { List staticList2 = setting.getStaticViews(); List standardList2 = setting.getStandardViews(); List indexList2 = setting.getIndexViews(); List memoryList2 = setting.getMemoryViews(); cleanUpOldObjects2(indexList2); List indxList = addIndexObjects(indxObjs); cleanUpOldObjects2(memoryList2); List memList = addMemoryObjects(memObjs); Setting settingCopy = new Setting(); settingCopy.addViews(staticList2); settingCopy.addViews(standardList2); settingCopy.addViews(indxList, indxSelected); settingCopy.addViews(memList, memSelected); settingCopy.setPreferredViewName(AnWindow.getInstance().getViews().getCurrentViewName()); set(originalSource, settingCopy); } public List getStaticViews() { List list = new ArrayList(); for (View view : setting.getStaticViews()) { list.add(view); } return list; } public List getStandardViews() { List list = new ArrayList(); for (View view : setting.getStandardViews()) { list.add(view); } return list; } public List getIndexViews() { List list = new ArrayList(); for (View view : setting.getIndexViews()) { list.add(view); } return list; } public List getMemoryViews() { List list = new ArrayList(); for (View view : setting.getMemoryViews()) { list.add(view); } return list; } public List getSelectedViews() { List list = new ArrayList(); for (View view : setting.getSelectedViews()) { list.add(view.getAnDispTab()); } return list; } public View findView(String cmd) { return setting.findView(cmd); } public View findView(int type) { return setting.findView(type); } public boolean isViewAvailable(String cmd) { return findView(cmd) != null; } public boolean isAvailableAndShowing(String cmd) { View view = setting.findView(cmd); if (view == null) { return false; } else { return view.isSelected(); } } public View getFirstDataView() { View dataView = setting.getFirstDataView(); return dataView; } @Override Type getType() { return AnSettingChangeEvent.Type.VIEWS; } @Override Object getValue() { return setting; } @Override void setValue(Object newValue) { Setting newSetting = (Setting) newValue; setting = newSetting; // setting.debug(); } private void cleanUpOldObjects2(List list) { if (list != null) { for (int i = 0; i < list.size(); i++) { View view = (View) list.get(i); AnDisplay anDisplay = view.getAnDispTab().getTComp(); if (anDisplay instanceof MemoryIndexObjectView) { ((MemoryIndexObjectView) anDisplay).toBeRemoved(); } } } } public static boolean viewNameChanged( ViewsSetting.Setting oldSetting, ViewsSetting.Setting newSetting) { boolean changed = false; String oldViewName = oldSetting.getPreferredViewName(); String newViewName = newSetting.getPreferredViewName(); if (newViewName != null) { if (oldViewName == null) { changed = true; } else { changed = !newViewName.equals(oldViewName); } } return changed; } public static boolean viewsChanged( ViewsSetting.Setting oldSetting, ViewsSetting.Setting newSetting) { boolean changed = false; if (oldSetting == null) { changed = true; } else { List oldList = oldSetting.getSelectedViews(); List newList = newSetting.getSelectedViews(); if (oldList.size() != newList.size()) { changed = true; } else { for (int i = 0; i < oldList.size(); i++) { View oldView = oldList.get(i); View newView = newList.get(i); if (oldView.isSelected() != newView.isSelected() || oldView.getAnDispTab() != newView.getAnDispTab()) { changed = true; break; } } } } return changed; } public List createViewsSettingsSelector() { List componentList = new ArrayList(); componentList.add(AnWindow.getInstance().getViewsSettingsAction().getMenuItem()); return componentList; } // IPC Calls // ------------------------------------------------------------------------------------------------------------ public static Object[] getTabListInfoIPC() { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getTabListInfo"); anWindow.IPC().send(0); return (Object[]) anWindow.IPC().recvObject(); } } /** * Send request to get Tab List Info. Non-blocking IPC call. Caller should call * ipcResult.getObjects() to get the result * * @return IPCResult */ public static IPCResult getTabListInfoIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getTabListInfo"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // Object[] result = ipcResult.getObjects() // blocking return ipcResult; } public static boolean[] getTabSelectionStateIPC() { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("getTabSelectionState"); window.IPC().send(0); return (boolean[]) window.IPC().recvObject(); } } /** * Send request to get Tab Selection State. Non-blocking IPC call. Caller should call * ipcResult.getBooleans() to get the result * * @return IPCResult */ public static IPCResult getTabSelectionStateIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getTabSelectionState"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // boolean[] result = ipcResult.getBooleans() // blocking return ipcResult; } // private void setTabSelectionState(final boolean[] selected) { // synchronized (IPC.lock) { // m_window.IPC().send("setTabSelectionState"); // m_window.IPC().send(m_window.getWindowID()); // m_window.IPC().send(selected); // m_window.IPC().recvString(); //synchronize // } // } public static boolean[] getMemTabSelectionStateIPC() { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("getMemTabSelectionState"); window.IPC().send(0); return (boolean[]) window.IPC().recvObject(); } } /** * Send request to get Mem Tab Selection State. Non-blocking IPC call. Caller should call * ipcResult.getBooleans() to get the result * * @return IPCResult */ public static IPCResult getMemTabSelectionStateIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getMemTabSelectionState"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // boolean[] result = ipcResult.getBooleans() // blocking return ipcResult; } // private void setMemTabSelectionState(final boolean[] selected) { // synchronized (IPC.lock) { // m_window.IPC().send("setMemTabSelectionState"); // m_window.IPC().send(m_window.getWindowID()); // m_window.IPC().send(selected); // m_window.IPC().recvString(); //synchronize // } // } public static Object[] getMemObjectsIPC() { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("getMemObjects"); window.IPC().send(0); return (Object[]) window.IPC().recvObject(); } } /** * Send request to get Mem Objects. Non-blocking IPC call. Caller should call * ipcResult.getObjects() to get the result * * @return IPCResult */ public static IPCResult getMemObjectsIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getMemObjects"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // Object[] result = ipcResult.getObjects() // blocking return ipcResult; } // private String[] getCPUVerMachineModel() { // synchronized (IPC.lock) { // m_window.IPC().send("getCPUVerMachineModel"); // m_window.IPC().send(m_window.getWindowID()); // return (String[]) m_window.IPC().recvObject(); // } // } public static String getMachineModelIPC() { synchronized (IPC.lock) { AnWindow m_window = AnWindow.getInstance(); m_window.IPC().send("getMachineModel"); return m_window.IPC().recvString(); } } /** * Send request to get Machine Model. Non-blocking IPC call. Caller should call * ipcResult.getString() to get the result * * @return IPCResult */ public static IPCResult getMachineModelIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getMachineModel"); IPCResult ipcResult = ipcHandle.sendRequest(); // String result = ipcResult.getString() // blocking return ipcResult; } public static String loadMachineModelIPC(final String name) { synchronized (IPC.lock) { AnWindow m_window = AnWindow.getInstance(); m_window.IPC().send("loadMachineModel"); m_window.IPC().send(name); return m_window.IPC().recvString(); } } public static String[] listMachineModelsIPC() { synchronized (IPC.lock) { AnWindow m_window = AnWindow.getInstance(); m_window.IPC().send("listMachineModels"); return (String[]) m_window.IPC().recvObject(); } } public static String defineMemObjIPC( final String name, final String formula, final String sdesc, final String ldesc) { synchronized (IPC.lock) { AnWindow m_window = AnWindow.getInstance(); m_window.IPC().send("defineMemObj"); m_window.IPC().send(name); m_window.IPC().send(formula); m_window.IPC().send(sdesc); m_window.IPC().send(ldesc); return m_window.IPC().recvString(); } } public static boolean[] getIndxTabSelectionStateIPC() { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("getIndxTabSelectionState"); window.IPC().send(0); return (boolean[]) window.IPC().recvObject(); } } /** * Send request to get Index Tab Selection State. Non-blocking IPC call. Caller should call * ipcResult.getBooleans() to get the result * * @return IPCResult */ public static IPCResult getIndxTabSelectionStateIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getIndxTabSelectionState"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // boolean[] result = ipcResult.getBooleans() // blocking return ipcResult; } // private void setIndxTabSelectionState(final boolean[] selected) { // synchronized (IPC.lock) { // m_window.IPC().send("setIndxTabSelectionState"); // m_window.IPC().send(m_window.getWindowID()); // m_window.IPC().send(selected); // m_window.IPC().recvString(); //synchronize // } // } public static Object[] getIndxObjDescriptionsIPC() { synchronized (IPC.lock) { AnWindow window = AnWindow.getInstance(); window.IPC().send("getIndxObjDescriptions"); window.IPC().send(0); return (Object[]) window.IPC().recvObject(); } } /** * Send request to get Index Object Descriptions. Non-blocking IPC call. Caller should call * ipcResult.getObjects() to get the result * * @return IPCResult */ public static IPCResult getIndxObjDescriptionsIPCRequest() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getIndxObjDescriptions"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // Object[] result = ipcResult.getObjects() // blocking return ipcResult; } public static String defineIndxObjIPC( final String name, final String formula, final String sdesc, final String ldesc) { synchronized (IPC.lock) { AnWindow m_window = AnWindow.getInstance(); m_window.IPC().send("defineIndxObj"); m_window.IPC().send(name); m_window.IPC().send(formula); m_window.IPC().send(sdesc); m_window.IPC().send(ldesc); return m_window.IPC().recvString(); } } public static Object[] getCustomIndxObjectsIPC() { synchronized (IPC.lock) { AnWindow m_window = AnWindow.getInstance(); m_window.IPC().send("getCustomIndxObjects"); m_window.IPC().send(0); return (Object[]) m_window.IPC().recvObject(); } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/SearchPathPanel.form0000644000175000017500000003177614517772113021502 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricState.java0000644000175000017500000000604514517772113020671 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnMetric; public class MetricState { private String listName; private int listId; private AnMetric anMetric; private MetricAttributes capable; private MetricSelection factory; private MetricSelection selection; public MetricState( String listName, int listId, AnMetric anMetric, MetricAttributes capable, MetricSelection factory, MetricSelection selection) { this.listName = listName; this.listId = listId; this.anMetric = anMetric; this.capable = capable; this.factory = factory; this.selection = selection; } public void dump() { System.out.print(String.format("%-20s", anMetric.getComd())); dumpMetricAttributes(capable); System.out.print(" "); dumpMetricAttributes(factory); System.out.print(" "); dumpMetricAttributes(getSelection()); System.out.println(); } private void dumpMetricAttributes(MetricSelection metricSelection) { System.out.print(metricSelection.isSelected() ? "X" : " "); dumpMetricAttributes(metricSelection.getAttributes()); } private void dumpMetricAttributes(MetricAttributes metricAttributes) { System.out.print(metricAttributes.isETime() ? "+" : "-"); System.out.print(metricAttributes.isEValue() ? "+" : "-"); System.out.print(metricAttributes.isEPercent() ? "+" : "-"); System.out.print(" "); System.out.print(metricAttributes.isITime() ? "+" : "-"); System.out.print(metricAttributes.isIValue() ? "+" : "-"); System.out.print(metricAttributes.isIPercent() ? "+" : "-"); } /** * @return the listName */ public String getListName() { return listName; } /** * @return the anMetric */ public AnMetric getAnMetric() { return anMetric; } /** * @return the selection */ public MetricSelection getSelection() { return selection; } /** * @return a deep copy (except for static states */ public MetricState copy() { MetricState copy = new MetricState(listName, listId, anMetric, capable, factory, selection.copy()); return copy; } /** * @return the factory */ public MetricSelection getFactory() { return factory; } /** * @return the capable */ public MetricAttributes getCapable() { return capable; } /** * @return the listId */ public int getListId() { return listId; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/ExportSettingsPanel.java0000644000175000017500000010503114517772113022422 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnFile; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; /** * @author tpreisle */ public class ExportSettingsPanel extends javax.swing.JPanel { private static final Color errorColor = Color.red; private static final Color warningColor = new Color(255, 150, 0); ExportSettingsDialog dialog = null; DocListener docListener = new DocListener(); private List checkBoxes = new ArrayList(); /** Creates new form SaveSettingsPanel */ public ExportSettingsPanel(ExportSettingsDialog dialog) { this.dialog = dialog; initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); ActionListener checkBoxActionListener = new CheckBoxActionListener(); checkBoxes.add(metricsCheckBox); checkBoxes.add(viewsCheckBox); checkBoxes.add(formatsCheckBox); checkBoxes.add(callTreeCheckBox); checkBoxes.add(sourceDisassemblyCheckBox); checkBoxes.add(functionColorsCheckBox); checkBoxes.add(timelineCheckBox); checkBoxes.add(searchPathCheckBox); checkBoxes.add(pathmapCheckBox); checkBoxes.add(libraryClassVisibilityCheckBox); checkBoxes.add(miscCheckBox); AnUtility.setTTAndAccessibleContext(allCheckBox, AnLocale.getString("Select all")); AnUtility.setTextAndAccessibleContext( infoLabel, AnLocale.getString( "Export settings to a configuration file. Select which options to save and where to" + " save them. Saved configuration files can be imported and also selected when" + " opening an experiment.")); AnUtility.setTextAndAccessibleContext(whatLabel, AnLocale.getString("Options to export:")); whatLabel.setDisplayedMnemonic( AnLocale.getString('O', "ExportSettingsOptionsToExportLabelMnemonics")); whatLabel.setLabelFor(viewsCheckBox); metricsCheckBox.setText(AnLocale.getString("Metrics")); viewsCheckBox.setText(AnLocale.getString("Views")); formatsCheckBox.setText(AnLocale.getString("Formats")); callTreeCheckBox.setText(AnLocale.getString("Call Tree")); sourceDisassemblyCheckBox.setText(AnLocale.getString("Source/Disassembly")); functionColorsCheckBox.setText(AnLocale.getString("Function Colors")); timelineCheckBox.setText(AnLocale.getString("Timeline")); searchPathCheckBox.setText(AnLocale.getString("Search Path")); pathmapCheckBox.setText(AnLocale.getString("Pathmaps")); libraryClassVisibilityCheckBox.setText(AnLocale.getString("Library and Class Visibility")); miscCheckBox.setText(AnLocale.getString("Miscellaneous")); metricsCheckBox.setToolTipText( AnLocale.getString( "Selected metrics")); // getString("Selected metrics, order, and sort metric")); viewsCheckBox.setToolTipText(AnLocale.getString("Selected views and order")); formatsCheckBox.setToolTipText(AnLocale.getString("Formats settings")); callTreeCheckBox.setToolTipText(AnLocale.getString("Call Tree settings")); sourceDisassemblyCheckBox.setToolTipText(AnLocale.getString("Source/Disassembly settings")); functionColorsCheckBox.setToolTipText(AnLocale.getString("Function color settings")); timelineCheckBox.setToolTipText(AnLocale.getString("Timeline settings")); searchPathCheckBox.setToolTipText(AnLocale.getString("Search Path settings")); pathmapCheckBox.setToolTipText(AnLocale.getString("Pathmap settings")); libraryClassVisibilityCheckBox.setToolTipText( AnLocale.getString("Library and Class Visibility settings")); miscCheckBox.setToolTipText(AnLocale.getString("Find history, ...")); allCheckBox.addActionListener(new AllCheckBoxActionListener()); for (JCheckBox checkBox : checkBoxes) { checkBox.addActionListener(checkBoxActionListener); } metricsCheckBox.setSelected(true); viewsCheckBox.setSelected(true); formatsCheckBox.setSelected(true); callTreeCheckBox.setSelected(true); sourceDisassemblyCheckBox.setSelected(true); functionColorsCheckBox.setSelected(true); timelineCheckBox.setSelected(true); searchPathCheckBox.setSelected(true); pathmapCheckBox.setSelected(true); libraryClassVisibilityCheckBox.setSelected(true); miscCheckBox.setSelected(true); fullPathTextField.setEditable(false); AnUtility.setTextAndAccessibleContext( locationOptionsLabel, AnLocale.getString("Where to save the configuration file:")); locationOptionsLabel.setDisplayedMnemonic( AnLocale.getString('W', "ExportSettingsWhereToLabelMnemonics")); locationOptionsLabel.setLabelFor(experimentFolderRadioButton); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(experimentFolderRadioButton); buttonGroup.add(experimetParentRadioButton); buttonGroup.add(homeRadioButton); buttonGroup.add(otherRadioButton); experimentFolderRadioButton.setText(AnLocale.getString("Experiment")); experimentFolderRadioButton.setToolTipText( AnLocale.getString("Save settings inside the experiment (private to this experiment)")); experimetParentRadioButton.setText(AnLocale.getString("Experiment's parent folder")); experimetParentRadioButton.setToolTipText( AnLocale.getString( "Save settings in the parent folder of the experiment (shared between experiments in" + " this folder)")); homeRadioButton.setText(AnLocale.getString("User Directory")); homeRadioButton.setToolTipText( AnLocale.getString( "Save settings in the user directory " + UserPref.getAnalyzerDirPath() + " (shared between all experiments)")); otherRadioButton.setText(AnLocale.getString("Other")); otherRadioButton.setToolTipText(AnLocale.getString("Save settings in another location...")); RadioButtonActionListener radioButtonActionListener = new RadioButtonActionListener(); experimentFolderRadioButton.addActionListener(radioButtonActionListener); experimetParentRadioButton.addActionListener(radioButtonActionListener); homeRadioButton.addActionListener(radioButtonActionListener); otherRadioButton.addActionListener(radioButtonActionListener); // AnUtility.setTextAndAccessibleContext(locationLabel, AnLocale.getString("Location:")); locationLabel.setDisplayedMnemonic( AnLocale.getString('L', "ExportSettingsLocationLabelMnemonic")); locationLabel.setLabelFor(pathTextField); // AnUtility.setTTAndAccessibleContext(pathTextField, locationLabel.getText()); browseButton.setToolTipText(AnLocale.getString("Browse for Location (ALT B)")); browseButton.setMnemonic(AnLocale.getString('B', "ExportBrowseButtonMnemonic")); experimentFolderRadioButton.setSelected(true); // radioButtonActionListener.actionPerformed(null); // pathTextField.getDocument().addDocumentListener(docListener); AnUtility.setTextAndAccessibleContext( configurationNameLabel, AnLocale.getString("Configuration Name:")); configurationNameLabel.setDisplayedMnemonic( AnLocale.getString('g', "ExportSettingsConfigurationNameLabelMnemonic")); configurationNameLabel.setLabelFor(configurationNameTextField); AnUtility.setTTAndAccessibleContext( configurationNameTextField, configurationNameLabel.getText()); AnUtility.setTextAndAccessibleContext( defaultNameCheckBox, AnLocale.getString("Save as Default configuration")); defaultNameCheckBox.setMnemonic(AnLocale.getString('S', "ExportSettingsSaveCheckboxMN")); defaultNameCheckBox.setSelected(false); defaultNameCheckBoxActionPerformed(null); configurationNameTextField.getDocument().addDocumentListener(docListener); // AnUtility.setTextAndAccessibleContext(fullPathLabel1, AnLocale.getString("Full // Path:")); // AnUtility.setTTAndAccessibleContext(fullPathTextField, fullPathLabel1.getText()); linePanel.setBorder( BorderFactory.createMatteBorder(1, 0, 0, 0, AnEnvironment.ABOUT_BOX_BORDER_COLOR)); updateRadioButtons(); updateStates(); } public String getConfigurationPath() { return fullPathTextField.getText(); } public List getWhat() { List what = new ArrayList(); if (viewsCheckBox.isSelected()) { what.add(UserPref.What.VIEWS); } if (metricsCheckBox.isSelected()) { what.add(UserPref.What.METRICS); } if (timelineCheckBox.isSelected()) { what.add(UserPref.What.TIMELINE); } if (sourceDisassemblyCheckBox.isSelected()) { what.add(UserPref.What.SOURCEDISASSEMBLY); } if (callTreeCheckBox.isSelected()) { what.add(UserPref.What.CALLTREE); } if (formatsCheckBox.isSelected()) { what.add(UserPref.What.FORMATS); } if (searchPathCheckBox.isSelected()) { what.add(UserPref.What.SEARCHPATH); } if (pathmapCheckBox.isSelected()) { what.add(UserPref.What.PATHMAP); } if (functionColorsCheckBox.isSelected()) { what.add(UserPref.What.FUNCTIONCOLORS); } if (libraryClassVisibilityCheckBox.isSelected()) { what.add(UserPref.What.LIBRARYVISIBILITY); } if (miscCheckBox.isSelected()) { what.add(UserPref.What.MISC); } return what; } private class RadioButtonActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { updateRadioButtons(); updateStates(); } } private class AllCheckBoxActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { boolean sel = allCheckBox.isSelected(); for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled()) { checkBox.setSelected(sel); } } String errorText = checkCkeckBoxesStates(); handleErrorWarning(errorText, null); } } private class CheckBoxActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { updateStates(); } } class DocListener implements DocumentListener { @Override public void changedUpdate(DocumentEvent e) { updateStates(); } @Override public void insertUpdate(DocumentEvent e) { updateStates(); } @Override public void removeUpdate(DocumentEvent e) { updateStates(); } } private void updateRadioButtons() { String FS = ""; String remoteFS = ""; String localFS = ""; if (Analyzer.getInstance().isRemote()) { remoteFS = " (" + AnLocale.getString("remote") + ")"; localFS = " (" + AnLocale.getString("local") + ")"; } if (experimentFolderRadioButton.isSelected()) { String experiment = AnUtility.toFullPath(AnWindow.getInstance().getExperimentGroups()[0][0]); pathTextField.setText(UserPref.getConfigurationDirPath(experiment)); FS = remoteFS; } else if (experimetParentRadioButton.isSelected()) { String experiment = AnUtility.toFullPath(AnWindow.getInstance().getExperimentGroups()[0][0]); String parentDir = AnUtility.dirname(experiment); pathTextField.setText(parentDir); FS = remoteFS; } else if (homeRadioButton.isSelected()) { pathTextField.setText(UserPref.getHomeConfigurationDirPath()); FS = localFS; } else if (otherRadioButton.isSelected()) { String last = UserPref.getInstance().getLastExportImportConfPath(); if (last != null) { pathTextField.setText(AnUtility.dirname(last)); } FS = remoteFS; } AnUtility.setTextAndAccessibleContext(locationLabel, AnLocale.getString("Location") + FS + ":"); AnUtility.setTTAndAccessibleContext(pathTextField, locationLabel.getText()); AnUtility.setTextAndAccessibleContext( fullPathLabel1, AnLocale.getString("Full Path") + FS + ":"); AnUtility.setTTAndAccessibleContext(fullPathTextField, fullPathLabel1.getText()); } private void updateStates() { pathTextField.getDocument().removeDocumentListener(docListener); pathTextField.setEnabled(otherRadioButton.isSelected()); browseButton.setEnabled(otherRadioButton.isSelected()); configurationNameTextField.setEnabled(!defaultNameCheckBox.isSelected()); if (pathTextField.isEnabled()) { pathTextField.getDocument().addDocumentListener(docListener); } fullPathTextField.setText( pathTextField.getText() + "/" + configurationNameTextField.getText() + UserPref.configurationSuffix); String errorText = null; String warningText = null; if (configurationNameTextField.getText().length() == 0) { errorText = AnLocale.getString("A configuration must have a name"); } else { errorText = checkCkeckBoxesStates(); if (errorText == null) { String confPath = fullPathTextField.getText(); boolean homeDefaultConfiguration = confPath.startsWith(UserPref.getAnalyzerDirPath()); File confFile = homeDefaultConfiguration ? new File(confPath) : new AnFile(confPath); if (confFile.exists()) { warningText = AnLocale.getString("Configuration already exists"); } } } allCheckBox.setSelected(false); if (errorText == null) { boolean allCheckBoxSelectedState = true; for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled() && !checkBox.isSelected()) { allCheckBoxSelectedState = false; break; } } allCheckBox.setSelected(allCheckBoxSelectedState); } else { allCheckBox.setSelected(false); } handleErrorWarning(errorText, warningText); } private void handleErrorWarning(String errorText, String warningText) { if (errorText != null) { dialog.getOKButton().setEnabled(false); setError(errorText); } else if (warningText != null) { dialog.getOKButton().setEnabled(true); setWarning(warningText); } else { dialog.getOKButton().setEnabled(true); resetErrorWarning(); } } private String checkCkeckBoxesStates() { String errorText = null; if (errorText == null) { if (!anyCheckBoxesSelected()) { errorText = AnLocale.getString("At least one option needs to be selected"); } } if (errorText == null) { boolean allCheckBoxSelectedState = true; for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled() && !checkBox.isSelected()) { allCheckBoxSelectedState = false; break; } } allCheckBox.setSelected(allCheckBoxSelectedState); } else { allCheckBox.setSelected(false); } return errorText; } private boolean anyCheckBoxesSelected() { boolean ret = false; for (JCheckBox checkBox : checkBoxes) { if (checkBox.isSelected()) { ret = true; break; } } return ret; } private void setError(String text) { errorLabel.setForeground(errorColor); errorLabel.setText(AnLocale.getString("Error: ") + text); } private void setWarning(String text) { errorLabel.setForeground(warningColor); errorLabel.setText(AnLocale.getString("Warning: ") + text); } private void resetErrorWarning() { errorLabel.setText(" "); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; infoLabel = new javax.swing.JLabel(); whatLabel = new javax.swing.JLabel(); viewsCheckBox = new javax.swing.JCheckBox(); metricsCheckBox = new javax.swing.JCheckBox(); timelineCheckBox = new javax.swing.JCheckBox(); sourceDisassemblyCheckBox = new javax.swing.JCheckBox(); callTreeCheckBox = new javax.swing.JCheckBox(); formatsCheckBox = new javax.swing.JCheckBox(); searchPathCheckBox = new javax.swing.JCheckBox(); pathmapCheckBox = new javax.swing.JCheckBox(); functionColorsCheckBox = new javax.swing.JCheckBox(); libraryClassVisibilityCheckBox = new javax.swing.JCheckBox(); miscCheckBox = new javax.swing.JCheckBox(); locationOptionsLabel = new javax.swing.JLabel(); experimentFolderRadioButton = new javax.swing.JRadioButton(); experimetParentRadioButton = new javax.swing.JRadioButton(); homeRadioButton = new javax.swing.JRadioButton(); otherRadioButton = new javax.swing.JRadioButton(); pathTextField = new javax.swing.JTextField(); browseButton = new javax.swing.JButton(); locationLabel = new javax.swing.JLabel(); namePanel = new javax.swing.JPanel(); configurationNameLabel = new javax.swing.JLabel(); configurationNameTextField = new javax.swing.JTextField(); defaultNameCheckBox = new javax.swing.JCheckBox(); fullPathPanel = new javax.swing.JPanel(); fullPathLabel1 = new javax.swing.JLabel(); fullPathTextField = new javax.swing.JTextField(); errorLabel = new javax.swing.JLabel(); allCheckBox = new javax.swing.JCheckBox(); linePanel = new javax.swing.JPanel(); setLayout(new java.awt.GridBagLayout()); infoLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); add(infoLabel, gridBagConstraints); whatLabel.setText("Options...:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(16, 0, 0, 0); add(whatLabel, gridBagConstraints); viewsCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(viewsCheckBox, gridBagConstraints); metricsCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 6; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(metricsCheckBox, gridBagConstraints); timelineCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 7; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(timelineCheckBox, gridBagConstraints); sourceDisassemblyCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 8; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(sourceDisassemblyCheckBox, gridBagConstraints); callTreeCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 9; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(callTreeCheckBox, gridBagConstraints); formatsCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 10; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(formatsCheckBox, gridBagConstraints); searchPathCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 11; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(searchPathCheckBox, gridBagConstraints); pathmapCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 12; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(pathmapCheckBox, gridBagConstraints); functionColorsCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 13; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(functionColorsCheckBox, gridBagConstraints); libraryClassVisibilityCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 14; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(libraryClassVisibilityCheckBox, gridBagConstraints); miscCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 15; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(miscCheckBox, gridBagConstraints); locationOptionsLabel.setText("Where...:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 16; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(16, 0, 0, 0); add(locationOptionsLabel, gridBagConstraints); experimentFolderRadioButton.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 17; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(experimentFolderRadioButton, gridBagConstraints); experimetParentRadioButton.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 18; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(experimetParentRadioButton, gridBagConstraints); homeRadioButton.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 19; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(homeRadioButton, gridBagConstraints); otherRadioButton.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 20; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(otherRadioButton, gridBagConstraints); pathTextField.setColumns(70); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 22; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; add(pathTextField, gridBagConstraints); browseButton.setText("..."); browseButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { browseButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 22; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(browseButton, gridBagConstraints); locationLabel.setText("Location:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 21; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; add(locationLabel, gridBagConstraints); namePanel.setOpaque(false); namePanel.setLayout(new java.awt.GridBagLayout()); configurationNameLabel.setText("Configuration Name:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 13; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; namePanel.add(configurationNameLabel, gridBagConstraints); configurationNameTextField.setColumns(30); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 13; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); namePanel.add(configurationNameTextField, gridBagConstraints); defaultNameCheckBox.setText("Save as..."); defaultNameCheckBox.setOpaque(false); defaultNameCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { defaultNameCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 14; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; namePanel.add(defaultNameCheckBox, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 23; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(16, 0, 0, 0); add(namePanel, gridBagConstraints); fullPathPanel.setOpaque(false); fullPathPanel.setLayout(new java.awt.GridBagLayout()); fullPathLabel1.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; fullPathPanel.add(fullPathLabel1, gridBagConstraints); fullPathTextField.setEditable(false); fullPathTextField.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; fullPathPanel.add(fullPathTextField, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 24; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(16, 0, 0, 0); add(fullPathPanel, gridBagConstraints); errorLabel.setForeground(new java.awt.Color(255, 0, 51)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 25; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(16, 0, 0, 0); add(errorLabel, gridBagConstraints); allCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(allCheckBox, gridBagConstraints); linePanel.setMaximumSize(new java.awt.Dimension(20, 20)); linePanel.setMinimumSize(new java.awt.Dimension(10, 30)); linePanel.setOpaque(false); linePanel.setPreferredSize(new java.awt.Dimension(200, 2)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(3, 0, 0, 0); add(linePanel, gridBagConstraints); } // //GEN-END:initComponents private void browseButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_browseButtonActionPerformed String feed = pathTextField.getText(); File feedFile = new File(feed); if (!feedFile.exists() || !feedFile.isDirectory()) { feedFile = null; } JFileChooser fileChooser = AnWindow.getInstance().getAnChooser("", AnChooser.DIR_CHOOSER, null); if (feedFile != null) { fileChooser.setCurrentDirectory(feedFile); } fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { String filePath = fileChooser.getSelectedFile().getAbsolutePath(); pathTextField.setText(filePath); } updateStates(); } // GEN-LAST:event_browseButtonActionPerformed private void defaultNameCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_defaultNameCheckBoxActionPerformed if (defaultNameCheckBox.isSelected()) { configurationNameTextField.setText(UserPref.configDefaultName); } else { configurationNameTextField.setText("name"); } updateStates(); } // GEN-LAST:event_defaultNameCheckBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox allCheckBox; private javax.swing.JButton browseButton; private javax.swing.JCheckBox callTreeCheckBox; private javax.swing.JLabel configurationNameLabel; private javax.swing.JTextField configurationNameTextField; private javax.swing.JCheckBox defaultNameCheckBox; private javax.swing.JLabel errorLabel; private javax.swing.JRadioButton experimentFolderRadioButton; private javax.swing.JRadioButton experimetParentRadioButton; private javax.swing.JCheckBox formatsCheckBox; private javax.swing.JLabel fullPathLabel1; private javax.swing.JPanel fullPathPanel; private javax.swing.JTextField fullPathTextField; private javax.swing.JCheckBox functionColorsCheckBox; private javax.swing.JRadioButton homeRadioButton; private javax.swing.JLabel infoLabel; private javax.swing.JCheckBox libraryClassVisibilityCheckBox; private javax.swing.JPanel linePanel; private javax.swing.JLabel locationLabel; private javax.swing.JLabel locationOptionsLabel; private javax.swing.JCheckBox metricsCheckBox; private javax.swing.JCheckBox miscCheckBox; private javax.swing.JPanel namePanel; private javax.swing.JRadioButton otherRadioButton; private javax.swing.JTextField pathTextField; private javax.swing.JCheckBox pathmapCheckBox; private javax.swing.JCheckBox searchPathCheckBox; private javax.swing.JCheckBox sourceDisassemblyCheckBox; private javax.swing.JCheckBox timelineCheckBox; private javax.swing.JCheckBox viewsCheckBox; private javax.swing.JLabel whatLabel; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/settings/CallTreePanel.form0000644000175000017500000000631114517772113021136 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/settings/FormatSetting.java0000644000175000017500000001240114517772113021224 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; public class FormatSetting extends Setting { private static final Style defaultStyle = Style.LONG; private static final boolean defaultAppendSoName = false; public enum Style { LONG(1, AnLocale.getString("Long")), SHORT(2, AnLocale.getString("Short")), MANGLED(3, AnLocale.getString("Mangled")); private final int value; private final String name; private Style(int value, String name) { this.value = value; this.name = name; } public int value() { return value; } public static Style fromValue(int val) { for (Style rt : Style.values()) { if (rt.value() == val) { return rt; } } return null; } @Override public String toString() { return name; } }; public class Format { public Style style = defaultStyle; public boolean appendSOName = defaultAppendSoName; } private Format format = new Format(); public static Style getDefaultStyle() { return defaultStyle; } public static boolean getDefaultAppendSoName() { return defaultAppendSoName; } public FormatSetting() {} public FormatSetting(Style style, boolean appendSOName) { format.style = style; format.appendSOName = appendSOName; } public void init(Object originalSource, Style style, boolean appendSoName) { format.style = style; format.appendSOName = appendSoName; setNameFormatIPC(format.style.value(), format.appendSOName); // IPC fireChangeEvent(originalSource, this); } public void set(Object originalSource, Style style, boolean appendSoName) { if (style != format.style || appendSoName != format.appendSOName) { FormatSetting newFormatSetting = new FormatSetting(style, appendSoName); setValueAndFireChangeEvent(originalSource, this, newFormatSetting); } } public Style getStyle() { return format.style; } public boolean getAppendSoName() { return format.appendSOName; } public void setAppendSoNames(Object originalSource, boolean appendSoName) { if (appendSoName != format.appendSOName) { setValueAndFireChangeEvent(originalSource, this, format); } } @Override Type getType() { return AnSettingChangeEvent.Type.FORMAT; } @Override Object getValue() { return format; } @Override void setValue(Object newValue) { FormatSetting newFormatSetting = (FormatSetting) newValue; format.style = newFormatSetting.format.style; format.appendSOName = newFormatSetting.format.appendSOName; setNameFormatIPC(format.style.value(), format.appendSOName); // IPC } public static int getNameFormatIPC() { synchronized (IPC.lock) { AnWindow.getInstance().IPC().send("getNameFormat"); AnWindow.getInstance().IPC().send(0); return AnWindow.getInstance().IPC().recvInt(); } } /** * Send request to get Name Format. Non-blocking IPC call. Caller should call ipcResult.getInt() * to get the result * * @return IPCResult */ public static IPCResult SendRequest_getNameFormatIPC() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getNameFormat"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // int result = ipcResult.getInt() // blocking return ipcResult; } public static boolean getSoNameIPC() { synchronized (IPC.lock) { AnWindow.getInstance().IPC().send("getSoName"); AnWindow.getInstance().IPC().send(0); return AnWindow.getInstance().IPC().recvBoolean(); } } /** * Send request to get SoName. Non-blocking IPC call. Caller should call ipcResult.getBoolean() to * get the result * * @return IPCResult */ public static IPCResult SendRequest_getSoNameIPC() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getSoName"); ipcHandle.append(0); IPCResult ipcResult = ipcHandle.sendRequest(); // boolean result = ipcResult.getBoolean() // blocking return ipcResult; } private static void setNameFormatIPC(final int set, final boolean so_name) { synchronized (IPC.lock) { AnWindow.getInstance().IPC().send("setNameFormat"); AnWindow.getInstance().IPC().send(0); AnWindow.getInstance().IPC().send(set); AnWindow.getInstance().IPC().send(so_name); AnWindow.getInstance().IPC().recvString(); // synchronize } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/ImportSettingsPanel.java0000644000175000017500000006211514517772113022420 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnFile; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.persistence.UserPrefPersistence; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JCheckBox; import javax.swing.JFileChooser; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.filechooser.FileFilter; /** * @author tpreisle */ public class ImportSettingsPanel extends javax.swing.JPanel { private static final Color errorColor = Color.red; private static final Color warningColor = new Color(255, 150, 0); private final ImportSettingsDialog dialog; private final DocListener docListener = new DocListener(); private UserPref userPref; private List checkBoxes = new ArrayList(); /** Creates new form SaveSettingsPanel */ public ImportSettingsPanel(ImportSettingsDialog dialog) { this.dialog = dialog; initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); ActionListener checkBoxActionListener = new CheckBoxActionListener(); AnUtility.setTextAndAccessibleContext( infoLabel, AnLocale.getString("Import settings from a saved configuration file.")); AnUtility.setTextAndAccessibleContext(whatLabel, AnLocale.getString("Options to import:")); whatLabel.setDisplayedMnemonic( AnLocale.getString('O', "ExportSettingsOptionsToExportLabelMnemonics")); whatLabel.setLabelFor(viewsCheckBox); checkBoxes.add(metricsCheckBox); checkBoxes.add(viewsCheckBox); checkBoxes.add(formatsCheckBox); checkBoxes.add(callTreeCheckBox); checkBoxes.add(sourceDisassemblyCheckBox); checkBoxes.add(functionColorsCheckBox); checkBoxes.add(timelineCheckBox); checkBoxes.add(searchPathCheckBox); checkBoxes.add(pathmapCheckBox); checkBoxes.add(libraryClassVisibilityCheckBox); checkBoxes.add(miscCheckBox); metricsCheckBox.setText(AnLocale.getString("Metrics")); viewsCheckBox.setText(AnLocale.getString("Views")); formatsCheckBox.setText(AnLocale.getString("Formats")); callTreeCheckBox.setText(AnLocale.getString("Call Tree")); sourceDisassemblyCheckBox.setText(AnLocale.getString("Source/Disassembly")); functionColorsCheckBox.setText(AnLocale.getString("Function Colors")); timelineCheckBox.setText(AnLocale.getString("Timeline")); searchPathCheckBox.setText(AnLocale.getString("Search Path")); pathmapCheckBox.setText(AnLocale.getString("Pathmaps")); libraryClassVisibilityCheckBox.setText(AnLocale.getString("Library and Class Visibility")); miscCheckBox.setText(AnLocale.getString("Miscellaneous")); metricsCheckBox.setToolTipText( AnLocale.getString( "Selected metrics")); // getString("Selected metrics, order, and sort metric")); viewsCheckBox.setToolTipText(AnLocale.getString("Selected views and order")); formatsCheckBox.setToolTipText(AnLocale.getString("Formats settings")); callTreeCheckBox.setToolTipText(AnLocale.getString("Call Tree settings")); sourceDisassemblyCheckBox.setToolTipText(AnLocale.getString("Source/Disassembly settings")); functionColorsCheckBox.setToolTipText(AnLocale.getString("Function color settings")); timelineCheckBox.setToolTipText(AnLocale.getString("Timeline settings")); searchPathCheckBox.setToolTipText(AnLocale.getString("Search Path settings")); pathmapCheckBox.setToolTipText(AnLocale.getString("Pathmap settings")); libraryClassVisibilityCheckBox.setToolTipText( AnLocale.getString("Library and Class Visibility settings")); miscCheckBox.setToolTipText(AnLocale.getString("Find history, ...")); AnUtility.setTTAndAccessibleContext(allCheckBox, AnLocale.getString("Select all")); allCheckBox.addActionListener(new AllCheckBoxActionListener()); for (JCheckBox checkBox : checkBoxes) { checkBox.addActionListener(checkBoxActionListener); } AnUtility.setTextAndAccessibleContext(locationLabel, AnLocale.getString("Configuration File:")); locationLabel.setDisplayedMnemonic( AnLocale.getString('C', "ImportSettingsConfigurationFileMnemonic")); locationLabel.setLabelFor(pathTextField); browseButton.setToolTipText(AnLocale.getString("Browse for Location (ALT B)")); browseButton.setMnemonic(AnLocale.getString('B', "ExportBrowseButtonMnemonic")); if (UserPref.getInstance().getLastExportImportConfPath() != null) { pathTextField.setText(UserPref.getInstance().getLastExportImportConfPath()); } pathTextField.getDocument().addDocumentListener(docListener); linePanel.setBorder( BorderFactory.createMatteBorder(1, 0, 0, 0, AnEnvironment.ABOUT_BOX_BORDER_COLOR)); updateStates(); } public String getConfigurationPath() { return pathTextField.getText(); } public List getWhat() { List what = new ArrayList(); if (metricsCheckBox.isSelected()) { what.add(UserPref.What.METRICS); } if (formatsCheckBox.isSelected()) { what.add(UserPref.What.FORMATS); } if (viewsCheckBox.isSelected()) { what.add(UserPref.What.VIEWS); } if (callTreeCheckBox.isSelected()) { what.add(UserPref.What.CALLTREE); } if (sourceDisassemblyCheckBox.isSelected()) { what.add(UserPref.What.SOURCEDISASSEMBLY); } if (functionColorsCheckBox.isSelected()) { what.add(UserPref.What.FUNCTIONCOLORS); } if (miscCheckBox.isSelected()) { what.add(UserPref.What.MISC); } if (timelineCheckBox.isSelected()) { what.add(UserPref.What.TIMELINE); } if (libraryClassVisibilityCheckBox.isSelected()) { what.add(UserPref.What.LIBRARYVISIBILITY); } if (searchPathCheckBox.isSelected()) { what.add(UserPref.What.SEARCHPATH); } if (pathmapCheckBox.isSelected()) { what.add(UserPref.What.PATHMAP); } return what; } private class CheckBoxActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { String errorText = checkCkeckBoxesStates(); handleErrorWarning(errorText, null); } } private class AllCheckBoxActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { boolean sel = allCheckBox.isSelected(); for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled()) { checkBox.setSelected(sel); } } String errorText = checkCkeckBoxesStates(); handleErrorWarning(errorText, null); } } class DocListener implements DocumentListener { @Override public void changedUpdate(DocumentEvent e) { updateStates(); } @Override public void insertUpdate(DocumentEvent e) { updateStates(); } @Override public void removeUpdate(DocumentEvent e) { updateStates(); } } private void updateStates() { String errorText = null; String warningText = null; allCheckBox.setEnabled(false); allCheckBox.setSelected(false); for (JCheckBox checkBox : checkBoxes) { checkBox.setEnabled(false); checkBox.setSelected(false); } if (pathTextField.getText().length() == 0) { errorText = AnLocale.getString("Specify a configuration file to import settings from"); } else if (!pathTextField.getText().endsWith(UserPref.configurationSuffix)) { errorText = AnLocale.getString("File is not a configuration file"); } else if (!new AnFile(pathTextField.getText()).exists()) { errorText = AnLocale.getString("Configuration file doesn't exixts"); } if (errorText == null) { // Process config file and enable only available options. userPref = new UserPref(); String configFilePath = getConfigurationPath(); if (Analyzer.getInstance().isRemote()) { configFilePath = AnWindow.copyFromRemote(configFilePath); } new UserPrefPersistence().restoreSettings(configFilePath, userPref); if (userPref.getVersion() >= 10) { List whatList = userPref.getWhatList(); if (whatList.contains(UserPref.What.METRICS)) { metricsCheckBox.setEnabled(true); metricsCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.VIEWS)) { viewsCheckBox.setEnabled(true); viewsCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.FORMATS)) { formatsCheckBox.setEnabled(true); formatsCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.CALLTREE)) { callTreeCheckBox.setEnabled(true); callTreeCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.SOURCEDISASSEMBLY)) { sourceDisassemblyCheckBox.setEnabled(true); sourceDisassemblyCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.TIMELINE)) { timelineCheckBox.setEnabled(true); timelineCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.SEARCHPATH)) { searchPathCheckBox.setEnabled(true); searchPathCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.PATHMAP)) { pathmapCheckBox.setEnabled(true); pathmapCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.MISC)) { miscCheckBox.setEnabled(true); miscCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.LIBRARYVISIBILITY)) { libraryClassVisibilityCheckBox.setEnabled(true); libraryClassVisibilityCheckBox.setSelected(true); } if (whatList.contains(UserPref.What.FUNCTIONCOLORS)) { functionColorsCheckBox.setEnabled(true); functionColorsCheckBox.setSelected(true); } } else { userPref = null; errorText = AnLocale.getString( "Configuration file is an older version. Import from older version configuration" + " files is not supported."); } } if (errorText == null) { errorText = checkCkeckBoxesStates(); } handleErrorWarning(errorText, warningText); } private String checkCkeckBoxesStates() { String errorText = null; if (errorText == null) { if (!anyCheckBoxesSelected()) { errorText = AnLocale.getString("At least one option needs to be selected"); } } if (errorText == null) { boolean allCheckBoxSelectedState = true; for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled() && !checkBox.isSelected()) { allCheckBoxSelectedState = false; break; } } allCheckBox.setEnabled(true); allCheckBox.setSelected(allCheckBoxSelectedState); } else { allCheckBox.setSelected(false); } return errorText; } private void handleErrorWarning(String errorText, String warningText) { if (errorText == null) { boolean allCheckBoxSelectedState = true; for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled() && !checkBox.isSelected()) { allCheckBoxSelectedState = false; break; } } allCheckBox.setEnabled(true); allCheckBox.setSelected(allCheckBoxSelectedState); } else { allCheckBox.setSelected(false); } if (errorText != null) { dialog.getOKButton().setEnabled(false); setError(errorText); } else if (warningText != null) { dialog.getOKButton().setEnabled(true); setWarning(warningText); } else { dialog.getOKButton().setEnabled(true); resetErrorWarning(); } } private boolean anyCheckBoxesSelected() { boolean ret = false; for (JCheckBox checkBox : checkBoxes) { if (checkBox.isSelected()) { ret = true; break; } } return ret; } private void setError(String text) { errorLabel.setForeground(errorColor); errorLabel.setText(AnLocale.getString("Error: ") + text); } private void setWarning(String text) { errorLabel.setForeground(warningColor); errorLabel.setText(AnLocale.getString("Warning: ") + text); } private void resetErrorWarning() { errorLabel.setText(" "); } public UserPref getUserPref() { return userPref; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; infoLabel = new javax.swing.JLabel(); whatLabel = new javax.swing.JLabel(); allCheckBox = new javax.swing.JCheckBox(); linePanel = new javax.swing.JPanel(); viewsCheckBox = new javax.swing.JCheckBox(); metricsCheckBox = new javax.swing.JCheckBox(); timelineCheckBox = new javax.swing.JCheckBox(); sourceDisassemblyCheckBox = new javax.swing.JCheckBox(); callTreeCheckBox = new javax.swing.JCheckBox(); formatsCheckBox = new javax.swing.JCheckBox(); searchPathCheckBox = new javax.swing.JCheckBox(); pathmapCheckBox = new javax.swing.JCheckBox(); functionColorsCheckBox = new javax.swing.JCheckBox(); libraryClassVisibilityCheckBox = new javax.swing.JCheckBox(); miscCheckBox = new javax.swing.JCheckBox(); pathTextField = new javax.swing.JTextField(); browseButton = new javax.swing.JButton(); locationLabel = new javax.swing.JLabel(); errorLabel = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); infoLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); add(infoLabel, gridBagConstraints); whatLabel.setText("Options...:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(whatLabel, gridBagConstraints); allCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 7; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(allCheckBox, gridBagConstraints); linePanel.setMaximumSize(new java.awt.Dimension(20, 20)); linePanel.setMinimumSize(new java.awt.Dimension(10, 30)); linePanel.setOpaque(false); linePanel.setPreferredSize(new java.awt.Dimension(200, 2)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 8; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(3, 0, 0, 0); add(linePanel, gridBagConstraints); viewsCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 9; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(viewsCheckBox, gridBagConstraints); metricsCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 10; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(metricsCheckBox, gridBagConstraints); timelineCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 11; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(timelineCheckBox, gridBagConstraints); sourceDisassemblyCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 12; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(sourceDisassemblyCheckBox, gridBagConstraints); callTreeCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 13; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(callTreeCheckBox, gridBagConstraints); formatsCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 14; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(formatsCheckBox, gridBagConstraints); searchPathCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 15; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(searchPathCheckBox, gridBagConstraints); pathmapCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 16; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(pathmapCheckBox, gridBagConstraints); functionColorsCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 17; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(functionColorsCheckBox, gridBagConstraints); libraryClassVisibilityCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 18; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(libraryClassVisibilityCheckBox, gridBagConstraints); miscCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 19; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(miscCheckBox, gridBagConstraints); pathTextField.setColumns(70); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; add(pathTextField, gridBagConstraints); browseButton.setText("..."); browseButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { browseButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(browseButton, gridBagConstraints); locationLabel.setText("Location:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(locationLabel, gridBagConstraints); errorLabel.setForeground(new java.awt.Color(255, 0, 51)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 22; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(16, 0, 0, 0); add(errorLabel, gridBagConstraints); } // //GEN-END:initComponents private void browseButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_browseButtonActionPerformed String feed = pathTextField.getText(); File feedFile = null; if (feed.length() > 0) { feedFile = new File(feed).getParentFile(); if (feedFile != null && (!feedFile.exists() || !feedFile.isDirectory())) { feedFile = null; } } JFileChooser fileChooser = AnWindow.getInstance().getAnChooser("", AnChooser.DIR_FILE_CHOOSER, null); if (feedFile != null) { fileChooser.setCurrentDirectory(feedFile); } fileChooser.setFileFilter(new ConfFileFileFilter()); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { String filePath = fileChooser.getSelectedFile().getAbsolutePath(); pathTextField.setText(filePath); } updateStates(); } // GEN-LAST:event_browseButtonActionPerformed private class ConfFileFileFilter extends FileFilter { @Override public String getDescription() { return UserPref.configurationSuffix; } @Override public boolean accept(File f) { if (f.isDirectory()) { return true; } else if (f.getName().endsWith(UserPref.configurationSuffix)) { return true; } else { return false; } } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox allCheckBox; private javax.swing.JButton browseButton; private javax.swing.JCheckBox callTreeCheckBox; private javax.swing.JLabel errorLabel; private javax.swing.JCheckBox formatsCheckBox; private javax.swing.JCheckBox functionColorsCheckBox; private javax.swing.JLabel infoLabel; private javax.swing.JCheckBox libraryClassVisibilityCheckBox; private javax.swing.JPanel linePanel; private javax.swing.JLabel locationLabel; private javax.swing.JCheckBox metricsCheckBox; private javax.swing.JCheckBox miscCheckBox; private javax.swing.JTextField pathTextField; private javax.swing.JCheckBox pathmapCheckBox; private javax.swing.JCheckBox searchPathCheckBox; private javax.swing.JCheckBox sourceDisassemblyCheckBox; private javax.swing.JCheckBox timelineCheckBox; private javax.swing.JCheckBox viewsCheckBox; private javax.swing.JLabel whatLabel; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/settings/CallTreeSetting.java0000644000175000017500000000341314517772113021472 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; public class CallTreeSetting extends Setting { private static final int defaultThreshold = 1; private int threshold; public CallTreeSetting() { threshold = UserPref.getInstance().getCallStackThreshold(); } public boolean validValue(int value) { return value >= 0 && value <= 100; } public boolean setThreshold(Object originalSource, int newThreshold) { if (!validValue(newThreshold)) { return false; } if (newThreshold != threshold) { setValueAndFireChangeEvent(originalSource, this, newThreshold); } return true; } public int getThreshold() { return threshold; } public static int getDefaultThreshold() { return defaultThreshold; } @Override Type getType() { return AnSettingChangeEvent.Type.CALL_TREE; } @Override Object getValue() { return threshold; } @Override void setValue(Object newValue) { int newThreshold = ((Integer) newValue).intValue(); threshold = newThreshold; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/LibraryVisibilitySetting.java0000644000175000017500000001531714517772113023461 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; import java.util.ArrayList; import java.util.List; public class LibraryVisibilitySetting extends Setting { private List settings; // Complete list in original order public LibraryVisibilitySetting() {} public void set(Object originalSource, List newSettings) { boolean changed = false; for (int i = 0; i < settings.size(); i++) { Entry oldEntry = settings.get(i); Entry newEntry = newSettings.get(i); if (oldEntry.getState() != newEntry.getState()) { changed = true; break; } } if (changed) { setValueAndFireChangeEvent(originalSource, this, newSettings); } } public void setFromStrings(Object originalSource, List initStates) { List newSettings = new ArrayList(); for (Entry entry : settings) { newSettings.add(entry.copy()); } if (initStates != null && !initStates.isEmpty()) { for (String s : initStates) { int stateValue = new Integer(s.substring(0, 1)); String path = s.substring(2); for (Entry entry : newSettings) { if (entry.getPath().equals(path)) { entry.setState(stateValue); } } } } else { for (Entry entry : newSettings) { entry.setState(0); } } set(originalSource, newSettings); } public void init(Object originalSource, Object[] custom_object, List initStates) { if (custom_object == null) { return; } String[] names = (String[]) custom_object[0]; int[] states = (int[]) custom_object[1]; int[] indices = (int[]) custom_object[2]; String[] paths = (String[]) custom_object[3]; int[] java = (int[]) custom_object[4]; if (initStates != null && !initStates.isEmpty()) { for (String s : initStates) { int stateValue = new Integer(s.substring(0, 1)); String path = s.substring(2); for (int i = 0; i < paths.length; i++) { if (paths[i].equals(path)) { states[i] = stateValue; break; } } } setLoadObjectStateIPC(0, states); // IPC } settings = new ArrayList(); for (int i = 0; i < names.length; i++) { Entry entry = new Entry(names[i], paths[i], states[i], indices[i], java[i] == 1); settings.add(entry); } } public List get() { return settings; } @Override Type getType() { return AnSettingChangeEvent.Type.LIBRARY_VISIBILITY; } @Override Object getValue() { return settings; } @Override void setValue(Object newValue) { List newSettings = (List) newValue; settings = newSettings; int[] newStates = new int[settings.size()]; int i = 0; for (Entry entry : settings) { newStates[i++] = entry.getState(); } setLoadObjectStateIPC(0, newStates); // IPC } // For persistance public List getStates() { List list = new ArrayList(); for (Entry entry : settings) { if (entry.getState() != 0) { list.add("" + entry.getState() + ":" + entry.getPath()); } } return list; } public static class Entry { private String name; private String path; private int state; private int index; private boolean java; public Entry(String name, String path, int state, int index, boolean java) { this.name = name; this.path = path; this.state = state; this.index = index; this.java = java; } /** * @return the name */ public String getName() { return name; } /** * @return the path */ public String getPath() { return path; } /** * @return the state */ public int getState() { return state; } /** * @return the index */ public int getIndex() { return index; } /** * @param state the state to set */ public void setState(int state) { this.state = state; } public Entry copy() { return new Entry(name, path, state, index, isJava()); } /** * @return the java */ public boolean isJava() { return java; } } // Native methods from liber_dbe.so public static Object[] getLoadObjectListIPC(int w_id) { AnWindow m_window = AnWindow.getInstance(); synchronized (IPC.lock) { m_window.IPC().send("getLoadObjectList"); m_window.IPC().send(w_id); return (Object[]) m_window.IPC().recvObject(); } } /** * Send request to get Load Object List. Non-blocking IPC call. Caller should call * ipcResult.getObjects() to get the result * * @return IPCResult */ public static IPCResult getLoadObjectListIPCRequest(int w_id) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getLoadObjectList"); ipcHandle.append(w_id); IPCResult ipcResult = ipcHandle.sendRequest(); // Object[] result = ipcResult.getObjects() // blocking return ipcResult; } public static int[] getLoadObjectStateIPC(int w_id) { AnWindow m_window = AnWindow.getInstance(); synchronized (IPC.lock) { m_window.IPC().send("getLoadObjectState"); m_window.IPC().send(w_id); return (int[]) m_window.IPC().recvObject(); } } public static void setLoadObjectStateIPC(final int w_id, final int[] state) { AnWindow m_window = AnWindow.getInstance(); synchronized (IPC.lock) { m_window.IPC().send("setLoadObjectState"); m_window.IPC().send(w_id); m_window.IPC().send(state); m_window.IPC().recvString(); // synchronize } } public static void setLoadObjectDefaultsIPC(final int w_id) { AnWindow m_window = AnWindow.getInstance(); synchronized (IPC.lock) { m_window.IPC().send("setLoadObjectDefaults"); m_window.IPC().send(w_id); m_window.IPC().recvString(); // synchronize } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/PathmapsPanel.form0000644000175000017500000004312214517772113021221 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/settings/SearchPathSetting.java0000644000175000017500000000670514517772113022030 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; import java.util.ArrayList; import java.util.List; public class SearchPathSetting extends Setting { private String[] searchPath = new String[0]; // Default public SearchPathSetting() {} public void set(Object originalSource, String[] newSearch_path) { boolean changed = false; if (searchPath.length != newSearch_path.length) { changed = true; } else { for (int i = 0; i < searchPath.length; i++) { if (!searchPath[i].equals(newSearch_path[i])) { changed = true; break; } } } if (changed) { setValueAndFireChangeEvent(originalSource, this, newSearch_path); } } public void add(Object originalSource, String path) { String[] newSearchPath = new String[searchPath.length + 1]; for (int i = 0; i < searchPath.length; i++) { newSearchPath[i] = searchPath[i]; } newSearchPath[searchPath.length] = path; set(originalSource, newSearchPath); } public void init(Object originalSource, List searchPath) { String[] arr = searchPath.toArray(new String[searchPath.size()]); setValue(arr); fireChangeEvent(originalSource, searchPath); } public static List getDefaultSearchPath() { List list = new ArrayList(); list.add("$expts"); list.add("."); return list; } public static boolean isDefault(List list) { List def = getDefaultSearchPath(); boolean ret = true; if (def.size() != list.size()) { ret = false; } else { for (int i = 0; i < def.size(); i++) { if (!def.get(i).equals(list.get(i))) { ret = false; break; } } } return ret; } public List get() { List list = new ArrayList(); for (String s : searchPath) { list.add(s); } return list; } @Override Type getType() { return AnSettingChangeEvent.Type.SEARCH_PATH; } @Override Object getValue() { return searchPath; } @Override void setValue(Object newValue) { String[] newSearchPath = (String[]) newValue; searchPath = newSearchPath; setSearchPathIPC(searchPath); // IPC } public static String[] getSearchPathIPC() { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getSearchPath"); return (String[]) anWindow.IPC().recvObject(); } } private static void setSearchPathIPC(String[] path) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("setSearchPath"); anWindow.IPC().send(path); anWindow.IPC().recvString(); // synchronize } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/SearchPathPanel.java0000644000175000017500000005026314517772113021450 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnFile; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Component; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.DefaultListCellRenderer; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.event.ListSelectionEvent; public class SearchPathPanel extends javax.swing.JPanel { private static Color shadedBackground = new Color(246, 246, 246); private List data = new ArrayList(); private PMListSelectionListener fromListSelectionListener; private PMDocumentListener pmDocumentListener; private Settings settings; public SearchPathPanel(Settings settings) { this.settings = settings; initComponents(); setBorder(BorderFactory.createMatteBorder(12, 12, 12, 10, (Color) null)); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); AnUtility.setTextAndAccessibleContext(topLabel, AnLocale.getString("Search Path:")); AnUtility.setTextAndAccessibleContext(pathLabel, AnLocale.getString("Path:")); pathLabel.setDisplayedMnemonic(AnLocale.getString('P', "SearchPathPathLabelMnemonic")); pathLabel.setLabelFor(pathTextField); AnUtility.setTTAndAccessibleContext(pathTextField, AnLocale.getString("Search path")); appendButton.setText(AnLocale.getString("Append")); appendButton.setToolTipText(AnLocale.getString("Append the Search Path to the list")); appendButton.setMnemonic(AnLocale.getString('e', "SearchPathPanelAppend_MN")); updateButton.setText(AnLocale.getString("Update")); updateButton.setMnemonic(AnLocale.getString('t', "SearchPathPanelUpdate_MN")); updateButton.setToolTipText( AnLocale.getString("Update the selected search path with the changes")); upButton.setText(AnLocale.getString("Up")); upButton.setMnemonic(AnLocale.getString('u', "SearchPathPanelUp_MN")); upButton.setToolTipText(AnLocale.getString("Move the selected search path up")); downButton.setText(AnLocale.getString("Down")); downButton.setMnemonic(AnLocale.getString('d', "SearchPathPanelDown_MN")); downButton.setToolTipText(AnLocale.getString("Move theselected search path down")); removeButton.setText(AnLocale.getString("Remove")); removeButton.setMnemonic(AnLocale.getString('r', "SearchPathPanelRemove_MN")); removeButton.setToolTipText(AnLocale.getString("Remove the selected search path")); browseButton.setToolTipText(AnLocale.getString("Browse for Path (ALT B)")); browseButton.setMnemonic(AnLocale.getString('B', "SearchPathPanelBrowseButtonMN")); AnUtility.setTextAndAccessibleContext(listLabel, AnLocale.getString("Search Paths:")); listLabel.setDisplayedMnemonic(AnLocale.getString('S', "SearchPathSearchPathsLabelMnemonic")); listLabel.setLabelFor(list); listPanel.setBorder( BorderFactory.createLineBorder(AnEnvironment.NAVIGATION_PANEL_BORDER_COLOR, 1)); // scrollPane.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, // AnEnvironment.NAVIGATION_PANEL_BORDER_COLOR)); list.setCellRenderer(new LCR()); AnUtility.setTTAndAccessibleContext(list, AnLocale.getString("Search path list")); fromListSelectionListener = new PMListSelectionListener(); pmDocumentListener = new PMDocumentListener(); list.addListSelectionListener(fromListSelectionListener); pathTextField.getDocument().addDocumentListener(pmDocumentListener); updateStates(); } private class LCR extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JLabel label = (JLabel) super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus); // To change body of generated methods, choose Tools | Templates. label.setText(" " + label.getText()); if (index % 2 == 1 && !isSelected) { label.setBackground(shadedBackground); } return label; } } private void refreshPanel(int selectedIndex) { list.setListData(data.toArray()); // appendButton.setText("dsa"); // appendButton.validate(); // appendButton.repaint(); if (data.size() == 0) { return; } if (selectedIndex >= 0 && selectedIndex <= data.size()) { list.setSelectedIndex(selectedIndex); list.ensureIndexIsVisible(selectedIndex); } } private void madeChanges() { settings.setMessageAreaVisible(true); settings.stateChanged(null); } /** Called when there are changes to pathmaps settings */ public void updateGUI() { final int size; int i; data.clear(); List searchPath = AnWindow.getInstance().getSettings().getSearchPathSetting().get(); size = searchPath.size(); for (i = 0; i < size; i++) { data.add(searchPath.get(i)); } list.setListData(data.toArray()); if (size == 0) { return; } list.setSelectedIndex(0); list.ensureIndexIsVisible(0); refreshPanel(0); } public void checkSearchPathChanged(Object originalSource) { String[] searchPath = data.toArray(new String[data.size()]); AnWindow.getInstance().getSettings().getSearchPathSetting().set(originalSource, searchPath); } class PMDocumentListener implements DocumentListener { @Override public void removeUpdate(DocumentEvent e) { updateStates(); } @Override public void insertUpdate(DocumentEvent e) { updateStates(); } @Override public void changedUpdate(DocumentEvent e) { updateStates(); } } class PMListSelectionListener implements javax.swing.event.ListSelectionListener { @Override public void valueChanged(ListSelectionEvent event) { if (event.getValueIsAdjusting()) { return; } pathTextField.setText((String) list.getSelectedValue()); updateStates(); } } private void updateStates() { appendButton.setEnabled(false); updateButton.setEnabled(false); upButton.setEnabled(false); downButton.setEnabled(false); removeButton.setEnabled(false); if (data != null && data.size() > 0) { if (list.getSelectedIndex() >= 0) { removeButton.setEnabled(true); } if (list.getSelectedIndex() > 0) { upButton.setEnabled(true); } if (list.getSelectedIndex() < data.size() - 1) { downButton.setEnabled(true); } } if (pathTextField.getText().length() > 0) { appendButton.setEnabled(true); if (data != null && data.size() > 0) { int index = list.getSelectedIndex(); if (index >= 0) { String from = data.get(index); if (!from.equals(pathTextField.getText())) { updateButton.setEnabled(true); } } } } } private String browse(String feed) { String filePath = null; if (!Analyzer.getInstance().isRemote()) { // Local File feedFile = new File(feed); if (!feedFile.exists()) { feedFile = null; } JFileChooser fileChooser = new JFileChooser(); // Always local file chooser fileChooser.setDialogTitle(AnLocale.getString("From path")); if (feedFile != null) { fileChooser.setCurrentDirectory(feedFile); } fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { filePath = fileChooser.getSelectedFile().getAbsolutePath(); } } else { // Remote AnFile feedFile = new AnFile(feed); if (!feedFile.exists()) { feedFile = null; } AnChooser fileChooser = AnWindow.getInstance() .getAnChooser(AnLocale.getString("To path"), AnChooser.DIR_FILE_CHOOSER, feed); // JFileChooser fileChooser = new JFileChooser(); // Always local file chooser if (feedFile != null) { fileChooser.setCurrentDirectory(feedFile); } fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { filePath = fileChooser.getSelectedFile().getAbsolutePath(); } } return filePath; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; topLabel = new javax.swing.JLabel(); pathLabel = new javax.swing.JLabel(); pathTextField = new javax.swing.JTextField(); browseButton = new javax.swing.JButton(); listLabel = new javax.swing.JLabel(); listPanel = new javax.swing.JPanel(); listPanelInner = new javax.swing.JPanel(); scrollPane = new javax.swing.JScrollPane(); list = new javax.swing.JList(); topButtonPanel = new javax.swing.JPanel(); appendButton = new javax.swing.JButton(); updateButton = new javax.swing.JButton(); buttomButtonPanel = new javax.swing.JPanel(); upButton = new javax.swing.JButton(); downButton = new javax.swing.JButton(); removeButton = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); topLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; add(topLabel, gridBagConstraints); pathLabel.setText("From:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(pathLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); add(pathTextField, gridBagConstraints); browseButton.setText("..."); browseButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { browseButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); add(browseButton, gridBagConstraints); listLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(listLabel, gridBagConstraints); listPanel.setLayout(new java.awt.GridBagLayout()); listPanelInner.setLayout(new java.awt.GridBagLayout()); scrollPane.setBorder(null); scrollPane.setViewportView(list); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 0.5; gridBagConstraints.weighty = 1.0; listPanelInner.add(scrollPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; listPanel.add(listPanelInner, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(listPanel, gridBagConstraints); topButtonPanel.setLayout(new java.awt.GridBagLayout()); appendButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { appendButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; topButtonPanel.add(appendButton, gridBagConstraints); updateButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { updateButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); topButtonPanel.add(updateButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 1; gridBagConstraints.gridheight = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 0); add(topButtonPanel, gridBagConstraints); buttomButtonPanel.setLayout(new java.awt.GridBagLayout()); upButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { upButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; buttomButtonPanel.add(upButton, gridBagConstraints); downButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { downButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); buttomButtonPanel.add(downButton, gridBagConstraints); removeButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { removeButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); buttomButtonPanel.add(removeButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 0); add(buttomButtonPanel, gridBagConstraints); } // //GEN-END:initComponents private void appendButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_appendButtonActionPerformed data.add(pathTextField.getText()); refreshPanel(data.size() - 1); madeChanges(); } // GEN-LAST:event_appendButtonActionPerformed private void updateButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_updateButtonActionPerformed int index = list.getSelectedIndex(); if (index >= 0) { data.remove(index); data.add(index, pathTextField.getText()); refreshPanel(index); madeChanges(); } } // GEN-LAST:event_updateButtonActionPerformed private void removeButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_removeButtonActionPerformed int index = list.getSelectedIndex(); if (index >= 0) { data.remove(index); if (index < data.size()) { refreshPanel(index); } else { refreshPanel(index - 1); } madeChanges(); } } // GEN-LAST:event_removeButtonActionPerformed private void upButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_upButtonActionPerformed int index = list.getSelectedIndex(); if (index > 0) { String from = data.get(index); data.remove(index); data.add(index - 1, from); refreshPanel(index - 1); madeChanges(); } } // GEN-LAST:event_upButtonActionPerformed private void downButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_downButtonActionPerformed int index = list.getSelectedIndex(); if (index < data.size()) { String from = data.get(index); data.remove(index); data.add(index + 1, from); refreshPanel(index + 1); madeChanges(); } } // GEN-LAST:event_downButtonActionPerformed private void browseButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_browseButtonActionPerformed String feed = pathTextField.getText(); String res = browse(feed); pathTextField.setText(res); } // GEN-LAST:event_browseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton appendButton; private javax.swing.JButton browseButton; private javax.swing.JPanel buttomButtonPanel; private javax.swing.JButton downButton; private javax.swing.JList list; private javax.swing.JLabel listLabel; private javax.swing.JPanel listPanel; private javax.swing.JPanel listPanelInner; private javax.swing.JLabel pathLabel; private javax.swing.JTextField pathTextField; private javax.swing.JButton removeButton; private javax.swing.JScrollPane scrollPane; private javax.swing.JPanel topButtonPanel; private javax.swing.JLabel topLabel; private javax.swing.JButton upButton; private javax.swing.JButton updateButton; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/settings/ExportSettingsDialog.java0000644000175000017500000000511014517772113022557 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import static org.gprofng.mpmt.AnWindow.copyToRemote; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnDialog2; import java.awt.Frame; import java.util.List; public class ExportSettingsDialog extends AnDialog2 { private ExportSettingsPanel saveSettingsPanel; public ExportSettingsDialog(Frame owner) { super(owner, owner, AnLocale.getString("Export Settings")); saveSettingsPanel = new ExportSettingsPanel(this); setCustomPanel(saveSettingsPanel); setHelpTag(AnVariable.HELP_ExportSettings); getOKButton().setText(AnLocale.getString("Export")); // getOKButton().setMnemonic(AnLocale.getString('x', "EXPORT_SETTINGS_DIALOG_SAVE_MN")); getOKButton().setToolTipText(AnLocale.getString("Export selected settings")); // getHelpButton().setEnabled(false); } @Override protected void setStatus(Status status) { super.setStatus(status); if (status == Status.OK) { String configurationPath = saveSettingsPanel.getConfigurationPath(); List what = saveSettingsPanel.getWhat(); String localPath = configurationPath; boolean homeDefaultConfiguration = configurationPath.startsWith(UserPref.getAnalyzerDirPath()); if (Analyzer.getInstance().isRemote() && !homeDefaultConfiguration) { localPath = AnWindow.tempFile().getAbsolutePath(); } UserPref.getInstance().save(localPath, what); if (Analyzer.getInstance().isRemote() && !homeDefaultConfiguration) { int res = copyToRemote(localPath, configurationPath); if (res < 0) { System.err.println("SaveSettingsDialog:copyToRemote failed: " + res); } } UserPref.getInstance().setLastExportImportConfPath(configurationPath); } } } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricsPanel.java0000644000175000017500000012275714517772113021044 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.AnCheckBox; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; /** * @author tpreisle */ public class MetricsPanel extends javax.swing.JPanel { private int gridY = 0; private int maxMetricNameLengthInPixels = 0; private HashMap metricHashMap = new HashMap(); private List showCheckBoxes; private List eTimeCheckBoxes; private List eValueCheckBoxes; private List ePercentCheckBoxes; private List iTimeCheckBoxes; private List iValueCheckBoxes; private List iPercentCheckBoxes; private JCheckBox allShowCheckBox; private JCheckBox eAllPercentCheckBox; private JCheckBox eAllTimeCheckBox; private JCheckBox eAllValueCheckBox; private JCheckBox iAllPercentCheckBox; private JCheckBox iAllTimeCheckBox; private JCheckBox iAllValueCheckBox; /** Creates new form MetricsPanel */ public MetricsPanel() { initComponents(); setPreferredSize(new Dimension(850, 550)); } private void setTopLabelAttr(JLabel label) { label.setFont(showLabel1.getFont().deriveFont(Font.BOLD)); label.setOpaque(true); label.setBackground(new Color(225, 225, 225)); label.setBorder(BorderFactory.createEmptyBorder(0, 6, 0, 6)); } private void initComponents2() { setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); innerPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); scrollPane.setBorder( BorderFactory.createMatteBorder(1, 1, 1, 1, AnEnvironment.SCROLLBAR_BORDER_COLOR)); setTopLabelAttr(showLabel1); setTopLabelAttr(exclusiveLabel); setTopLabelAttr(inclusiveLabel); // showLabel1.setOpaque(true); AnUtility.setTextAndAccessibleContext(showLabel1, AnLocale.getString("Show in Views")); AnUtility.setTextAndAccessibleContext(exclusiveLabel, AnLocale.getString("EXCLUSIVE")); AnUtility.setTextAndAccessibleContext(inclusiveLabel, AnLocale.getString("INCLUSIVE")); eTimeLabel.setText(null); eTimeLabel.setIcon(AnUtility.timeIcon); AnUtility.setTTAndAccessibleContext(eTimeLabel, AnLocale.getString("Time")); eValueLabel.setText(null); eValueLabel.setIcon(AnUtility.numberIcon); AnUtility.setTTAndAccessibleContext(eValueLabel, AnLocale.getString("Value")); ePercentLabel.setText(null); ePercentLabel.setIcon(AnUtility.percentIcon); AnUtility.setTTAndAccessibleContext(ePercentLabel, AnLocale.getString("Percent")); iTimeLabel.setText(null); iTimeLabel.setIcon(AnUtility.timeIcon); AnUtility.setTTAndAccessibleContext(iTimeLabel, AnLocale.getString("Time")); iValueLabel.setText(null); iValueLabel.setIcon(AnUtility.numberIcon); AnUtility.setTTAndAccessibleContext(iValueLabel, AnLocale.getString("Value")); iPercentLabel.setText(null); iPercentLabel.setIcon(AnUtility.percentIcon); AnUtility.setTTAndAccessibleContext(iPercentLabel, AnLocale.getString("Percent")); hotButton.setText(AnLocale.getString("Hot")); hotButton.setToolTipText( AnLocale.getString( "Select only metrics with the highest activity levels (marked check boxes)")); hotButton.setMnemonic(AnLocale.getString('t', "SettingsMetricsHotButtonMN")); hotButton.setMargin(new Insets(0, 4, 0, 4)); resetButton.setText(AnLocale.getString("Reset")); resetButton.setToolTipText(AnLocale.getString("Select the default set of metrics")); resetButton.setMnemonic(AnLocale.getString('R', "SettingsMetricsResetButtonMN")); resetButton.setMargin(new Insets(0, 4, 0, 4)); clearAllButton.setText(AnLocale.getString("Clear All")); clearAllButton.setToolTipText(AnLocale.getString("Deselect all metrics")); clearAllButton.setMnemonic(AnLocale.getString('c', "SettingsMetricsClearAllButtonMN")); clearAllButton.setMargin(new Insets(0, 4, 0, 4)); allShowCheckBox = new AnCheckBox(); AnUtility.setTTAndAccessibleContext(allShowCheckBox, AnLocale.getString("Show all metrics")); eAllTimeCheckBox = new AnCheckBox(); AnUtility.setTTAndAccessibleContext(eAllTimeCheckBox, AnLocale.getString("All EXCLUSIVE time")); eAllValueCheckBox = new AnCheckBox(); AnUtility.setTTAndAccessibleContext( eAllValueCheckBox, AnLocale.getString("All EXCLUSIVE value")); eAllPercentCheckBox = new AnCheckBox(); AnUtility.setTTAndAccessibleContext( eAllPercentCheckBox, AnLocale.getString("All EXCLUSIVE percent")); iAllTimeCheckBox = new AnCheckBox(); AnUtility.setTTAndAccessibleContext(iAllTimeCheckBox, AnLocale.getString("All INCLUSIVE time")); iAllValueCheckBox = new AnCheckBox(); AnUtility.setTTAndAccessibleContext( iAllValueCheckBox, AnLocale.getString("All INCLUSIVE value")); iAllPercentCheckBox = new AnCheckBox(); AnUtility.setTTAndAccessibleContext( iAllPercentCheckBox, AnLocale.getString("All INCLUSIVE percent")); GridBagConstraints gridBagConstraints; gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 3; gridBagConstraints.insets = new Insets(0, 12, 0, 0); innerPanel.add(allShowCheckBox, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 3; innerPanel.add(eAllTimeCheckBox, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 6; gridBagConstraints.gridy = 3; innerPanel.add(eAllValueCheckBox, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 7; gridBagConstraints.gridy = 3; innerPanel.add(eAllPercentCheckBox, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 9; gridBagConstraints.gridy = 3; innerPanel.add(iAllTimeCheckBox, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 10; gridBagConstraints.gridy = 3; innerPanel.add(iAllValueCheckBox, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 11; gridBagConstraints.gridy = 3; innerPanel.add(iAllPercentCheckBox, gridBagConstraints); filler0.setPreferredSize(new Dimension(0, 3)); filler1.setPreferredSize(new Dimension(16, 3)); filler2.setPreferredSize(new Dimension(16, 3)); hotButton.setIcon(AnUtility.hot_icon); hotButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Collection collection = metricHashMap.values(); Iterator iterator = collection.iterator(); while (iterator.hasNext()) { MetricGUIEntry metricGUIEntry = iterator.next(); metricGUIEntry.hot(); } refreshAllCheckBoxes(); markChanged(); } }); resetButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Collection collection = metricHashMap.values(); Iterator iterator = collection.iterator(); while (iterator.hasNext()) { MetricGUIEntry metricGUIEntry = iterator.next(); metricGUIEntry.factorySetting(); } refreshAllCheckBoxes(); markChanged(); } }); clearAllButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Collection collection = metricHashMap.values(); Iterator iterator = collection.iterator(); while (iterator.hasNext()) { MetricGUIEntry metricGUIEntry = iterator.next(); metricGUIEntry.clear(); } refreshAllCheckBoxes(); markChanged(); } }); exclusiveLabel.setIcon(AnUtility.excl_icon); inclusiveLabel.setIcon(AnUtility.incl_icon); int checkBoxWidth = 14; int iconLabelWidth = (exclusiveLabel.getPreferredSize().width - checkBoxWidth) / 2; Dimension labelDim1 = new Dimension(iconLabelWidth, 13); Dimension labelDim2 = new Dimension(16, 13); eTimeLabel.setPreferredSize(labelDim1); eValueLabel.setPreferredSize(labelDim2); ePercentLabel.setPreferredSize(labelDim1); iTimeLabel.setPreferredSize(labelDim1); iValueLabel.setPreferredSize(labelDim2); iPercentLabel.setPreferredSize(labelDim1); } private void markChanged() { AnWindow.getInstance().getSettings().stateChanged(null); // Will enable Apply/OK } private class AllAttributeActionListener implements ActionListener { private JCheckBox allCheckBox; private List checkBoxes; public AllAttributeActionListener(JCheckBox allCheckBox, List checkBoxes) { this.checkBoxes = checkBoxes; this.allCheckBox = allCheckBox; } @Override public void actionPerformed(ActionEvent e) { boolean on = allCheckBox.isSelected(); for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled()) { checkBox.setSelected(on); } } Collection collection = metricHashMap.values(); Iterator iterator = collection.iterator(); while (iterator.hasNext()) { MetricGUIEntry metricGUIEntry = iterator.next(); metricGUIEntry.updateViewCheckBoxes(); } markChanged(); } } private class AllShowActionListener implements ActionListener { private JCheckBox allCheckBox; private List checkBoxes; public AllShowActionListener(JCheckBox allCheckBox, List checkBoxes) { this.checkBoxes = checkBoxes; this.allCheckBox = allCheckBox; } @Override public void actionPerformed(ActionEvent e) { boolean on = allCheckBox.isSelected(); for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled()) { checkBox.setSelected(on); } } Collection collection = metricHashMap.values(); Iterator iterator = collection.iterator(); while (iterator.hasNext()) { MetricGUIEntry metricGUIEntry = iterator.next(); metricGUIEntry.updateAttributes(); } markChanged(); } } protected void updateGUIValues() { List metricStateList = AnWindow.getInstance() .getSettings() .getMetricsSetting() .getMetricStates() .getMetricStateList(); updateGUIValues(metricStateList); } protected void updateGUIValues(List metricStateList) { for (MetricState metricState : metricStateList) { AnMetric anMetric = metricState.getAnMetric(); MetricGUIEntry metricsGUIEntry = metricHashMap.get(anMetric.getComd().hashCode()); if (metricsGUIEntry != null) { metricsGUIEntry.showCheckBox.setSelected(metricState.getSelection().isSelected()); if (!metricState.getAnMetric().isStatic()) { metricsGUIEntry.eTimeCheckBox.setSelected(false); metricsGUIEntry.eValueCheckBox.setSelected(false); metricsGUIEntry.ePercentCheckBox.setSelected(false); metricsGUIEntry.iTimeCheckBox.setSelected(false); metricsGUIEntry.iValueCheckBox.setSelected(false); metricsGUIEntry.iPercentCheckBox.setSelected(false); if (metricState.getSelection().isSelected()) { if (metricState.getCapable().isETime()) { metricsGUIEntry.eTimeCheckBox.setSelected( metricState.getSelection().getAttributes().isETime()); } if (metricState.getCapable().isEValue()) { metricsGUIEntry.eValueCheckBox.setSelected( metricState.getSelection().getAttributes().isEValue()); } if (metricState.getCapable().isEPercent()) { metricsGUIEntry.ePercentCheckBox.setSelected( metricState.getSelection().getAttributes().isEPercent()); } if (metricState.getCapable().isITime()) { metricsGUIEntry.iTimeCheckBox.setSelected( metricState.getSelection().getAttributes().isITime()); } if (metricState.getCapable().isIValue()) { metricsGUIEntry.iValueCheckBox.setSelected( metricState.getSelection().getAttributes().isIValue()); } if (metricState.getCapable().isIPercent()) { metricsGUIEntry.iPercentCheckBox.setSelected( metricState.getSelection().getAttributes().isIPercent()); } } } } } refreshAllCheckBoxes(); } private void refreshAllCheckBoxes() { refreshAllCheckBox(allShowCheckBox, showCheckBoxes); refreshAllCheckBox(eAllTimeCheckBox, eTimeCheckBoxes); refreshAllCheckBox(eAllValueCheckBox, eValueCheckBoxes); refreshAllCheckBox(eAllPercentCheckBox, ePercentCheckBoxes); refreshAllCheckBox(iAllTimeCheckBox, iTimeCheckBoxes); refreshAllCheckBox(iAllValueCheckBox, iValueCheckBoxes); refreshAllCheckBox(iAllPercentCheckBox, iPercentCheckBoxes); } private void refreshAllCheckBox(JCheckBox checkBox, List checkBoxes) { if (!allDisabled(checkBoxes)) { checkBox.setEnabled(true); checkBox.setSelected(allSelected(checkBoxes)); } else { checkBox.setEnabled(false); } } private boolean allSelected(List checkBoxes) { boolean ret = true; for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled() && !checkBox.isSelected()) { ret = false; break; } } return ret; } private boolean allDisabled(List checkBoxes) { boolean ret = true; for (JCheckBox checkBox : checkBoxes) { if (checkBox.isEnabled()) { ret = false; break; } } return ret; } protected void updateGUIElements() { removeAll(); gridY = 4; initComponents(); initComponents2(); showCheckBoxes = new ArrayList(); allShowCheckBox.addActionListener(new AllShowActionListener(allShowCheckBox, showCheckBoxes)); eTimeCheckBoxes = new ArrayList(); eAllTimeCheckBox.addActionListener( new AllAttributeActionListener(eAllTimeCheckBox, eTimeCheckBoxes)); eValueCheckBoxes = new ArrayList(); eAllValueCheckBox.addActionListener( new AllAttributeActionListener(eAllValueCheckBox, eValueCheckBoxes)); ePercentCheckBoxes = new ArrayList(); eAllPercentCheckBox.addActionListener( new AllAttributeActionListener(eAllPercentCheckBox, ePercentCheckBoxes)); iTimeCheckBoxes = new ArrayList(); iAllTimeCheckBox.addActionListener( new AllAttributeActionListener(iAllTimeCheckBox, iTimeCheckBoxes)); iValueCheckBoxes = new ArrayList(); iAllValueCheckBox.addActionListener( new AllAttributeActionListener(iAllValueCheckBox, iValueCheckBoxes)); iPercentCheckBoxes = new ArrayList(); iAllPercentCheckBox.addActionListener( new AllAttributeActionListener(iAllPercentCheckBox, iPercentCheckBoxes)); List metricStateList = AnWindow.getInstance() .getSettings() .getMetricsSetting() .getMetricStates() .getMetricStateList(); String listName = null; // Find longest metric name int longestLabelLengthInPixels = 0; for (MetricState metricState : metricStateList) { AnMetric anMetric = metricState.getAnMetric(); JLabel label = new JLabel(anMetric.getUserName()); int labelLengthInPixels = label.getPreferredSize().width; if (labelLengthInPixels > longestLabelLengthInPixels) { longestLabelLengthInPixels = labelLengthInPixels; } } if (longestLabelLengthInPixels < 200) { maxMetricNameLengthInPixels = 200; } else if (longestLabelLengthInPixels > 600) { maxMetricNameLengthInPixels = 600; } else { maxMetricNameLengthInPixels = longestLabelLengthInPixels + 20; } for (MetricState metricState : metricStateList) { AnMetric anMetric = metricState.getAnMetric(); if (anMetric.isNameMetric()) { continue; } String ln = metricState.getListName(); if (ln != null && !ln.equals(listName)) { // System.out.println(ln); listName = ln; addGroupEntry(listName); } addMetricEntry(metricState); } addLastEntry(); // Update the values updateGUIValues(metricStateList); } private void addMetricEntry(MetricState metricState) { AnMetric anMetric = metricState.getAnMetric(); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridY; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 16, 0, 0); JLabel label = new JLabel(getMetricName(anMetric)); // if (anMetric.isHot()) { // label.setIcon(AnUtility.hot_icon); // gridBagConstraints.insets = new Insets(0, 0, 0, 0); // } else { // gridBagConstraints.insets = new Insets(0, 16, 0, 0); // } label.setToolTipText(anMetric.getUserName()); label.setPreferredSize( new Dimension(maxMetricNameLengthInPixels + 17, label.getPreferredSize().height)); innerPanel.add(label, gridBagConstraints); // if (anMetric.isHot()) { // gridBagConstraints = new GridBagConstraints(); // gridBagConstraints.gridx = 2; // gridBagConstraints.gridy = gridY; // JLabel hotLabel = new JLabel(); // hotLabel.setIcon(AnUtility.hot_icon); // innerPanel.add(hotLabel, gridBagConstraints); // } MetricGUIEntry metricGUIEntry = new MetricGUIEntry(metricState); metricHashMap.put(metricState.getAnMetric().getComd().hashCode(), metricGUIEntry); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = gridY; JPanel showPanel = new JPanel(new GridBagLayout()); showPanel.setOpaque(false); Insets insets; if (anMetric.isHot()) { gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; JLabel hotLabel = new JLabel(); hotLabel.setOpaque(false); hotLabel.setIcon(AnUtility.hot_icon); showPanel.add(hotLabel, gridBagConstraints); insets = new Insets(0, 0, 0, 0); } else { insets = new Insets(0, 12, 0, 0); } gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; showPanel.add(metricGUIEntry.showCheckBox, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.insets = insets; // gridBagConstraints.anchor = GridBagConstraints.WEST; innerPanel.add(showPanel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = gridY; if (!anMetric.isStatic()) { gridBagConstraints.gridx = 5; metricGUIEntry.eTimeCheckBox.setEnabled(metricState.getCapable().isETime()); innerPanel.add(metricGUIEntry.eTimeCheckBox, gridBagConstraints); gridBagConstraints.gridx = 6; metricGUIEntry.eValueCheckBox.setEnabled(metricState.getCapable().isEValue()); innerPanel.add(metricGUIEntry.eValueCheckBox, gridBagConstraints); gridBagConstraints.gridx = 7; metricGUIEntry.ePercentCheckBox.setEnabled(metricState.getCapable().isEPercent()); innerPanel.add(metricGUIEntry.ePercentCheckBox, gridBagConstraints); gridBagConstraints.gridx = 9; metricGUIEntry.iTimeCheckBox.setEnabled(metricState.getCapable().isITime()); innerPanel.add(metricGUIEntry.iTimeCheckBox, gridBagConstraints); gridBagConstraints.gridx = 10; metricGUIEntry.iValueCheckBox.setEnabled(metricState.getCapable().isIValue()); innerPanel.add(metricGUIEntry.iValueCheckBox, gridBagConstraints); gridBagConstraints.gridx = 11; metricGUIEntry.iPercentCheckBox.setEnabled(metricState.getCapable().isIPercent()); innerPanel.add(metricGUIEntry.iPercentCheckBox, gridBagConstraints); } gridY++; } private class MetricGUIEntry { AnMetric anMetric; AnCheckBox showCheckBox; AnCheckBox eTimeCheckBox; AnCheckBox eValueCheckBox; AnCheckBox ePercentCheckBox; AnCheckBox iTimeCheckBox; AnCheckBox iValueCheckBox; AnCheckBox iPercentCheckBox; public MetricGUIEntry(MetricState metricState) { this.anMetric = metricState.getAnMetric(); ActionListener showActionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateAttributes(); refreshAllCheckBoxes(); markChanged(); } }; showCheckBox = new AnCheckBox(); String txt = AnLocale.getString("Show this metric in views"); showCheckBox.setToolTipText(txt); AnUtility.setAccessibleContext(showCheckBox.getAccessibleContext(), txt); showCheckBox.addActionListener(showActionListener); showCheckBoxes.add(showCheckBox); if (!metricState.getAnMetric().isStatic()) { ActionListener attributeActionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { showCheckBox.setSelected(anySelected()); refreshAllCheckBoxes(); markChanged(); } }; eTimeCheckBox = new AnCheckBox(); txt = AnLocale.getString("Show EXCLUSIVE Time in views"); eTimeCheckBox.setToolTipText(txt); AnUtility.setAccessibleContext(eTimeCheckBox.getAccessibleContext(), txt); eTimeCheckBox.addActionListener(attributeActionListener); eTimeCheckBoxes.add(eTimeCheckBox); eValueCheckBox = new AnCheckBox(); txt = AnLocale.getString("Show EXCLUSIVE Value in views"); eValueCheckBox.setToolTipText(txt); AnUtility.setAccessibleContext(eValueCheckBox.getAccessibleContext(), txt); eValueCheckBox.addActionListener(attributeActionListener); eValueCheckBoxes.add(eValueCheckBox); ePercentCheckBox = new AnCheckBox(); txt = AnLocale.getString("Show EXCLUSIVE Percent in views"); ePercentCheckBox.setToolTipText(txt); AnUtility.setAccessibleContext(ePercentCheckBox.getAccessibleContext(), txt); ePercentCheckBox.addActionListener(attributeActionListener); ePercentCheckBoxes.add(ePercentCheckBox); iTimeCheckBox = new AnCheckBox(); txt = AnLocale.getString("Show INCLUSIVE Time in views"); iTimeCheckBox.setToolTipText(txt); AnUtility.setAccessibleContext(iTimeCheckBox.getAccessibleContext(), txt); iTimeCheckBox.addActionListener(attributeActionListener); iTimeCheckBoxes.add(iTimeCheckBox); iValueCheckBox = new AnCheckBox(); txt = AnLocale.getString("Show INCLUSIVE Value in views"); iValueCheckBox.setToolTipText(txt); AnUtility.setAccessibleContext(iValueCheckBox.getAccessibleContext(), txt); iValueCheckBox.addActionListener(attributeActionListener); iValueCheckBoxes.add(iValueCheckBox); iPercentCheckBox = new AnCheckBox(); txt = AnLocale.getString("Show INCLUSIVE Percent in views"); iPercentCheckBox.setToolTipText(txt); AnUtility.setAccessibleContext(iPercentCheckBox.getAccessibleContext(), txt); iPercentCheckBox.addActionListener(attributeActionListener); iPercentCheckBoxes.add(iPercentCheckBox); } } public void updateAttributes() { MetricState metricState = AnWindow.getInstance() .getSettings() .getMetricsSetting() .getMetricStates() .findMetricStateByName(anMetric.getComd()); if (!metricState.getAnMetric().isStatic()) { if (showCheckBox.isSelected()) { eTimeCheckBox.setSelected(metricState.getSelection().getAttributes().isETime()); eValueCheckBox.setSelected(metricState.getSelection().getAttributes().isEValue()); ePercentCheckBox.setSelected(metricState.getSelection().getAttributes().isEPercent()); iTimeCheckBox.setSelected(metricState.getSelection().getAttributes().isITime()); iValueCheckBox.setSelected(metricState.getSelection().getAttributes().isIValue()); iPercentCheckBox.setSelected(metricState.getSelection().getAttributes().isIPercent()); if (!anySelected()) { eTimeCheckBox.setSelected(metricState.getFactory().getAttributes().isETime()); eValueCheckBox.setSelected(metricState.getFactory().getAttributes().isEValue()); ePercentCheckBox.setSelected(metricState.getFactory().getAttributes().isEPercent()); iTimeCheckBox.setSelected(metricState.getFactory().getAttributes().isITime()); iValueCheckBox.setSelected(metricState.getFactory().getAttributes().isIValue()); iPercentCheckBox.setSelected(metricState.getFactory().getAttributes().isIPercent()); } if (!anySelected()) { // FIXUP: need to do anything here? System.out.println("MetricsPanel:showCheckBox: no attributes selected"); } } else { eTimeCheckBox.setSelected(false); eValueCheckBox.setSelected(false); ePercentCheckBox.setSelected(false); iTimeCheckBox.setSelected(false); iValueCheckBox.setSelected(false); iPercentCheckBox.setSelected(false); } } } public void updateViewCheckBoxes() { if (!anMetric.isStatic()) { showCheckBox.setSelected(anySelected()); } } public void hot() { showCheckBox.setSelected(anMetric.isHot()); updateAttributes(); } public void clear() { showCheckBox.setSelected(false); updateAttributes(); } public void factorySetting() { MetricState metricState = AnWindow.getInstance() .getSettings() .getMetricsSetting() .getMetricStates() .findMetricStateByName(anMetric.getComd()); showCheckBox.setSelected(metricState.getFactory().isSelected()); if (!metricState.getAnMetric().isStatic()) { if (showCheckBox.isSelected()) { eTimeCheckBox.setSelected(metricState.getFactory().getAttributes().isETime()); eValueCheckBox.setSelected(metricState.getFactory().getAttributes().isEValue()); ePercentCheckBox.setSelected(metricState.getFactory().getAttributes().isEPercent()); iTimeCheckBox.setSelected(metricState.getFactory().getAttributes().isITime()); iValueCheckBox.setSelected(metricState.getFactory().getAttributes().isIValue()); iPercentCheckBox.setSelected(metricState.getFactory().getAttributes().isIPercent()); } else { eTimeCheckBox.setSelected(false); eValueCheckBox.setSelected(false); ePercentCheckBox.setSelected(false); iTimeCheckBox.setSelected(false); iValueCheckBox.setSelected(false); iPercentCheckBox.setSelected(false); } } } public boolean anySelected() { return eTimeCheckBox.isSelected() || eValueCheckBox.isSelected() || ePercentCheckBox.isSelected() || iTimeCheckBox.isSelected() || iValueCheckBox.isSelected() || iPercentCheckBox.isSelected(); } } private String getMetricName(AnMetric anMetric) { StringBuilder buf = new StringBuilder(); buf.append(anMetric.getUserName()); JLabel label = new JLabel(buf.toString()); if (label.getPreferredSize().width < maxMetricNameLengthInPixels) { while (label.getPreferredSize().width < maxMetricNameLengthInPixels) { buf.append(" ."); label.setText(buf.toString()); } } return buf.toString(); } private void addGroupEntry(String groupName) { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridY++; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(2, 0, 0, 0); JLabel label = new JLabel(); AnUtility.setTextAndAccessibleContext(label, groupName); label.setFont(label.getFont().deriveFont(Font.BOLD)); label.setForeground(AnEnvironment.METRIC_MENU_SECTION_COLOR); innerPanel.add(label, gridBagConstraints); } private void addLastEntry() { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridY++; gridBagConstraints.weighty = 1.0; innerPanel.add(new JLabel(""), gridBagConstraints); } public List getMetricNameSelections() { AnMetric[] availableMetrics = AnWindow.getInstance().getSettings().getMetricsSetting().getAvailableAnMetrics(); List list = new ArrayList(); for (int index = 0; index < availableMetrics.length; index++) { AnMetric anMetric = availableMetrics[index]; MetricGUIEntry metricGUIEntry = metricHashMap.get(anMetric.getComd().hashCode()); if (anMetric.isNameMetric()) { MetricAttributes metricAttributes = new MetricAttributes( false, false, false, false, false, false); // compatible with previous version MetricSelection metricSelection = new MetricSelection(false, metricAttributes); // compatible with previous version MetricNameSelection metricNameSelection = new MetricNameSelection(anMetric.getComd(), metricSelection); list.add(metricNameSelection); } else { if (metricGUIEntry != null) { MetricAttributes metricAttributes; if (!anMetric.isStatic()) { metricAttributes = new MetricAttributes( metricGUIEntry.eTimeCheckBox.isSelected(), metricGUIEntry.eValueCheckBox.isSelected(), metricGUIEntry.ePercentCheckBox.isSelected(), metricGUIEntry.iTimeCheckBox.isSelected(), metricGUIEntry.iValueCheckBox.isSelected(), metricGUIEntry.iPercentCheckBox.isSelected()); } else { metricAttributes = new MetricAttributes(false, true, false, false, false, false); } MetricSelection metricSelection = new MetricSelection(metricGUIEntry.showCheckBox.isSelected(), metricAttributes); MetricNameSelection metricNameSelection = new MetricNameSelection(anMetric.getComd(), metricSelection); list.add(metricNameSelection); } else { System.err.println( "MetricsPanel.getMetricValues: Error: cannot find: " + anMetric.getComd()); } } } return list; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; scrollPane = new javax.swing.JScrollPane(); innerPanel = new javax.swing.JPanel(); showLabel1 = new javax.swing.JLabel(); exclusiveLabel = new javax.swing.JLabel(); inclusiveLabel = new javax.swing.JLabel(); showLabel2 = new javax.swing.JLabel(); eTimeLabel = new javax.swing.JLabel(); eValueLabel = new javax.swing.JLabel(); ePercentLabel = new javax.swing.JLabel(); iTimeLabel = new javax.swing.JLabel(); iValueLabel = new javax.swing.JLabel(); iPercentLabel = new javax.swing.JLabel(); separator = new javax.swing.JSeparator(); filler0 = new javax.swing.Box.Filler( new java.awt.Dimension(12, 12), new java.awt.Dimension(12, 12), new java.awt.Dimension(12, 12)); filler1 = new javax.swing.Box.Filler( new java.awt.Dimension(16, 12), new java.awt.Dimension(16, 12), new java.awt.Dimension(16, 12)); filler2 = new javax.swing.Box.Filler( new java.awt.Dimension(12, 12), new java.awt.Dimension(12, 12), new java.awt.Dimension(12, 12)); buttonPanel = new javax.swing.JPanel(); hotButton = new javax.swing.JButton(); resetButton = new javax.swing.JButton(); clearAllButton = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); scrollPane.setBorder(null); scrollPane.setOpaque(false); innerPanel.setLayout(new java.awt.GridBagLayout()); showLabel1.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); showLabel1.setText("Show in Views"); showLabel1.setToolTipText(""); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; innerPanel.add(showLabel1, gridBagConstraints); exclusiveLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); exclusiveLabel.setText("EXCLUSIVE"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; innerPanel.add(exclusiveLabel, gridBagConstraints); inclusiveLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); inclusiveLabel.setText("INCLUSIVE"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 9; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; innerPanel.add(inclusiveLabel, gridBagConstraints); showLabel2.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); showLabel2.setToolTipText(""); showLabel2.setOpaque(true); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.ipadx = 12; innerPanel.add(showLabel2, gridBagConstraints); eTimeLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); eTimeLabel.setText("xx"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(1, 0, 0, 0); innerPanel.add(eTimeLabel, gridBagConstraints); eValueLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); eValueLabel.setText("yy"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 6; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(1, 0, 0, 0); innerPanel.add(eValueLabel, gridBagConstraints); ePercentLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); ePercentLabel.setText("zz"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 7; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(1, 0, 0, 0); innerPanel.add(ePercentLabel, gridBagConstraints); iTimeLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); iTimeLabel.setText("xx"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 9; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(1, 0, 0, 0); innerPanel.add(iTimeLabel, gridBagConstraints); iValueLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); iValueLabel.setText("yy"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 10; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(1, 0, 0, 0); innerPanel.add(iValueLabel, gridBagConstraints); iPercentLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); iPercentLabel.setText("zz"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 11; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(1, 0, 0, 0); innerPanel.add(iPercentLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; innerPanel.add(separator, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; innerPanel.add(filler0, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 0; innerPanel.add(filler1, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 8; gridBagConstraints.gridy = 0; innerPanel.add(filler2, gridBagConstraints); scrollPane.setViewportView(innerPanel); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 6, 0, 6); add(scrollPane, gridBagConstraints); buttonPanel.setLayout(new java.awt.GridBagLayout()); hotButton.setText("Hot"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; buttonPanel.add(hotButton, gridBagConstraints); resetButton.setText("Reset"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); buttonPanel.add(resetButton, gridBagConstraints); clearAllButton.setText("Clear All"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); buttonPanel.add(clearAllButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new java.awt.Insets(6, 6, 6, 0); add(buttonPanel, gridBagConstraints); } // //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel buttonPanel; private javax.swing.JButton clearAllButton; private javax.swing.JLabel ePercentLabel; private javax.swing.JLabel eTimeLabel; private javax.swing.JLabel eValueLabel; private javax.swing.JLabel exclusiveLabel; private javax.swing.Box.Filler filler0; private javax.swing.Box.Filler filler1; private javax.swing.Box.Filler filler2; private javax.swing.JButton hotButton; private javax.swing.JLabel iPercentLabel; private javax.swing.JLabel iTimeLabel; private javax.swing.JLabel iValueLabel; private javax.swing.JLabel inclusiveLabel; private javax.swing.JPanel innerPanel; private javax.swing.JButton resetButton; private javax.swing.JScrollPane scrollPane; private javax.swing.JSeparator separator; private javax.swing.JLabel showLabel1; private javax.swing.JLabel showLabel2; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/settings/MetricNameSelection.java0000644000175000017500000000337114517772113022336 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; /** * @author tpreisle */ public class MetricNameSelection { private String name; private MetricSelection metricSelection; public MetricNameSelection(String name, boolean selected, boolean[] exclusiveInclusive) { this.name = name; MetricAttributes metricAttributes = new MetricAttributes( exclusiveInclusive[0], exclusiveInclusive[1], exclusiveInclusive[2], exclusiveInclusive[3], exclusiveInclusive[4], exclusiveInclusive[5]); this.metricSelection = new MetricSelection(selected, metricAttributes); } public MetricNameSelection(String name, MetricSelection metricSelection) { this.name = name; this.metricSelection = metricSelection; } /** * @return the name */ public String getName() { return name; } /** * @return the selected */ public boolean isSelected() { return getMetricSelection().isSelected(); } /** * @return the metricSelection */ public MetricSelection getMetricSelection() { return metricSelection; } } gprofng-gui-1.0/org/gprofng/mpmt/settings/ImportSettingsPanel.form0000644000175000017500000003633614517772113022450 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/settings/Setting.java0000644000175000017500000001120714517772113020056 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.settings; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.ipc.IPCContext; import org.gprofng.mpmt.settings.AnSettingChangeEvent.Type; import org.gprofng.mpmt.util.gui.AnUtility; public abstract class Setting { abstract void setValue(Object newValue); abstract Object getValue(); abstract Type getType(); public void setValueAndFireChangeEvent( final Object originalSource, final Setting setting, final Object newValue) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { synchronized (AnVariable.mainFlowLock) { // System.out.println("Setting.setValueAndFireChangeEvent: " + // getType() + " " + originalSource + " " + Setting.this); IPCContext.newCurrentContext( AnLocale.getString("Changing settings..."), IPCContext.Scope.SESSION, false, AnWindow.getInstance()); Object progressBarHandle = AnWindow.getInstance() .getSystemProgressPanel() .progressBarStart(AnLocale.getString("Changing Settings")); final Object oldValue = setting.getValue(); final AnSettingChangeEvent anPropertyChangeEvent = new AnSettingChangeEvent( originalSource, Setting.this, getType(), oldValue, newValue); AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent( anPropertyChangeEvent, AnChangeEvent.Type.SETTING_CHANGING)); setValue(newValue); // possible IPC AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(anPropertyChangeEvent, AnChangeEvent.Type.SETTING_CHANGED)); AnWindow.getInstance().getSystemProgressPanel().progressBarStop(progressBarHandle); IPCContext.newCurrentContext( null, IPCContext.Scope.SESSION, false, AnWindow.getInstance()); } } }, "Setting Thread"); } public void fireChangeEvent(final Object originalSource, final Object newValue) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { synchronized (AnVariable.mainFlowLock) { // System.out.println("Setting.fireChangeEvent: " + getType() + " " // + originalSource + " " + Setting.this); IPCContext.newCurrentContext( AnLocale.getString("Changing settings..."), IPCContext.Scope.SESSION, false, AnWindow.getInstance()); Object progressBarHandle = AnWindow.getInstance() .getSystemProgressPanel() .progressBarStart(AnLocale.getString("Changing Settings")); final AnSettingChangeEvent anPropertyChangeEvent = new AnSettingChangeEvent(originalSource, Setting.this, getType(), null, newValue); AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent( anPropertyChangeEvent, AnChangeEvent.Type.SETTING_CHANGING)); AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(anPropertyChangeEvent, AnChangeEvent.Type.SETTING_CHANGED)); AnWindow.getInstance().getSystemProgressPanel().progressBarStop(progressBarHandle); IPCContext.newCurrentContext( null, IPCContext.Scope.SESSION, false, AnWindow.getInstance()); } } }, "Setting Thread"); } } gprofng-gui-1.0/org/gprofng/mpmt/AboutPanel.java0000644000175000017500000002225014517772113016633 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.ipc.IPCProtocol; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnDialog2; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.HeadlessException; import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.text.BadLocationException; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import javax.swing.text.StyledDocument; public class AboutPanel extends JPanel { private static final String REGULAR = "regular"; private static final String BOLD = "bold"; private static final String ITALIC = "italic"; private static final String strLegalNotice = "Copyright (C) 2022 Free Software Foundation\n\n" + "This program is free software; you can redistribute it and/or modify\n" + "it under the terms of the GNU General Public License as published by\n" + "the Free Software Foundation, either version 3 of the License, or\n" + "(at your option) any later version.\n\n" + "This program is distributed in the hope that it will be useful,\n" + "but WITHOUT ANY WARRANTY; without even the implied warranty of\n" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" + "GNU General Public License for more details.\n\n" + "You should have received a copy of the GNU General Public License\n" + "along with this program. If not, see .\n"; public AboutPanel() { initComponents(); iconLabel.setBorder(BorderFactory.createLineBorder(AnEnvironment.ABOUT_BOX_BORDER_COLOR)); copyrightScrollPane.setBorder( BorderFactory.createLineBorder(AnEnvironment.ABOUT_BOX_BORDER_COLOR)); infoScrollPane.setBorder(BorderFactory.createLineBorder(AnEnvironment.ABOUT_BOX_BORDER_COLOR)); iconLabel.setIcon( new javax.swing.ImageIcon( getClass().getResource("/org/gprofng/mpmt/icons/performanceAnalyzerSplash.gif"))); copyrightTextArea.setWrapStyleWord(true); copyrightTextArea.setLineWrap(true); copyrightTextArea.setText(strLegalNotice); copyrightTextArea.setCaretPosition(0); copyrightTextArea.setBackground(new Color(254, 254, 254)); // copyrightTextArea.setOpaque(false); String cn = AnLocale.getString("Copyright Notice"); copyrightTextArea.getAccessibleContext().setAccessibleName(cn); copyrightTextArea.getAccessibleContext().setAccessibleDescription(cn); copyrightTextArea.setFont( copyrightTextArea.getFont().deriveFont((float) copyrightTextArea.getFont().getSize() - 1)); StyledDocument doc = infoTextPane.getStyledDocument(); Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE); Style regularStyle = doc.addStyle(REGULAR, def); Style italicStyle = doc.addStyle(ITALIC, regularStyle); StyleConstants.setItalic(italicStyle, true); Style boldStyle = doc.addStyle(BOLD, regularStyle); StyleConstants.setBold(boldStyle, true); try { doc.insertString(doc.getLength(), AnLocale.getString("Version: "), doc.getStyle(BOLD)); doc.insertString(doc.getLength(), Analyzer.fdversion + "\n", doc.getStyle(REGULAR)); doc.insertString( doc.getLength(), AnLocale.getString("GUI protocol version: "), doc.getStyle(BOLD)); doc.insertString(doc.getLength(), IPCProtocol.version + "\n", doc.getStyle(REGULAR)); doc.insertString(doc.getLength(), AnLocale.getString("Install: "), doc.getStyle(BOLD)); doc.insertString(doc.getLength(), Analyzer.fdhome + "\n", doc.getStyle(REGULAR)); doc.insertString( doc.getLength(), AnLocale.getString("Working directory: "), doc.getStyle(BOLD)); doc.insertString( doc.getLength(), Analyzer.getInstance().getWorkingDirectory() + "\n", doc.getStyle(REGULAR)); doc.insertString(doc.getLength(), AnLocale.getString("Java: "), doc.getStyle(BOLD)); doc.insertString( doc.getLength(), "J2SE[tm] " + Analyzer.jvm_ver + "\n", doc.getStyle(REGULAR)); doc.insertString(doc.getLength(), AnLocale.getString("Java home: "), doc.getStyle(BOLD)); doc.insertString(doc.getLength(), Analyzer.jvm_home + "\n", doc.getStyle(REGULAR)); doc.insertString(doc.getLength(), AnLocale.getString("User directory: "), doc.getStyle(BOLD)); doc.insertString( doc.getLength(), UserPref.getInstance().getAnalyzerDirPath() + "\n", doc.getStyle(REGULAR)); doc.insertString(doc.getLength(), "gp-display-text: ", doc.getStyle(BOLD)); doc.insertString( doc.getLength(), Analyzer.getInstance().er_print + "\n", doc.getStyle(REGULAR)); } catch (BadLocationException ble) { } AnUtility.setAccessibleContext( infoTextPane.getAccessibleContext(), AnLocale.getString("Info Pane")); } /** Show Version and Copyright Notice */ public static void showDialog() throws HeadlessException { String aTitle = AnLocale.getString("About gprofng GUI"); AnDialog2 dialog2 = new AnDialog2(AnWindow.getInstance().getFrame(), AnWindow.getInstance().getFrame(), aTitle); dialog2.setCustomPanel(new AboutPanel()); dialog2.setModal(false); dialog2.setAlwaysOnTop(true); dialog2.getAccessibleContext().setAccessibleName(aTitle); dialog2.getAccessibleContext().setAccessibleDescription(aTitle); dialog2.getCancelButton().setVisible(false); dialog2.pack(); dialog2.setVisible(true); dialog2.getOKButton().requestFocus(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; innerPanel = new javax.swing.JPanel(); iconLabel = new javax.swing.JLabel(); infoScrollPane = new javax.swing.JScrollPane(); infoTextPane = new javax.swing.JTextPane(); copyrightScrollPane = new javax.swing.JScrollPane(); copyrightTextArea = new javax.swing.JTextArea(); setLayout(new java.awt.GridBagLayout()); innerPanel.setLayout(new java.awt.GridBagLayout()); iconLabel.setIcon( new javax.swing.ImageIcon( getClass().getResource("/org/gprofng/mpmt/icons/performanceAnalyzerSplash.gif"))); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; innerPanel.add(iconLabel, gridBagConstraints); infoScrollPane.setPreferredSize(new java.awt.Dimension(300, 180)); infoTextPane.setEditable(false); infoScrollPane.setViewportView(infoTextPane); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); innerPanel.add(infoScrollPane, gridBagConstraints); copyrightTextArea.setEditable(false); copyrightTextArea.setColumns(20); copyrightTextArea.setLineWrap(true); copyrightTextArea.setRows(8); copyrightTextArea.setMargin(new java.awt.Insets(4, 4, 4, 4)); copyrightScrollPane.setViewportView(copyrightTextArea); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); innerPanel.add(copyrightScrollPane, gridBagConstraints); add(innerPanel, new java.awt.GridBagConstraints()); } // //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane copyrightScrollPane; private javax.swing.JTextArea copyrightTextArea; private javax.swing.JLabel iconLabel; private javax.swing.JScrollPane infoScrollPane; private javax.swing.JTextPane infoTextPane; private javax.swing.JPanel innerPanel; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/IPCProcess.java0000644000175000017500000001617714517772113016566 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import javax.swing.JOptionPane; /** Process which delegates Runtime.exec process for gp-display-text -IPC */ public final class IPCProcess extends Process { private OutputStream stdin; private InputStream stdout, stderr; public ExitMonitor monitor; private final Process delegate; private final Analyzer parent_Analyzer; public ProcListener a_Proc_Listener; public IPCProcess( final Analyzer parent, final Process delegate, final OutputStream stdin, final InputStream stdout, final InputStream stderr) { this.delegate = delegate; this.stdin = stdin; this.stdout = stdout; this.stderr = stderr; this.parent_Analyzer = parent; } @Override public InputStream getErrorStream() { return stderr; } @Override public OutputStream getOutputStream() { return stdin; } @Override public InputStream getInputStream() { return stdout; } @Override public int waitFor() throws InterruptedException { try { return delegate.waitFor(); } catch (InterruptedException x) { return -1; } } @Override public int exitValue() throws IllegalThreadStateException { return delegate.exitValue(); } @Override public void destroy() { delegate.destroy(); } public synchronized void setExitListener() { a_Proc_Listener = new ProcListener(); if (monitor != null) { monitor.interrupt(); monitor = null; } monitor = new ExitMonitor(this, a_Proc_Listener); monitor.start(); } public synchronized void removeExitListener() { a_Proc_Listener = null; if (monitor != null) { monitor.interrupt(); monitor = null; } } /*------------------------------------- INNER CLASSES ----------------------------------------------------*/ /** * Class for catching process exit. * * @see ExitListener */ public final class ProcListener implements ExitListener { public ProcListener() {} /** * Implements method processExited of ExitListener interface * * @param p - external process Method prints error message and cleanups analyzer (standalone) or * close TopComponent (netbeans module). * @see ExitListener */ @Override public void processExited(final Process p) { String msg; int exit_value = -1; try { exit_value = p.exitValue(); } catch (IllegalThreadStateException ex) { } // process has already exited switch (exit_value) { case -1: msg = null; // process has not yet terminated, default exit value break; case 0: msg = AnLocale.getString("Communication channel will be closed"); break; case 2: // SIGINT msg = AnLocale.getString("gp-display-text has been interrupted."); break; case 3: // SIGQUIT msg = AnLocale.getString("gp-display-text has quit."); break; case 4: // SIGILL msg = AnLocale.getString("Illegal instruction in gp-display-text."); break; case 5: // SIGTRAP msg = AnLocale.getString("Trace/Breakpoint trap in gp-display-text."); break; case 6: // SIGABRT msg = AnLocale.getString("gp-display-text has been aborted."); break; case 7: // SIGEMT msg = AnLocale.getString("Emulation trap in gp-display-text."); break; case 8: // SIGFPE msg = AnLocale.getString("Floating point exception in gp-display-text."); break; case 9: // SIGKILL msg = AnLocale.getString("gp-display-text has been killed."); break; case 10: // SIGBUS msg = AnLocale.getString("Bus Error in gp-display-text."); break; case 11: // SIGSEGV msg = AnLocale.getString("Segmentation Fault in gp-display-text."); break; case 15: // SIGTERM msg = AnLocale.getString("gp-display-text has been terminated."); break; case 16: // SIGUSR1 msg = AnLocale.getString("Out of memory Error in gp-display-text."); break; default: // All other signals msg = AnLocale.getString("gp-display-text has exited unexpectedly."); break; } if (exit_value != -1) { msg += AnLocale.getString(" Exit status is ") + exit_value; } // msg += AnLocale.getString("\nAnalyzer session will be reinitialized."); // if (!Analyzer.inNetBeans() && Analyzer.gui_initialized) // AnWindow.getRootWindow().reinit(); // analyzer cleanup // if (parent_Analyzer.get_win_size() != 0) // No SIGTERM occured (netbeans only) // parent_Analyzer.endIPC(msg); try { stdin.close(); stdout.close(); stderr.close(); } catch (IOException ex) { // ex.printStackTrace(); // No need - we are going to exit } if (parent_Analyzer.isConnected() && (!parent_Analyzer.isRemote())) { if (!parent_Analyzer.connectingToRemoteHost) { // not connecting? // Show error message and save it in the log file AnWindow.getInstance() .getExperimentsView() .appendLog(AnLocale.getString("Error: ") + msg); System.err.println(AnLocale.getString("Error: ") + msg); JOptionPane.showMessageDialog( (AnWindow.getInstance()).getFrame(), msg, AnLocale.getString("Error"), JOptionPane.ERROR_MESSAGE); System.exit(1); } } } } /** Monitor class for listening external process to catch process exit. */ public final class ExitMonitor extends Thread { private final Process proc; private final ExitListener listener; /** * Monitor constructor * * @param proc - external process for listening * @param listener - listener interface * @see ExitListener */ ExitMonitor(final Process proc, final ExitListener listener) { this.proc = proc; this.listener = listener; } @Override public final void run() { try { proc.waitFor(); } catch (InterruptedException ex) { // ignore monitor interruption } // Show error dialog - user may want to reestablish connection listener.processExited(proc); monitor = null; } } public interface ExitListener { public void processExited(Process p); } } gprofng-gui-1.0/org/gprofng/mpmt/persistence/0000755000175000017500000000000014517775726016356 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/persistence/UserPrefPersistence.java0000644000175000017500000020013114517772113023061 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.persistence; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.ExperimentPickList; import org.gprofng.mpmt.ExperimentPickListElement; import org.gprofng.mpmt.metrics.MetricColors.MetricColor; import org.gprofng.mpmt.persistence.UserPref.ConnectionProperties; import org.gprofng.mpmt.persistence.UserPref.ViewPanelOrder; import org.gprofng.mpmt.picklist.StringPickList; import org.gprofng.mpmt.picklist.StringPickListElement; import org.gprofng.mpmt.remote.Authentication; import org.gprofng.mpmt.settings.MetricNameSelection; import org.gprofng.mpmt.settings.MetricType; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.settings.PathMapSetting; import org.gprofng.mpmt.settings.SearchPathSetting; import org.gprofng.mpmt.settings.SourceDisassemblySetting; import org.gprofng.mpmt.settings.ViewsSetting.CustomObject; import org.gprofng.mpmt.statecolors.ColorRule; import org.gprofng.mpmt.toolbar.FindTextPanel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Dimension; import java.awt.Point; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.Stack; import javax.swing.JOptionPane; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.xml.sax.Attributes; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; public class UserPrefPersistence { /** * V15: HOSTNAME_AUTH_ATTR V14: LIBRARY_VISIBILITY_JAVA V13: FULL_METRIC_NAME_IN_TABLES_ELEM V12: * Metric sorting, direction, and order V11: changed order and added sections V10: call stack * threshold V9 : working directory V8 : find history V7 : splitpane(123) size V6 : navigation * panel splitpane position V5 : recent experiments per host V4 : added userName attr to host V3 : * added hostNamePath maps V2 : added most recent experiments V1 : initial version */ private static final int version = 15; private static final String spaces = " "; // Elements private static final String VERSION_ELEM = "version"; private static final String ANALYZER_ELEM = "analyzer"; private static final String USER_ELEM = "user"; private static final String FRAME_ELEM = "frame"; private static final String FRAME_WIDTH_ATTR = "width"; private static final String FRAME_HEIGHT_ATTR = "height"; private static final String FRAME_X_ATTR = "x"; private static final String FRAME_Y_ATTR = "y"; private static final String SPLITPANE1_ELEM = "splitpane1"; private static final String SPLITPANE2_ELEM = "splitpane2"; private static final String SPLITPANE3_ELEM = "splitpane3"; private static final String NAV_SPLITPANE_ELEM = "navsplitpane"; private static final String NAV_FILTER_SPLITPANE_ELEM = "navfiltersplitpane"; private static final String SPLITPANE_POS_ATTR = "pos"; private static final String SPLITPANE_LAST_POS_ATTR = "lastpos"; private static final String SPLITPANE_RIGHT_SIZE_ATTR = "rightsize"; private static final String VIEWS_ELEM = "views"; private static final String VIEW_ORDER_LIST_ELEM = "vieworderlist"; private static final String VIEW_ORDER_ELEM = "viewelem"; private static final String VIEW_ORDER_NAME_ATTR = "name"; private static final String VIEW_ORDER_SHOWN_ATTR = "shown"; private static final String EXPERIMENT_LIST_ELEM = "recentExperimentsList"; private static final String EXPERIMENT_PATH_ELEM = "experimentPath"; private static final String EXPERIMENT_ELEM = "experiment"; private static final String HOSTNAME_LIST_ELEM = "hostNameList"; private static final String HOSTNAME_ELEM = "host"; private static final String HOSTNAME_NAME_ATTR = "name"; private static final String HOSTNAME_PATH_ATTR = "path"; private static final String HOSTNAME_AUTH_ATTR = "auth"; private static final String HOSTNAME_USERNAME_ATTR = "username"; private static final String HOST_NAME_ATTR = "host"; private static final String PATH_ATTR = "path"; private static final String WD_ATTR = "wd"; private static final String LAST_CLOSED_EXP_CONF_PATH_ELEM = "lceconfpath"; private static final String LAST_EXPORT_IMPORT_EXP_CONF_PATH_ELEM = "leiconfpath"; private static final String SHOW_COMPARE_WARNING_ELEM = "comparewarning"; private static final String CONF_ATTR = "conf"; private static final String MISC_ELEM = "misc"; private static final String FIND_LIST_ELEM = "findlist"; private static final String FIND_ELEM = "text"; private static final String WHAT_LIST_ELEM = "whatlist"; private static final String WHAT_ELEM = "what"; private static final String LIBRARY_VISIBILITY_INCLUDE_FILTER_LIST_ELEM = "hidefuncsincludefilterlist"; private static final String LIBRARY_VISIBILITY_INCLUDE_FILTER_ELEM = "hidefuncsincludefiltertext"; private static final String LIBRARY_VISIBILITY_EXCLUDE_FILTER_LIST_ELEM = "hidefuncsexcludefilterlist"; private static final String LIBRARY_VISIBILITY_EXCLUDE_FILTER_ELEM = "hidefuncsexcludefiltertext"; private static final String LIBRARY_VISIBILITY_CURRENT_FILTER_ATTR = "current"; private static final String LIBRARY_VISIBILITY_JAVA = "libraryvisibilityjava"; private static final String CALL_TREE_PROP = "calltree"; private static final String CALL_TREE_THRESHOLD = "calltreethreshold"; private static final String FORMATS_ELEM = "formats"; private static final String FORMATS_VIEW_MODE = "viewmode"; private static final String FORMATS_STYLE = "style"; private static final String FORMATS_APPEND_SO_NAME = "appendsoname"; private static final String FORMATS_COMPARE_MODE = "comparemode"; private static final String FORMATS_WRAP_METRIC_NAMES_IN_TABLES_ELEM = "wrapmetricnamesintables"; private static final String SOURCE_DISASSEMBLY_ELEM = "sourceanddisassembly"; private static final String SOURCE_DISASSEMBLY = "sourcedisassembly"; private static final String VALUE_ELEM = "value"; private static final String MACHINE_MODEL_ELEM = "machinemodel"; private static final String INDEX_OBJECT_LIST_ELEM = "indexobjectlist"; private static final String MEMORY_OBJECT_LIST_ELEM = "memoryobjectlist"; private static final String CUSTOM_OBJECT_LIST_ELEM = "customobject"; private static final String CUSTOM_OBJECT_NAME_ATTR = "name"; private static final String CUSTOM_OBJECT_FORMULA_ATTR = "formula"; private static final String CALL_STACK_FUNCTION_COLORS_ELEM = "callstackfunctioncolors"; private static final String FUNCTION_COLORS_LIST_ELEM = "functioncolors"; private static final String FUNCTION_COLORS_COLOR_RULE_ELEM = "colorrule"; private static final String FUNCTION_COLORS_COLOR_RULE_TYPE_ATTR = "type"; private static final String FUNCTION_COLORS_COLOR_RULE_TEXT_ATTR = "text"; private static final String FUNCTION_COLORS_COLOR_RULE_COLOR_ATTR = "color"; private static final String METRICS_ELEM = "metrics"; private static final String METRIC_SELECTION_LIST_ELEM_V12 = "metricorderlist"; private static final String METRIC_SELECTION_LIST_ELEM = "metricselectionlist"; private static final String METRIC_SELECTION_ELEM = "metricelem"; private static final String METRIC_NAME_ATTR = "name"; private static final String METRIC_ORDER_SELECTED_ATTR = "selected"; private static final String METRIC_ORDER_EXCLINCL_ATTR = "x"; private static final String METRIC_REVERSED_SORT = "metricreversedsort"; private static final String METRIC_SORT_LIST_ELEM = "metricsortlist"; private static final String METRIC_SORT_ELEM = "metricsortbymtype"; private static final String METRIC_MTYPE_ATTR = "mtype"; private static final String METRIC_SUBTYPE_ATTR = "subtype"; private static final String METRIC_ORDER_LIST_ELEM = "metricorderlists"; private static final String METRIC_ORDER_MTYPE_LIST_ELEM = "metricordermtypelist"; private static final String METRIC_ORDER_ELEM = "metricorderelem"; private static final String TIMELINE_ELEM = "timeline"; private static final String TIMELINE_STACK_DEPTH_ELEM = "verticalzoom"; private static final String TIMELINE_STACK_FRAME_PIXELS_ELEM = "stackframepixels"; private static final String TIMELINE_GROUP_DATA_BY_BUTTON_NAME_ELEM = "groupdatabybuttonname"; private static final String TIMELINE_TLDATA_CMD_ELEM = "tldatacmd"; private static final String TIMELINE_STACK_ALIGN_ELEM = "stackalign"; private static final String TIMELINE_SHOW_STATES_ELEM = "showstates"; private static final String TIMELINE_SHOW_DENSITY_ELEM = "showdensity"; private static final String LIBRARY_VISIBILITY_ELEM = "libraryvisibility"; private static final String LOADOBJECT_LIST_ELEM = "loadobjects"; private static final String LOADOBJECT_ITEM_ELEM = "loitem"; private static final String SEARCHPATH_ELEM = "searchpath"; private static final String SEARCHPATH_LIST_ELEM = "searchpathlist"; private static final String SEARCHPATH_ITEM_ELEM = "searchpathitem"; private static final String PATHMAP_ELEM = "pathmap"; private static final String PATHMAP_LIST_ELEM = "pathmaplist"; private static final String PATHMAP_ITEM_ELEM = "pathmapitem"; private static final String PATHMAP_FROM_ATTR = "from"; private static final String PATHMAP_TO_ATTR = "to"; private static final String METRIC_COLOR_LIST_ELEM = "customMetricColors"; private static final String METRIC_COLOR_ITEM_ELEM = "metric"; private static final String METRIC_COLOR_NAME_ATTR = "name"; private static final String METRIC_COLOR_COLOR_ATTR = "color"; private UserPref userPref; private static HashSet experimentErrorHashSet = new HashSet(); public UserPrefPersistence() {} public void saveSettings(String path, UserPref userPref, List what) { PrintWriter out = null; String dirPath = AnUtility.dirname(path); try { if (!new File(dirPath).exists()) { new File(dirPath).mkdirs(); } out = new PrintWriter(new BufferedWriter(new FileWriter(path))); } catch (Exception e) { saveErrorDialog(path, e); return; } writeInitFile(out, userPref, what); out.flush(); out.close(); } private void saveErrorDialog(String path, Exception e) { if (experimentErrorHashSet.contains(path)) { return; } experimentErrorHashSet.add(path); StringBuilder sb = new StringBuilder(); sb.append(AnLocale.getString("Cannot access persistence file:")); sb.append("\n"); sb.append(path); sb.append("\n"); sb.append(AnLocale.getString("Because:")); sb.append("\n"); sb.append(e); String errmsg = sb.toString(); AnUtility.showMessage(AnWindow.getInstance().getFrame(), errmsg, JOptionPane.ERROR_MESSAGE); } public void restoreSettings(String path, UserPref userPref) { this.userPref = userPref; if (new File(path).exists()) { // System.out.println("Configuration file processed: " + path); AnLog.log("Configuration file processed: " + path); parseInitFile(path); } } private void writeInitFile(PrintWriter out, UserPref userPref, List what) { out.println(""); writeEntry(out, 0, ANALYZER_ELEM, false); writeUserPref(out, 2, userPref, what); writeEntry(out, 0, ANALYZER_ELEM, true); } private void writeUserPref( PrintWriter out, int indent, UserPref userPref, List whatList) { writeEntry(out, indent, VERSION_ELEM, "" + version); writeWhatList(out, indent, whatList); if (whatList.contains(UserPref.What.USER)) { writeEntry(out, indent, USER_ELEM, false); if (userPref.getFrameSize() != null && userPref.getFrameLocation() != null) { AttrValuePair[] attrValues = new AttrValuePair[4]; attrValues[0] = new AttrValuePair( FRAME_WIDTH_ATTR, "" + (userPref.getFrameSize() .width)); // FIXUP: loosing 10 pixels when ssh from a Mac attrValues[1] = new AttrValuePair( FRAME_HEIGHT_ATTR, "" + (userPref.getFrameSize() .height)); // FIXUP: loosing 8 pixels when ssh from a Mac attrValues[2] = new AttrValuePair(FRAME_X_ATTR, "" + userPref.getFrameLocation().x); attrValues[3] = new AttrValuePair(FRAME_Y_ATTR, "" + userPref.getFrameLocation().y); writeEntry(out, indent + 2, FRAME_ELEM, attrValues, true); } if (userPref.getSplitPane1().getSize() >= 0) { AttrValuePair[] attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair(SPLITPANE_RIGHT_SIZE_ATTR, "" + userPref.getSplitPane1().getSize()); writeEntry(out, indent + 2, SPLITPANE1_ELEM, attrValues, true); } if (userPref.getSplitPane2().getSize() >= 0) { AttrValuePair[] attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair(SPLITPANE_RIGHT_SIZE_ATTR, "" + userPref.getSplitPane2().getSize()); writeEntry(out, indent + 2, SPLITPANE2_ELEM, attrValues, true); } if (userPref.getSplitPane3().getSize() >= 0) { AttrValuePair[] attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair(SPLITPANE_RIGHT_SIZE_ATTR, "" + userPref.getSplitPane3().getSize()); writeEntry(out, indent + 2, SPLITPANE3_ELEM, attrValues, true); } if (userPref.getNavigationPanelDividerPosition() >= 0) { AttrValuePair[] attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair( SPLITPANE_POS_ATTR, "" + userPref.getNavigationPanelDividerPosition()); writeEntry(out, indent + 2, NAV_SPLITPANE_ELEM, attrValues, true); } if (userPref.getNavigationFilterSplitPane().getSize() >= 0 && userPref.getNavigationFilterSplitPane().getSize() < 300) { // FIXUP: sometimes Filter Status panel is too big (18307885) AttrValuePair[] attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair( SPLITPANE_RIGHT_SIZE_ATTR, "" + userPref.getNavigationFilterSplitPane().getSize()); writeEntry(out, indent + 2, NAV_FILTER_SPLITPANE_ELEM, attrValues, true); } writeRecentExperiments(out, indent + 2, userPref); writeHostNames(out, indent + 2, userPref); writeLastClosedConfPath(out, indent + 2, userPref); writeLastExportImportConfPath(out, indent + 2, userPref); writeCompareWarning(out, indent + 2, userPref); writeCustomMetricColors(out, indent + 2, userPref); writeEntry(out, indent, USER_ELEM, true); } if (whatList.contains(UserPref.What.VIEWS)) { writeViews(out, indent, userPref); } if (whatList.contains(UserPref.What.METRICS)) { writeMetrics(out, indent, userPref); } if (whatList.contains(UserPref.What.TIMELINE)) { writeTimeline(out, indent, userPref); } if (whatList.contains(UserPref.What.SOURCEDISASSEMBLY)) { writeSourceDisassembly(out, indent, userPref); } if (whatList.contains(UserPref.What.CALLTREE)) { writeCallStack(out, indent, userPref); } if (whatList.contains(UserPref.What.FORMATS)) { writeFormats(out, indent, userPref); } if (whatList.contains(UserPref.What.SEARCHPATH)) { writeSearchPath(out, indent, userPref); } if (whatList.contains(UserPref.What.PATHMAP)) { writePathmap(out, indent, userPref); } if (whatList.contains(UserPref.What.FUNCTIONCOLORS)) { writeFunctionColors(out, indent, userPref); } if (whatList.contains(UserPref.What.LIBRARYVISIBILITY)) { writeLibraryVisibility(out, indent, userPref); } if (whatList.contains(UserPref.What.MISC)) { writeMisc(out, indent, userPref); } } private void writeViews(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, VIEWS_ELEM, false); writeSideBar(out, indent + 2, userPref); writeMachineModel(out, indent + 2, userPref); writeCustomIndexObjects(out, indent + 2, userPref); writeCustomMemoryObjects(out, indent + 2, userPref); writeEntry(out, indent, VIEWS_ELEM, true); } private void writeSideBar(PrintWriter out, int indent, UserPref userPref) { if (userPref.getViewPanelOrder() != null && !userPref.getViewPanelOrder().isEmpty()) { writeEntry(out, indent + 2, VIEW_ORDER_LIST_ELEM, false); for (UserPref.ViewPanelOrder elem : userPref.getViewPanelOrder()) { AttrValuePair[] attrValues = new AttrValuePair[2]; attrValues[0] = new AttrValuePair(VIEW_ORDER_NAME_ATTR, "" + elem.getName()); attrValues[1] = new AttrValuePair(VIEW_ORDER_SHOWN_ATTR, "" + elem.isShown()); writeEntry(out, indent + 4, VIEW_ORDER_ELEM, attrValues, true); } writeEntry(out, indent + 2, VIEW_ORDER_LIST_ELEM, true); } } private void writeMetrics(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, METRICS_ELEM, false); List list = userPref.getMetricSelectionList(); if (list != null && !list.isEmpty()) { writeEntry(out, indent + 2, METRIC_SELECTION_LIST_ELEM, false); for (MetricNameSelection ms : list) { AttrValuePair[] attrValues = new AttrValuePair[8]; attrValues[0] = new AttrValuePair(METRIC_NAME_ATTR, "" + escapeSpecialCharacters(ms.getName())); attrValues[1] = new AttrValuePair(METRIC_ORDER_SELECTED_ATTR, "" + ms.isSelected()); attrValues[2] = new AttrValuePair( METRIC_ORDER_EXCLINCL_ATTR + 0, "" + ms.getMetricSelection().getAttributes().isETime()); attrValues[3] = new AttrValuePair( METRIC_ORDER_EXCLINCL_ATTR + 1, "" + ms.getMetricSelection().getAttributes().isEValue()); attrValues[4] = new AttrValuePair( METRIC_ORDER_EXCLINCL_ATTR + 2, "" + ms.getMetricSelection().getAttributes().isEPercent()); attrValues[5] = new AttrValuePair( METRIC_ORDER_EXCLINCL_ATTR + 3, "" + ms.getMetricSelection().getAttributes().isITime()); attrValues[6] = new AttrValuePair( METRIC_ORDER_EXCLINCL_ATTR + 4, "" + ms.getMetricSelection().getAttributes().isIValue()); attrValues[7] = new AttrValuePair( METRIC_ORDER_EXCLINCL_ATTR + 5, "" + ms.getMetricSelection().getAttributes().isIPercent()); writeEntry(out, indent + 4, METRIC_SELECTION_ELEM, attrValues, true); } writeEntry(out, indent + 2, METRIC_SELECTION_LIST_ELEM, true); } if (userPref.getMetricReversedSort() != userPref.getMetricReversedSortDefault()) { writeEntry(out, indent + 2, METRIC_REVERSED_SORT, "" + userPref.getMetricReversedSort()); } MetricType[] metricSortByMTypeList = userPref.getMetricSortByMTypeList(); if (metricSortByMTypeList != null) { writeEntry(out, indent + 2, METRIC_SORT_LIST_ELEM, false); for (int mType = 0; mType < metricSortByMTypeList.length; mType++) { if (mType > MetricsSetting.MET_NORMAL) { break; // Just save MET_NORMAL for now } AttrValuePair[] attrValues = new AttrValuePair[3]; attrValues[0] = new AttrValuePair(METRIC_MTYPE_ATTR, "" + mType); attrValues[1] = new AttrValuePair(METRIC_NAME_ATTR, "" + metricSortByMTypeList[mType].getCommand()); attrValues[2] = new AttrValuePair(METRIC_SUBTYPE_ATTR, "" + metricSortByMTypeList[mType].getSubType()); writeEntry(out, indent + 4, METRIC_SORT_ELEM, attrValues, true); } writeEntry(out, indent + 2, METRIC_SORT_LIST_ELEM, true); } List[] metricOrderLists = userPref.getMetricOrderLists(); if (metricOrderLists != null && metricOrderLists.length > 0) { writeEntry(out, indent + 2, METRIC_ORDER_LIST_ELEM, false); for (int mType = 0; mType < metricOrderLists.length; mType++) { if (mType > MetricsSetting.MET_NORMAL) { break; // Just save MET_NORMAL for now } AttrValuePair[] attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair(METRIC_MTYPE_ATTR, "" + mType); writeEntry(out, indent + 4, METRIC_ORDER_MTYPE_LIST_ELEM, attrValues, false); List orderList = metricOrderLists[mType]; for (MetricType metricType : orderList) { attrValues = new AttrValuePair[2]; attrValues[0] = new AttrValuePair(METRIC_NAME_ATTR, "" + metricType.getCommand()); attrValues[1] = new AttrValuePair(METRIC_SUBTYPE_ATTR, "" + metricType.getSubType()); writeEntry(out, indent + 6, METRIC_ORDER_ELEM, attrValues, true); } writeEntry(out, indent + 4, METRIC_ORDER_MTYPE_LIST_ELEM, true); } writeEntry(out, indent + 2, METRIC_ORDER_LIST_ELEM, true); } writeEntry(out, indent, METRICS_ELEM, true); } private void writeMachineModel(PrintWriter out, int indent, UserPref userPref) { if (userPref.getMachineModel() != null /*&& userPref.getLoadedMachineModel().length() > 0*/) { writeEntry(out, indent, MACHINE_MODEL_ELEM, "" + userPref.getMachineModel()); } } private void writeCustomMemoryObjects(PrintWriter out, int indent, UserPref userPref) { if (userPref.getCustomMemoryObjects() != null && !userPref.getCustomMemoryObjects().isEmpty()) { writeEntry(out, indent, MEMORY_OBJECT_LIST_ELEM, false); writeCustomObjectList(out, indent + 2, userPref.getCustomMemoryObjects()); writeEntry(out, indent, MEMORY_OBJECT_LIST_ELEM, true); } } private void writeCustomIndexObjects(PrintWriter out, int indent, UserPref userPref) { if (userPref.getCustomIndexObjects() != null && !userPref.getCustomIndexObjects().isEmpty()) { writeEntry(out, indent, INDEX_OBJECT_LIST_ELEM, false); writeCustomObjectList(out, indent + 2, userPref.getCustomIndexObjects()); writeEntry(out, indent, INDEX_OBJECT_LIST_ELEM, true); } } private void writeCustomObjectList(PrintWriter out, int indent, List list) { for (CustomObject customObject : list) { AttrValuePair[] attrValues = new AttrValuePair[2]; attrValues[0] = new AttrValuePair(CUSTOM_OBJECT_NAME_ATTR, customObject.getName()); attrValues[1] = new AttrValuePair( CUSTOM_OBJECT_FORMULA_ATTR, escapeSpecialCharacters(customObject.getFormula())); writeEntry(out, indent + 2, CUSTOM_OBJECT_LIST_ELEM, attrValues, true); } } private void writeRecentExperiments(PrintWriter out, int indent, UserPref userPref) { if (userPref.getExperimentsPicklists().getPicklistMap() != null && userPref.getExperimentsPicklists().getPicklistMap().size() > 0) { Map map = userPref.getExperimentsPicklists().getPicklistMap(); Set keySet = map.keySet(); for (String host : keySet) { ExperimentPickList experimentPicklist = map.get(host); AttrValuePair[] attrValues; attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair(HOST_NAME_ATTR, host); writeEntry(out, indent, EXPERIMENT_LIST_ELEM, attrValues, false); for (ExperimentPickListElement experiment : experimentPicklist.getRecentExperiments()) { int n = 1; if (experiment.getWorkingDirectory() != null) { n++; } if (experiment.getConfPath() != null) { n++; } attrValues = new AttrValuePair[n]; n = 0; attrValues[n++] = new AttrValuePair(PATH_ATTR, experiment.getPath()); if (experiment.getWorkingDirectory() != null) { attrValues[n++] = new AttrValuePair(WD_ATTR, experiment.getWorkingDirectory()); } if (experiment.getConfPath() != null) { attrValues[n++] = new AttrValuePair(CONF_ATTR, experiment.getConfPath()); } writeEntry(out, indent + 2, EXPERIMENT_ELEM, attrValues, true); } writeEntry(out, indent, EXPERIMENT_LIST_ELEM, true); } } } private void writeHostNames(PrintWriter out, int indent, UserPref userPref) { if (userPref.getHostNamePicklist() != null && userPref.getHostNamePicklist().getSize() > 0 && userPref.getConnectionPropertiesMap() != null && !userPref.getConnectionPropertiesMap().isEmpty()) { writeEntry(out, indent, HOSTNAME_LIST_ELEM, false); List elements = userPref.getHostNamePicklist().getStringElements(); for (int i = elements.size() - 1; i >= 0; i--) { StringPickListElement hostElement = elements.get(i); String hostName = hostElement.getString(); String path = userPref.getConnectionPropertiesMap().get(hostName).getPath(); String userName = userPref.getConnectionPropertiesMap().get(hostName).getUserName(); List authentications = userPref.getConnectionPropertiesMap().get(hostName).getAuthentications(); if (userName == null) { userName = ""; } if (path != null) { List attrValues = new ArrayList(); attrValues.add(new AttrValuePair(HOSTNAME_NAME_ATTR, hostName)); attrValues.add(new AttrValuePair(HOSTNAME_PATH_ATTR, path)); attrValues.add(new AttrValuePair(HOSTNAME_USERNAME_ATTR, userName)); if (!Authentication.toXMLString(UserPref.getDefaultAuthentications()) .equals(Authentication.toXMLString(authentications))) { attrValues.add( new AttrValuePair(HOSTNAME_AUTH_ATTR, Authentication.toXMLString(authentications))); } writeEntry( out, indent + 4, HOSTNAME_ELEM, attrValues.toArray(new AttrValuePair[attrValues.size()]), true); } } writeEntry(out, indent, HOSTNAME_LIST_ELEM, true); } } private void writeLastClosedConfPath(PrintWriter out, int indent, UserPref userPref) { if (userPref.getLastClosedExpConfPath() != null) { writeEntry(out, indent, LAST_CLOSED_EXP_CONF_PATH_ELEM, userPref.getLastClosedExpConfPath()); } } private void writeLastExportImportConfPath(PrintWriter out, int indent, UserPref userPref) { if (userPref.getLastExportImportConfPath() != null) { writeEntry( out, indent, LAST_EXPORT_IMPORT_EXP_CONF_PATH_ELEM, userPref.getLastExportImportConfPath()); } } private void writeCompareWarning(PrintWriter out, int indent, UserPref userPref) { if (userPref.showCompareSourceWarning() != userPref.showCompareSourceWarningDefault()) { writeEntry(out, indent, SHOW_COMPARE_WARNING_ELEM, "" + userPref.showCompareSourceWarning()); } } private void writeCustomMetricColors(PrintWriter out, int indent, UserPref userPref) { if (userPref.getCustomMetricColors() != null) { writeEntry(out, indent, METRIC_COLOR_LIST_ELEM, false); List metricColors = userPref.getCustomMetricColors(); for (MetricColor metricColor : metricColors) { String colorHexRed = String.format("%02x", metricColor.getColor().getRed()); String colorHexGreen = String.format("%02x", metricColor.getColor().getGreen()); String colorHexBlue = String.format("%02x", metricColor.getColor().getBlue()); String colorHex = "0x" + colorHexRed + colorHexGreen + colorHexBlue; AttrValuePair[] attrValues = new AttrValuePair[2]; attrValues[0] = new AttrValuePair(METRIC_COLOR_NAME_ATTR, metricColor.getMetricName()); attrValues[1] = new AttrValuePair(METRIC_COLOR_COLOR_ATTR, colorHex); writeEntry(out, indent + 2, METRIC_COLOR_ITEM_ELEM, attrValues, true); } writeEntry(out, indent, METRIC_COLOR_LIST_ELEM, true); } } private void writeFindPickList(PrintWriter out, int indent, UserPref userPref) { if (userPref.getFindPickList() != null && userPref.getFindPickList().getSize() > 0) { writeEntry(out, indent, FIND_LIST_ELEM, false); List elements = userPref.getFindPickList().getStringElements(); for (int i = elements.size() - 1; i >= 0; i--) { String elem = escapeSpecialCharacters(elements.get(i).getString()); writeEntry(out, indent + 2, FIND_ELEM, elem); } writeEntry(out, indent, FIND_LIST_ELEM, true); } } private void writeWhatList(PrintWriter out, int indent, List whatList) { writeEntry(out, indent, WHAT_LIST_ELEM, false); if (whatList != null && !whatList.isEmpty()) { for (UserPref.What what : whatList) { writeEntry(out, indent + 2, WHAT_ELEM, what.toString()); } } writeEntry(out, indent, WHAT_LIST_ELEM, true); } private void writeLibraryVisibilityPickList(PrintWriter out, int indent, UserPref userPref) { if (userPref.getLibraryVisibilityIncludePickList() != null && userPref.getLibraryVisibilityIncludePickList().getSize() > 0) { String currentLibraryVisibilityFilter = userPref.getLibraryVisibilityIncludeFilter(); if (currentLibraryVisibilityFilter != null && currentLibraryVisibilityFilter.length() > 0) { AttrValuePair[] attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair( LIBRARY_VISIBILITY_CURRENT_FILTER_ATTR, currentLibraryVisibilityFilter); writeEntry(out, indent, LIBRARY_VISIBILITY_INCLUDE_FILTER_LIST_ELEM, attrValues, false); } else { writeEntry(out, indent, LIBRARY_VISIBILITY_INCLUDE_FILTER_LIST_ELEM, false); } List elements = userPref.getLibraryVisibilityIncludePickList().getStringElements(); for (int i = elements.size() - 1; i >= 0; i--) { String elem = escapeSpecialCharacters(elements.get(i).getString()); writeEntry(out, indent + 2, LIBRARY_VISIBILITY_INCLUDE_FILTER_ELEM, elem); } writeEntry(out, indent, LIBRARY_VISIBILITY_INCLUDE_FILTER_LIST_ELEM, true); } if (userPref.getLibraryVisibilityExcludePickList() != null && userPref.getLibraryVisibilityExcludePickList().getSize() > 0) { String currentLibraryVisibilityFilter = userPref.getCurrenLibraryVisibilityExcludeFilter(); if (currentLibraryVisibilityFilter != null && currentLibraryVisibilityFilter.length() > 0) { AttrValuePair[] attrValues = new AttrValuePair[1]; attrValues[0] = new AttrValuePair( LIBRARY_VISIBILITY_CURRENT_FILTER_ATTR, currentLibraryVisibilityFilter); writeEntry(out, indent, LIBRARY_VISIBILITY_EXCLUDE_FILTER_LIST_ELEM, attrValues, false); } else { writeEntry(out, indent, LIBRARY_VISIBILITY_EXCLUDE_FILTER_LIST_ELEM, false); } List elements = userPref.getLibraryVisibilityExcludePickList().getStringElements(); for (int i = elements.size() - 1; i >= 0; i--) { String elem = escapeSpecialCharacters(elements.get(i).getString()); writeEntry(out, indent + 2, LIBRARY_VISIBILITY_EXCLUDE_FILTER_ELEM, elem); } writeEntry(out, indent, LIBRARY_VISIBILITY_EXCLUDE_FILTER_LIST_ELEM, true); } } private void writeCallStack(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, CALL_TREE_PROP, false); if (userPref.getCallStackThreshold() != userPref.getCallStackThresholdDefault()) { writeEntry(out, indent + 2, CALL_TREE_THRESHOLD, "" + userPref.getCallStackThreshold()); } writeEntry(out, indent, CALL_TREE_PROP, true); } private void writeFormats(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, FORMATS_ELEM, false); if (userPref.getFormatsViewMode() != userPref.getFormatsViewModeDefault()) { writeEntry(out, indent + 2, FORMATS_VIEW_MODE, "" + userPref.getFormatsViewMode()); } if (userPref.getFormatsStyle() != userPref.getFormatsStyleDefault()) { writeEntry(out, indent + 2, FORMATS_STYLE, "" + userPref.getFormatsStyle()); } if (userPref.getFormatsAppendSoName() != userPref.getFormatsAppendSoNameDefault()) { writeEntry(out, indent + 2, FORMATS_APPEND_SO_NAME, "" + userPref.getFormatsAppendSoName()); } if (userPref.getFormatsCompareMode() != userPref.getFormatsCompareModeDefault()) { writeEntry(out, indent + 2, FORMATS_COMPARE_MODE, "" + userPref.getFormatsCompareMode()); } if (userPref.wrapMetricNamesInTables() != userPref.wrapMetricNamesInTablesDefault()) { writeEntry( out, indent + 2, FORMATS_WRAP_METRIC_NAMES_IN_TABLES_ELEM, "" + userPref.wrapMetricNamesInTables()); } writeEntry(out, indent, FORMATS_ELEM, true); } private void writeSourceDisassembly(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, SOURCE_DISASSEMBLY_ELEM, false); if (SourceDisassemblySetting.changed( userPref.getSourceDisassemblySettingsDefault(), userPref.getSourceDisassemblySettings())) { int[] values = userPref.getSourceDisassemblySettings(); writeEntry(out, indent + 2, SOURCE_DISASSEMBLY, false); for (int value : values) { writeEntry(out, indent + 4, VALUE_ELEM, "" + value); } writeEntry(out, indent + 2, SOURCE_DISASSEMBLY, true); } writeEntry(out, indent, SOURCE_DISASSEMBLY_ELEM, true); } private void writeLibraryVisibility(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, LIBRARY_VISIBILITY_ELEM, false); writeLibraryVisibilityLoadObjects(out, indent + 2, userPref); writeLibraryVisibilityNativeOrJava(out, indent + 2, userPref); writeLibraryVisibilityPickList(out, indent + 2, userPref); writeEntry(out, indent, LIBRARY_VISIBILITY_ELEM, true); } private void writeMisc(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, MISC_ELEM, false); writeFindPickList(out, indent + 2, userPref); writeEntry(out, indent, MISC_ELEM, true); } private void writeFunctionColors(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, CALL_STACK_FUNCTION_COLORS_ELEM, false); List activeColorRules = userPref.getActiveColorRules(); if (activeColorRules != null && !activeColorRules.isEmpty()) { writeEntry(out, indent + 2, FUNCTION_COLORS_LIST_ELEM, false); writeColorRules(out, indent + 4, activeColorRules); writeEntry(out, indent + 2, FUNCTION_COLORS_LIST_ELEM, true); } writeEntry(out, indent, CALL_STACK_FUNCTION_COLORS_ELEM, true); } private void writeTimeline(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, TIMELINE_ELEM, false); if (!userPref .getTimelineGroupDataByButtonName() .equalsIgnoreCase(userPref.getTimelineGroupDataByButtonNameDefault())) { writeEntry( out, indent + 2, TIMELINE_GROUP_DATA_BY_BUTTON_NAME_ELEM, "" + escapeSpecialCharacters(userPref.getTimelineGroupDataByButtonName())); } if (!userPref.getTimelineTLDataCmd().equalsIgnoreCase(userPref.getTimelineTLDataCmdDefault())) { writeEntry(out, indent + 2, TIMELINE_TLDATA_CMD_ELEM, "" + userPref.getTimelineTLDataCmd()); } if (userPref.getTimelineStackAlign() != userPref.getDefaultTimelineStackAlign()) { writeEntry(out, indent + 2, TIMELINE_STACK_ALIGN_ELEM, "" + userPref.getTimelineStackAlign()); } if (userPref.getTimelineStackDepth() != userPref.getTimelineStackDepthDefault()) { writeEntry(out, indent + 2, TIMELINE_STACK_DEPTH_ELEM, "" + userPref.getTimelineStackDepth()); } if (userPref.getTimelineStackFramePixels() != userPref.getTimelineStackFramePixelsDefault()) { writeEntry( out, indent + 2, TIMELINE_STACK_FRAME_PIXELS_ELEM, "" + userPref.getTimelineStackFramePixels()); } if (userPref.getTimelineShowEventStates() != userPref.getTimelineShowEventStatesDefault()) { writeEntry( out, indent + 2, TIMELINE_SHOW_STATES_ELEM, "" + userPref.getTimelineShowEventStates()); } if (userPref.getTimelineShowEventDensity() != userPref.getTimelineShowEventDensityDefault()) { writeEntry( out, indent + 2, TIMELINE_SHOW_DENSITY_ELEM, "" + userPref.getTimelineShowEventDensity()); } writeEntry(out, indent, TIMELINE_ELEM, true); } private void writeLibraryVisibilityNativeOrJava(PrintWriter out, int indent, UserPref userPref) { if (userPref.getLibraryVisibilityJava() != userPref.getLibraryVisibilityJavaDefault()) { writeEntry(out, indent, LIBRARY_VISIBILITY_JAVA, "" + userPref.getLibraryVisibilityJava()); } } private void writeLibraryVisibilityLoadObjects(PrintWriter out, int indent, UserPref userPref) { List list = userPref.getLibraryVisibilitySettings(); if (list != null && !list.isEmpty()) { writeEntry(out, indent, LOADOBJECT_LIST_ELEM, false); for (String s : list) { writeEntry(out, indent + 2, LOADOBJECT_ITEM_ELEM, escapeSpecialCharacters(s)); } writeEntry(out, indent, LOADOBJECT_LIST_ELEM, true); } } private void writeSearchPath(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, SEARCHPATH_ELEM, false); List list = userPref.getSearchPath(); if (list != null && !list.isEmpty()) { if (!SearchPathSetting.isDefault(list)) { writeEntry(out, indent + 2, SEARCHPATH_LIST_ELEM, false); for (String s : list) { writeEntry(out, indent + 4, SEARCHPATH_ITEM_ELEM, escapeSpecialCharacters(s)); } writeEntry(out, indent + 2, SEARCHPATH_LIST_ELEM, true); } } writeEntry(out, indent, SEARCHPATH_ELEM, true); } private void writePathmap(PrintWriter out, int indent, UserPref userPref) { writeEntry(out, indent, PATHMAP_ELEM, false); String[][] pathmap = userPref.getPathmap(); if (pathmap != null && pathmap.length > 0) { if (!PathMapSetting.isDefault(pathmap)) { writeEntry(out, indent + 2, PATHMAP_LIST_ELEM, false); for (int i = 0; i < pathmap[0].length; i++) { String from = pathmap[0][i]; String to = pathmap[1][i]; AttrValuePair[] attrValues = new AttrValuePair[2]; attrValues[0] = new AttrValuePair(PATHMAP_FROM_ATTR, from); attrValues[1] = new AttrValuePair(PATHMAP_TO_ATTR, to); writeEntry(out, indent + 4, PATHMAP_ITEM_ELEM, attrValues, true); } writeEntry(out, indent + 2, PATHMAP_LIST_ELEM, true); } } writeEntry(out, indent, PATHMAP_ELEM, true); } private void writeColorRules(PrintWriter out, int indent, List colorRules) { if (colorRules != null) { for (ColorRule cr : colorRules) { AttrValuePair[] attrValues = new AttrValuePair[3]; attrValues[0] = new AttrValuePair(FUNCTION_COLORS_COLOR_RULE_TYPE_ATTR, "" + cr.getType()); String text = cr.getText() != null ? cr.getText() : ""; attrValues[1] = new AttrValuePair(FUNCTION_COLORS_COLOR_RULE_TEXT_ATTR, escapeSpecialCharacters(text)); attrValues[2] = new AttrValuePair(FUNCTION_COLORS_COLOR_RULE_COLOR_ATTR, "" + cr.getColor().getRGB()); writeEntry(out, indent, FUNCTION_COLORS_COLOR_RULE_ELEM, attrValues, true); } } } private String escapeSpecialCharacters(String s) { s = s.replace("&", "&"); s = s.replace("<", "<"); s = s.replace(">", ">"); s = s.replace("'", "'"); s = s.replace("\"", """); return s; } /** Write entry of this type: or */ private void writeEntry( PrintWriter out, int indent, String elemname, AttrValuePair[] attrValues, boolean b) { if (indent > 0) { out.print(spaces.substring(0, indent)); } out.print("<"); out.print(elemname); if (attrValues != null) { for (int i = 0; i < attrValues.length; i++) { out.print(" " + attrValues[i].getAttr() + "=\"" + attrValues[i].getValue() + "\""); } } if (b) { out.print("/"); } out.println(">"); } /** Write entry of this type: or */ private void writeEntry(PrintWriter out, int indent, String elemname, boolean b) { if (indent > 0) { out.print(spaces.substring(0, indent)); } out.print("<"); if (b) { out.print("/"); } out.print(elemname); out.println(">"); } /** Write entry of this type: v */ private void writeEntry(PrintWriter out, int indent, String elemname, String v) { if (indent > 0) { out.print(spaces.substring(0, indent)); } out.print("<"); out.print(elemname); out.print(">"); out.print(v); out.print(""); } private class AttrValuePair { private String attr; private String value; public AttrValuePair(String attr, String value) { this.attr = attr; this.value = value; } public String getAttr() { return attr; } public String getValue() { return value; } } class MySaxParser extends DefaultHandler { private Stack stack = new Stack(); private String currentElement = null; private String currentText = ""; private List viewPanelOrderList; private List recentExperiments; private String recentExperimentsHost; private Map connectionPropertiesMap; private StringPickList hostNamePickList; private StringPickList findPickList; private List whatList; private StringPickList libraryVisibilityIncludeFilterPickList; private StringPickList libraryVisibilityExcludeFilterPickList; private List sourceDisassemblyValues; private List customIndexObjects; private List customMemoryObjects; private List functionColors; private List metricsOrderList; private MetricType[] metricSortByMType; private List[] metricOrderLists; private int orderMtype; private List metricOrderMTypeList; private List loadobjectList; private List searchPathList; private List pathmap; private List customMetricColors; public void startDocument() throws SAXException {} public void startElement(String namespaceURI, String localName, String element, Attributes atts) throws SAXException { if (element.equals(FRAME_ELEM)) { String w = atts.getValue(FRAME_WIDTH_ATTR); String h = atts.getValue(FRAME_HEIGHT_ATTR); String x = atts.getValue(FRAME_X_ATTR); String y = atts.getValue(FRAME_Y_ATTR); try { Dimension dim = new Dimension(new Integer(w).intValue(), new Integer(h).intValue()); Point point = new Point(new Integer(x).intValue(), new Integer(y).intValue()); userPref.setFrameSize(dim); userPref.setFrameLocation(point); } catch (NumberFormatException nfe) { errorMessage("INIT_FILE_ERROR", element, nfe); } } else if (element.equals(VIEW_ORDER_LIST_ELEM)) { viewPanelOrderList = new ArrayList(); } else if (element.equals(METRIC_SELECTION_LIST_ELEM) || element.equals(METRIC_SELECTION_LIST_ELEM_V12)) { metricsOrderList = new ArrayList(); } else if (element.equals(METRIC_SORT_LIST_ELEM)) { metricSortByMType = new MetricType[MetricsSetting.MET_LAST]; } else if (element.equals(METRIC_ORDER_LIST_ELEM)) { metricOrderLists = (ArrayList[]) new ArrayList[MetricsSetting.MET_LAST]; } else if (element.equals(METRIC_ORDER_MTYPE_LIST_ELEM)) { String orderMtypeString = atts.getValue(METRIC_MTYPE_ATTR); orderMtype = new Integer(orderMtypeString).intValue(); metricOrderMTypeList = new ArrayList(); } else if (element.equals(LOADOBJECT_LIST_ELEM)) { loadobjectList = new ArrayList(); } else if (element.equals(SEARCHPATH_LIST_ELEM)) { searchPathList = new ArrayList(); } else if (element.equals(PATHMAP_LIST_ELEM)) { pathmap = new ArrayList(); } else if (element.equals(PATHMAP_ITEM_ELEM)) { String from = atts.getValue(PATHMAP_FROM_ATTR); String to = atts.getValue(PATHMAP_TO_ATTR); String[] map = new String[2]; map[0] = from; map[1] = to; pathmap.add(map); } else if (element.equals(INDEX_OBJECT_LIST_ELEM)) { customIndexObjects = new ArrayList(); } else if (element.equals(FUNCTION_COLORS_LIST_ELEM)) { functionColors = new ArrayList(); } else if (element.equals(MEMORY_OBJECT_LIST_ELEM)) { customMemoryObjects = new ArrayList(); } else if (element.equals(EXPERIMENT_LIST_ELEM)) { String host = "localhost"; // pre version 5 if (userPref.getVersion() >= 5) { host = atts.getValue(HOST_NAME_ATTR); } recentExperiments = new ArrayList(); recentExperimentsHost = host; } else if (element.equals(EXPERIMENT_ELEM)) { String path = atts.getValue(PATH_ATTR); String wd = atts.getValue(WD_ATTR); String confPath = atts.getValue(CONF_ATTR); recentExperiments.add(new ExperimentPickListElement(path, wd, confPath)); } else if (element.equals(HOSTNAME_LIST_ELEM)) { connectionPropertiesMap = new HashMap(); hostNamePickList = new StringPickList(); } else if (element.equals(METRIC_COLOR_LIST_ELEM)) { customMetricColors = new ArrayList(); } else if (element.equals(HOSTNAME_ELEM)) { String name = atts.getValue(HOSTNAME_NAME_ATTR); String path = atts.getValue(HOSTNAME_PATH_ATTR); String userName = null; if (userPref.getVersion() >= 4) { userName = atts.getValue(HOSTNAME_USERNAME_ATTR); } List authentications = null; String auth = atts.getValue(HOSTNAME_AUTH_ATTR); if (auth != null) { authentications = Authentication.fromXMLString(auth); } if (authentications == null) { authentications = UserPref.getDefaultAuthentications(); } connectionPropertiesMap.put( name, new ConnectionProperties(path, userName, authentications)); hostNamePickList.addElement(name); } else if (element.equals(METRIC_COLOR_ITEM_ELEM)) { String name = atts.getValue(METRIC_COLOR_NAME_ATTR); String colorString = atts.getValue(METRIC_COLOR_COLOR_ATTR); int colorVal; if (colorString.startsWith("0x")) { colorVal = Integer.parseInt(colorString.substring(2), 16); } else { colorVal = Integer.parseInt(colorString, 10); } Color color = new Color(colorVal); customMetricColors.add(new MetricColor(name, color)); UserPref.getInstance().setCustomMetricColors(customMetricColors); } else if (element.equals(FIND_LIST_ELEM)) { findPickList = new StringPickList(FindTextPanel.MAX_FIND_ITEMS); } else if (element.equals(WHAT_LIST_ELEM)) { whatList = new ArrayList(); } else if (element.equals(LIBRARY_VISIBILITY_INCLUDE_FILTER_LIST_ELEM)) { String currentLibrryVisibilityFilter = atts.getValue(LIBRARY_VISIBILITY_CURRENT_FILTER_ATTR); UserPref.getInstance().setLibraryVisibilityIncludeFilter(currentLibrryVisibilityFilter); libraryVisibilityIncludeFilterPickList = new StringPickList(FindTextPanel.MAX_FIND_ITEMS); } else if (element.equals(LIBRARY_VISIBILITY_EXCLUDE_FILTER_LIST_ELEM)) { String currentLibraryVisibilityFilter = atts.getValue(LIBRARY_VISIBILITY_CURRENT_FILTER_ATTR); UserPref.getInstance() .setCurrentLibraryVisibilityExcludeFilter(currentLibraryVisibilityFilter); libraryVisibilityExcludeFilterPickList = new StringPickList(FindTextPanel.MAX_FIND_ITEMS); } else if (element.equals(VIEW_ORDER_ELEM)) { String name = atts.getValue(VIEW_ORDER_NAME_ATTR); String shownString = atts.getValue(VIEW_ORDER_SHOWN_ATTR); viewPanelOrderList.add(new ViewPanelOrder(name, new Boolean(shownString).booleanValue())); } else if (element.equals(METRIC_SELECTION_ELEM)) { if (metricsOrderList != null) { String name = atts.getValue(METRIC_NAME_ATTR); boolean selected = new Boolean(atts.getValue(METRIC_ORDER_SELECTED_ATTR)).booleanValue(); boolean[] exclIncl = new boolean[6]; for (int i = 0; i < 6; i++) { boolean val = new Boolean(atts.getValue(METRIC_ORDER_EXCLINCL_ATTR + i)).booleanValue(); exclIncl[i] = val; } MetricNameSelection metricSetting = new MetricNameSelection(name, selected, exclIncl); metricsOrderList.add(metricSetting); } } else if (element.equals(METRIC_SORT_ELEM)) { if (metricSortByMType != null) { String mTypeString = atts.getValue(METRIC_MTYPE_ATTR); String name = atts.getValue(METRIC_NAME_ATTR); String subTypeString = atts.getValue(METRIC_SUBTYPE_ATTR); int mType = new Integer(mTypeString).intValue(); int subType = new Integer(subTypeString).intValue(); if (mType >= 0 && mType <= MetricsSetting.MET_LAST) { metricSortByMType[mType] = new MetricType(name, subType); } } } else if (element.equals(METRIC_ORDER_ELEM)) { if (metricOrderMTypeList != null) { String name = atts.getValue(METRIC_NAME_ATTR); String subTypeString = atts.getValue(METRIC_SUBTYPE_ATTR); int subType = new Integer(subTypeString).intValue(); metricOrderMTypeList.add(new MetricType(name, subType)); } } else if (element.equals(CUSTOM_OBJECT_LIST_ELEM)) { String name = atts.getValue(CUSTOM_OBJECT_NAME_ATTR); String cormula = atts.getValue(CUSTOM_OBJECT_FORMULA_ATTR); CustomObject customObject = new CustomObject(name, cormula, null, null); // CXXX add descriptions if (customIndexObjects != null) { customIndexObjects.add(customObject); } else if (customMemoryObjects != null) { customMemoryObjects.add(customObject); } } else if (element.equals(FUNCTION_COLORS_COLOR_RULE_ELEM)) { int type = new Integer(atts.getValue(FUNCTION_COLORS_COLOR_RULE_TYPE_ATTR)).intValue(); String text = atts.getValue(FUNCTION_COLORS_COLOR_RULE_TEXT_ATTR); if (text.length() == 0) { text = null; } int colorValue = new Integer(atts.getValue(FUNCTION_COLORS_COLOR_RULE_COLOR_ATTR)).intValue(); Color color = new Color(colorValue); if (functionColors != null) { functionColors.add(new ColorRule(color, type, text, false)); } } else if (element.equals(NAV_SPLITPANE_ELEM)) { String pos = atts.getValue(SPLITPANE_POS_ATTR); try { int posValue = new Integer(pos); userPref.setNavigationPanelDividerPosition(posValue); } catch (NumberFormatException nfe) { errorMessage("INIT_FILE_ERROR", element, nfe); } } else if (element.equals(NAV_FILTER_SPLITPANE_ELEM)) { try { splitPaneProp(atts, userPref.getNavigationFilterSplitPane()); } catch (NumberFormatException nfe) { errorMessage("INIT_FILE_ERROR", element, nfe); } } else if (element.equals(SPLITPANE1_ELEM)) { try { splitPaneProp(atts, userPref.getSplitPane1()); } catch (NumberFormatException nfe) { errorMessage("INIT_FILE_ERROR", element, nfe); } } else if (element.equals(SPLITPANE2_ELEM)) { try { splitPaneProp(atts, userPref.getSplitPane2()); } catch (NumberFormatException nfe) { errorMessage("INIT_FILE_ERROR", element, nfe); } } else if (element.equals(SPLITPANE3_ELEM)) { try { splitPaneProp(atts, userPref.getSplitPane3()); } catch (NumberFormatException nfe) { errorMessage("INIT_FILE_ERROR", element, nfe); } } else if (element.equals(SOURCE_DISASSEMBLY)) { sourceDisassemblyValues = new ArrayList(); } currentElement = element; stack.push(currentElement); } private void splitPaneProp( Attributes atts, UserPref.SplitPaneFixedRightSizeProp splitPaneFixedRightSizeProp) throws NumberFormatException { String sizeString = atts.getValue(SPLITPANE_RIGHT_SIZE_ATTR); if (sizeString != null) { int size = new Integer(sizeString); splitPaneFixedRightSizeProp.setSize(size); } } @Override public void characters(char[] ch, int start, int length) { String newcurrentText = new String(ch, start, length); if (newcurrentText.length() > 0 && newcurrentText.charAt(0) == '\n') { currentText = ""; } else { currentText = currentText + newcurrentText; } } @Override public void endElement(java.lang.String uri, java.lang.String localName, java.lang.String qName) throws SAXException { try { if (qName.equals(VERSION_ELEM)) { userPref.setVersion(new Integer(currentText).intValue()); } else if (qName.equals(LAST_CLOSED_EXP_CONF_PATH_ELEM)) { userPref.setLastClosedExpConfPath(currentText); } else if (qName.equals(LAST_EXPORT_IMPORT_EXP_CONF_PATH_ELEM)) { userPref.setLastExportImportConfPath(currentText); } else if (qName.equals(SHOW_COMPARE_WARNING_ELEM)) { userPref.setShowCompareSourceWarning(new Boolean(currentText).booleanValue()); } else if (qName.equals(LIBRARY_VISIBILITY_JAVA)) { userPref.setLibraryVisibilityJava(new Boolean(currentText).booleanValue()); } else if (qName.equals(FORMATS_WRAP_METRIC_NAMES_IN_TABLES_ELEM)) { userPref.setWrapMetricNamesInTables(new Boolean(currentText).booleanValue()); } else if (qName.equals(METRIC_REVERSED_SORT)) { userPref.setMetricReversedSort(new Boolean(currentText).booleanValue()); } else if (qName.equals(VIEW_ORDER_LIST_ELEM)) { userPref.setViewPanelOrder(viewPanelOrderList); viewPanelOrderList = null; } else if (qName.equals(METRIC_SELECTION_LIST_ELEM) || qName.equals(METRIC_SELECTION_LIST_ELEM_V12)) { userPref.setMetricSelectionList(metricsOrderList); metricsOrderList = null; } else if (qName.equals(METRIC_SORT_LIST_ELEM)) { userPref.setMetricSortByMTypeList(metricSortByMType); metricSortByMType = null; } else if (qName.equals(METRIC_ORDER_LIST_ELEM)) { userPref.setMetricOrderLists(metricOrderLists); metricOrderLists = null; } else if (qName.equals(METRIC_ORDER_MTYPE_LIST_ELEM)) { metricOrderLists[orderMtype] = metricOrderMTypeList; metricOrderMTypeList = null; } else if (qName.equals(LOADOBJECT_ITEM_ELEM)) { loadobjectList.add(currentText); } else if (qName.equals(SEARCHPATH_ITEM_ELEM)) { searchPathList.add(currentText); } else if (qName.equals(LOADOBJECT_LIST_ELEM)) { userPref.setLibraryVisibilitySettings(loadobjectList); loadobjectList = null; } else if (qName.equals(SEARCHPATH_LIST_ELEM)) { userPref.setSearchPath(searchPathList); searchPathList = null; } else if (qName.equals(PATHMAP_LIST_ELEM)) { String[][] pathmap2 = new String[2][pathmap.size()]; for (int i = 0; i < pathmap.size(); i++) { String[] pathmapItem = pathmap.get(i); pathmap2[0][i] = pathmapItem[0]; pathmap2[1][i] = pathmapItem[1]; } userPref.setPathmap(pathmap2); pathmap = null; } else if (qName.equals(INDEX_OBJECT_LIST_ELEM)) { userPref.setCustomIndexObjects(customIndexObjects); customIndexObjects = null; } else if (qName.equals(FUNCTION_COLORS_LIST_ELEM)) { userPref.setActiveColorRules(functionColors); functionColors = null; } else if (qName.equals(MEMORY_OBJECT_LIST_ELEM)) { userPref.setCustomMemoryObjects(customMemoryObjects); customMemoryObjects = null; } else if (qName.equals(EXPERIMENT_PATH_ELEM)) { recentExperiments.add(new ExperimentPickListElement(currentText, null, null)); } else if (qName.equals(EXPERIMENT_LIST_ELEM)) { userPref.getExperimentsPicklists().add(recentExperimentsHost, recentExperiments); recentExperiments = null; recentExperimentsHost = null; } else if (qName.equals(HOSTNAME_LIST_ELEM)) { userPref.setConnectionPropertiesMap(connectionPropertiesMap); connectionPropertiesMap = null; userPref.setHostNamePicklist(hostNamePickList); hostNamePickList = null; } else if (qName.equals(METRIC_COLOR_LIST_ELEM)) { userPref.setCustomMetricColors(customMetricColors); customMetricColors = null; } else if (qName.equals(FIND_ELEM)) { findPickList.addElement(currentText); } else if (qName.equals(WHAT_ELEM)) { UserPref.What what = UserPref.What.toWhat(currentText); if (what != null) { whatList.add(what); } } else if (qName.equals(LIBRARY_VISIBILITY_INCLUDE_FILTER_ELEM)) { libraryVisibilityIncludeFilterPickList.addElement(currentText); } else if (qName.equals(LIBRARY_VISIBILITY_EXCLUDE_FILTER_ELEM)) { libraryVisibilityExcludeFilterPickList.addElement(currentText); } else if (qName.equals(FIND_LIST_ELEM)) { userPref.setFindPickList(findPickList); findPickList = null; } else if (qName.equals(WHAT_LIST_ELEM)) { userPref.setWhatList(whatList); whatList = null; } else if (qName.equals(LIBRARY_VISIBILITY_INCLUDE_FILTER_LIST_ELEM)) { userPref.setLibraryVisibilityIncludePickList(libraryVisibilityIncludeFilterPickList); libraryVisibilityIncludeFilterPickList = null; } else if (qName.equals(LIBRARY_VISIBILITY_EXCLUDE_FILTER_LIST_ELEM)) { userPref.setLibraryVisibilityExcludePickList(libraryVisibilityExcludeFilterPickList); libraryVisibilityExcludeFilterPickList = null; } else if (qName.equals(CALL_TREE_THRESHOLD)) { userPref.setCallStackThreshold(new Integer(currentText).intValue()); } else if (qName.equals(TIMELINE_GROUP_DATA_BY_BUTTON_NAME_ELEM)) { userPref.setTimelineGroupDataByButtonName(currentText); } else if (qName.equals(TIMELINE_TLDATA_CMD_ELEM)) { userPref.setTimelineTLDataCmd(currentText); } else if (qName.equals(TIMELINE_STACK_ALIGN_ELEM)) { userPref.setTimelineStackAlign(new Integer(currentText).intValue()); } else if (qName.equals(TIMELINE_STACK_DEPTH_ELEM)) { userPref.setTimelineStackDepth(new Integer(currentText).intValue()); } else if (qName.equals(TIMELINE_STACK_FRAME_PIXELS_ELEM)) { userPref.setTimelineStackFramePixels(new Integer(currentText).intValue()); } else if (qName.equals(TIMELINE_SHOW_STATES_ELEM)) { userPref.setTimelineShowEventStates(new Boolean(currentText).booleanValue()); } else if (qName.equals(TIMELINE_SHOW_DENSITY_ELEM)) { userPref.setTimelineShowEventDensity(new Boolean(currentText).booleanValue()); } else if (qName.equals(MACHINE_MODEL_ELEM)) { userPref.setMachineModel(currentText); } else if (qName.equals(FORMATS_VIEW_MODE)) { userPref.setFormatsViewMode(new Integer(currentText).intValue()); } else if (qName.equals(FORMATS_STYLE)) { userPref.setFormatsStyle(new Integer(currentText).intValue()); } else if (qName.equals(FORMATS_APPEND_SO_NAME)) { userPref.setFormatsAppendSoName(new Boolean(currentText)); } else if (qName.equals(FORMATS_COMPARE_MODE)) { userPref.setFormatsCompareMode(new Integer(currentText).intValue()); } else if (qName.equals(VALUE_ELEM)) { sourceDisassemblyValues.add(new Integer(currentText).intValue()); } else if (qName.equals(SOURCE_DISASSEMBLY)) { // If reading older versions, copy default dettings into missing values int[] defaultSettings = SourceDisassemblySetting.getDefaultSourceDisassemblySetting(); int[] values = new int[defaultSettings.length]; int i = 0; for (i = 0; i < sourceDisassemblyValues.size(); i++) { if (i < values.length) { values[i] = sourceDisassemblyValues.get(i); } } // If reading an older version, fill in with default values for the missing settings for (; i < defaultSettings.length; i++) { values[i] = defaultSettings[i]; } userPref.setSourceDisassemblySettings(values); } } catch (NumberFormatException ne) { } stack.pop(); if (stack.empty()) { currentElement = null; } else { currentElement = (String) stack.peek(); } } public void endDocument() throws SAXException {} } class MyErrorHandler implements ErrorHandler { private PrintStream out; MyErrorHandler(PrintStream out) { this.out = out; } private String getParseExceptionInfo(SAXParseException spe) { String systemId = spe.getSystemId(); if (systemId == null) { systemId = "null"; } String info = "URI=" + systemId + " Line=" + spe.getLineNumber() + ": " + spe.getMessage(); return info; } public void warning(SAXParseException spe) throws SAXException { warningMessage("INIT_FILE_READ_WARNING", getParseExceptionInfo(spe)); } public void error(SAXParseException spe) throws SAXException { throw new SAXException("INIT_FILE_ERROR" + getParseExceptionInfo(spe)); } public void fatalError(SAXParseException spe) throws SAXException { throw new SAXException("INIT_FILE_ERROR" + getParseExceptionInfo(spe)); } } private String convertToFileURL(String filename) { String path = new File(filename).getAbsolutePath(); if (File.separatorChar != '/') { path = path.replace(File.separatorChar, '/'); } if (!path.startsWith("/")) { path = "/" + path; } return "file:" + path; } public void parseInitFile(String filename) { boolean validation = false; SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setValidating(validation); XMLReader xmlReader = null; try { SAXParser saxParser = spf.newSAXParser(); xmlReader = saxParser.getXMLReader(); } catch (Exception ex) { System.err.println(ex); return; } xmlReader.setContentHandler(new MySaxParser()); xmlReader.setErrorHandler(new MyErrorHandler(System.err)); try { xmlReader.parse(convertToFileURL(filename)); } catch (SAXException se) { errorMessage("INIT_FILE_READ_ERROR", se.getMessage()); } catch (IOException ioe) { errorMessage("INIT_FILE_READ_ERROR", ioe.getMessage()); } } private void errorMessage(String message, String error) { System.err.println("Error: " + message + " " + error); } private void errorMessage(String message, String error, Exception e) { System.err.println("Error: " + message + " " + error + " " + e); } private void warningMessage(String message, String warning) { System.err.println("Warning: " + message + " " + warning); } } gprofng-gui-1.0/org/gprofng/mpmt/persistence/UserPref.java0000644000175000017500000011456514517772113020673 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.persistence; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.ExperimentPickLists; import org.gprofng.mpmt.guitesting.GUITesting; import org.gprofng.mpmt.metrics.MetricColors.MetricColor; import org.gprofng.mpmt.picklist.StringPickList; import org.gprofng.mpmt.remote.Authentication; import org.gprofng.mpmt.settings.CallTreeSetting; import org.gprofng.mpmt.settings.CompareModeSetting; import org.gprofng.mpmt.settings.FormatSetting; import org.gprofng.mpmt.settings.MetricNameSelection; import org.gprofng.mpmt.settings.MetricType; import org.gprofng.mpmt.settings.PathMapSetting; import org.gprofng.mpmt.settings.SearchPathSetting; import org.gprofng.mpmt.settings.SourceDisassemblySetting; import org.gprofng.mpmt.settings.TableSettings; import org.gprofng.mpmt.settings.TimelineSetting; import org.gprofng.mpmt.settings.ViewModeSetting; import org.gprofng.mpmt.settings.ViewsSetting.CustomObject; import org.gprofng.mpmt.statecolors.ColorRule; import org.gprofng.mpmt.toolbar.FindTextPanel; import java.awt.Dimension; import java.awt.Point; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Date; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import javax.swing.JFrame; public class UserPref { public enum What { USER, METRICS, SOURCEDISASSEMBLY, FORMATS, TIMELINE, SEARCHPATH, PATHMAP, VIEWS, CALLTREE, FUNCTIONCOLORS, LIBRARYVISIBILITY, MISC; public static What toWhat(String whatString) { if (whatString.equals("USER")) { return USER; } else if (whatString.equals("METRICS")) { return METRICS; } else if (whatString.equals("SOURCEDISASSEMBLY")) { return SOURCEDISASSEMBLY; } else if (whatString.equals("CALLTREE")) { return CALLTREE; } else if (whatString.equals("FORMATS")) { return FORMATS; } else if (whatString.equals("TIMELINE")) { return TIMELINE; } else if (whatString.equals("SEARCHPATH")) { return SEARCHPATH; } else if (whatString.equals("PATHMAP")) { return PATHMAP; } else if (whatString.equals("VIEWS")) { return VIEWS; } else if (whatString.equals("CALLTREE")) { return CALLTREE; } else if (whatString.equals("FUNCTIONCOLORS")) { return FUNCTIONCOLORS; } else if (whatString.equals("LIBRARYVISIBILITY")) { return LIBRARYVISIBILITY; } else if (whatString.equals("MISC")) { return MISC; } return null; } } private static UserPref instance = null; private static final String THA_INIT_FILE = "tha.xml"; private static final String ANALYZER_INIT_FILE = "analyzer.xml"; /* Update OldUserDirs with old user dirs it should search for settings */ private static final String UserDir = ".gprofng/gui"; private static final String[] OldUserDirs = new String[] { "../../.oracledevstudio/analyzer-paragon-dev", "../../.oracledevstudio/analyzer-12.6" }; // Newest first! public static final String configDirName = "configurations"; public static final String configAsWhenClosedName = "asWhenClosed"; public static final String configDefaultName = "default"; public static final String configurationSuffix = ".config.xml"; private static String userDirFromCommandLine = null; // from gp-display-gui script public static String binDirFromCommandLine = null; public static String dataDirFromCommandLine = null; public static String gprofngdir = null; // Where gp-display-text is installed private static long threeMonth = 90l * 24l * 3600l * 1000l; // 3 month private int version; // What's in this file private List whatList = null; // System settings private Dimension frameSize; private Point frameLocation; private SplitPaneFixedRightSizeProp splitPane1 = new SplitPaneFixedRightSizeProp(375); private SplitPaneFixedRightSizeProp splitPane2 = new SplitPaneFixedRightSizeProp(160); private SplitPaneFixedRightSizeProp splitPane3 = new SplitPaneFixedRightSizeProp(getDefaultSplitPane3RightSize()); private SplitPaneFixedRightSizeProp navigationFilterSplitPane = new SplitPaneFixedRightSizeProp(160); private Integer navigationPanelDividerPosition; private ExperimentPickLists experimentsPicklists; private Map connectionPropertiesMap = new LinkedHashMap(); private StringPickList hostNamePicklist = new StringPickList(); private String lastClosedExpConfPath = null; private Boolean wrapMetricNamesInTables = null; // private String lastExportImportConfPath = null; // Experiment settings private StringPickList findPickList = null; private List libraryVisibilitySettings = null; private StringPickList libraryVisibilityIncludeFilterPickList = null; private String currentLibraryVisibilityIncludeFilter = null; private StringPickList libraryVisibilityExcludeFilterPickList = null; private String currentLibraryVisibilityExcludeFilter = null; private Boolean libraryVisibilityJava = null; private Integer callStackThreshold; private Integer formatsViewMode = null; private Integer formatsStyle = null; private Boolean formatsAppendSoName = null; private Integer compareMode = null; private int[] sourceDisassemblySettings = null; private List viewPanelOrder; private String machineModel; private List customIndexObjects = null; private List customMemoryObjects = null; private List activeColorRules = null; private String timelineGroupDataByButtonName = null; private String timelineTLDataCmd = null; private Integer timelineStackAlign = null; private Integer timelineStackDepth = null; private Integer timelineStackFramePixels = null; private Boolean timelineShowEventStates = null; private Boolean timelineShowEventDensity = null; private List searchPath = null; private String[][] pathmap = null; private List customMetricColors = null; private Boolean showCompareSourceWarning = null; private List metricSelectionList; private Boolean metricReversedSort = null; private MetricType[] metricSortByMTypeList = null; private List[] metricOrderLists = null; public static UserPref getInstance() { if (instance == null) { instance = new UserPref(); } return instance; } public static String getAnalyzerDirPath(String userDir) { String ret; String userHome = getHomeDirectory(); ret = userHome + "/" + userDir; return ret; } public static String getAnalyzerInitFilePath(String userDir) { return getAnalyzerDirPath(userDir) + "/" + getInitFileName(); } public static String getAnalyzerDirPath() { String ret = userDirFromCommandLine; // from analyzer/tha script if (ret == null || ret.length() == 0) { String userHome = getHomeDirectory(); ret = userHome + "/" + UserDir; } return ret; } public static String getAnalyzerInitFilePath() { return getAnalyzerDirPath() + "/" + getInitFileName(); } public static String[] getOldUserDirs() { String[] ods = OldUserDirs.clone(); return ods; } public static String getDefaultAnalyzerDirPath() { return getAnalyzerDirPath(UserDir); } public static String getDefaultAnalyzerInitFilePath() { return getAnalyzerInitFilePath(getDefaultAnalyzerDirPath()); } public static String getHomeDirectory() { String userHome = System.getProperty("user.home"); if (userHome == null || userHome.equals("?")) { // on some Linux the systems the call above returns "?". userHome = System.getenv("HOME"); } return userHome; } public static String getInitFileName() { return ANALYZER_INIT_FILE; } public static String getConfigurationDirPath(String experimentName) { return experimentName + "/" + configDirName; } public static String getHomeConfigurationDirPath() { return getAnalyzerDirPath() + "/" + configDirName; } public static String getAsWhenClosedConfigName() { return configAsWhenClosedName + "." + getUserName() + configurationSuffix; } public static String getDefaultConfigurationName() { return configDefaultName + configurationSuffix; } public static String getAsWhenClosedConfigDirPath() { return getHomeConfigurationDirPath() + "/" + configAsWhenClosedName; } public static String getAsWhenClosedConfigPath(String experimentPath) { if (!experimentPath.startsWith("/")) { experimentPath = Analyzer.getInstance().getWorkingDirectory() + "/" + experimentPath; } String host = ""; if (Analyzer.getInstance().isRemote()) { host = Analyzer.getInstance().getRemoteHost(); } String mangledFileName = getMangledFileName(experimentPath, host, true); String asWhenClosedConfigPath = getAsWhenClosedConfigDirPath() + "/" + mangledFileName + configurationSuffix; File asWhenClosedConfigFile = new File(asWhenClosedConfigPath); if (!asWhenClosedConfigFile.exists()) { // If asWhenClosedConfigFile doesn't exist and old style do exists, move old to new... String mangledFileNameOld = getMangledFileName(experimentPath, host, false); String asWhenClosedConfigPathOld = getAsWhenClosedConfigDirPath() + "/" + mangledFileNameOld + configurationSuffix; File asWhenClosedConfigFileOld = new File(asWhenClosedConfigPathOld); if (asWhenClosedConfigFileOld.exists()) { asWhenClosedConfigFileOld.renameTo(asWhenClosedConfigFile); } } return asWhenClosedConfigPath; } /** * @param experimentPath assuming full path * @param host * @return */ public static String getMangledFileName( String experimentPath, String host, boolean useTimestamp) { String experimentName = basename(experimentPath); String mangledFileName = null; if (useTimestamp) { File logFile = new File(experimentPath + "/" + "log.xml"); if (logFile.exists()) { String timestamp = null; try { // use creationTime, if available BasicFileAttributes attr = Files.readAttributes(logFile.toPath(), BasicFileAttributes.class); timestamp = "" + attr.creationTime().toMillis(); } catch (IOException ioe) { } if (timestamp == null) { // else use lastModified timestamp = "" + logFile.lastModified(); } mangledFileName = experimentName + "_" + timestamp; } } if (mangledFileName == null) { // Old style... if (host == null || host.isEmpty() || host.equals("localhost")) { host = ""; } else if (!host.endsWith(".")) { host = host + "."; } String hostPlusExperimentPath = host + experimentPath; int hash = hostPlusExperimentPath.hashCode(); if (hash < 0) { hash = -hash; } mangledFileName = experimentName + "_" + hash; } return mangledFileName; } public static String basename(String path) { String name = path; int i = path.lastIndexOf("/"); if (i >= 0 && i < (path.length() - 1)) { name = path.substring(i + 1); } return name; } public static String getUserName() { return System.getProperty("user.name"); } /** * ************************************************************************************************ */ public int getVersion() { return version; } public void setVersion(int version) { this.version = version; } public List getWhatList() { return whatList; } public void setWhatList(List whatList) { this.whatList = whatList; } public ExperimentPickLists getExperimentsPicklists() { if (experimentsPicklists == null) { experimentsPicklists = new ExperimentPickLists(); } return experimentsPicklists; } public void setExperimentsPicklists(ExperimentPickLists experimentsPicklists) { this.experimentsPicklists = experimentsPicklists; } public Map getConnectionPropertiesMap() { return connectionPropertiesMap; } public void setConnectionPropertiesMap( Map connectionPropertiesMap) { this.connectionPropertiesMap = connectionPropertiesMap; } public static class ConnectionProperties { private String path; private String userName; private List authentications; public ConnectionProperties( String path, String userName, List authentications) { this.path = path; this.userName = userName; this.authentications = authentications; } public String getPath() { return path; } public String getUserName() { return userName; } public List getAuthentications() { return authentications; } } public static List getDefaultAuthentications() { return Authentication.getDefaultAuthentications(); } public StringPickList getHostNamePicklist() { return hostNamePicklist; } public void setHostNamePicklist(StringPickList hostNamePicklist) { this.hostNamePicklist = hostNamePicklist; } public Dimension getFrameSize() { if (frameSize != null) { return frameSize; } else { return getDefaultFrameSize(); } } public Dimension getDefaultFrameSize() { int screenWidth = AnVariable.SCREEN_SIZE.width; int screenHeight = AnVariable.SCREEN_SIZE.height; int width; int height; if (GUITesting.getInstance().isRunningUnderGUITesting()) { // Use fixed size frame if running under GUI testing return new Dimension(1400, 950); } // Guess a max width so it doesn't come up too wide in a multi monitor environment if (screenHeight <= 480 && screenWidth > 640) { screenWidth = 640; } else if (screenHeight <= 600 && screenWidth >= 800) { screenWidth = 800; } else if (screenHeight <= 768 && screenWidth >= 1024) { screenWidth = 1024; } else if (screenHeight <= 1200 && screenWidth >= 1920) { screenWidth = 1920; } else if (screenWidth >= 1024) { // ??? screenWidth = 1024; // ??? } if (screenWidth <= 400) { width = screenWidth - 10; } else if (screenWidth <= 800) { width = screenWidth - 25; } else if (screenWidth <= 1280) { width = screenWidth - 50; } else { width = screenWidth - 200; } if (screenHeight <= 300) { height = screenHeight - 10; } else if (screenHeight <= 600) { height = screenHeight - 50; } else if (screenHeight <= 1024) { height = screenHeight - 100; } else { height = screenHeight - 200; } return new Dimension(width, height); } public void setFrameSize(Dimension frameSize) { this.frameSize = frameSize; } public Point getFrameLocation() { if (frameLocation != null) { return frameLocation; } else { return getDefaultFrameLocation(); } } public Point getDefaultFrameLocation() { Dimension size = getDefaultFrameSize(); int x = (AnVariable.SCREEN_SIZE.width - size.width) / 2; int y = (AnVariable.SCREEN_SIZE.height - size.height) / 2; if (x <= 0) { x = 0; } if (y <= 0) { y = 0; } return new Point(x, y); } public void setFrameLocation(Point frameLocation) { this.frameLocation = frameLocation; } public SplitPaneFixedRightSizeProp getSplitPane1() { return splitPane1; } public SplitPaneFixedRightSizeProp getSplitPane2() { return splitPane2; } public SplitPaneFixedRightSizeProp getSplitPane3() { return splitPane3; } public SplitPaneFixedRightSizeProp getNavigationFilterSplitPane() { return navigationFilterSplitPane; } public static class SplitPaneFixedRightSizeProp { private Integer defaultSize; private Integer size; public SplitPaneFixedRightSizeProp(Integer defaultSize) { this.defaultSize = defaultSize; } /** * @return the size */ public Integer getSize() { if (size == null) { size = getDefaultSize(); } return size; } /** * @param size the size to set */ public void setSize(Integer size) { this.size = size; } /** * @return the defaultSize */ public Integer getDefaultSize() { return defaultSize; } } public Integer getNavigationPanelDividerPosition() { if (navigationPanelDividerPosition == null) { navigationPanelDividerPosition = 145; // default value } return navigationPanelDividerPosition; } public void setNavigationPanelDividerPosition(Integer navigationPanelDividerPosition) { this.navigationPanelDividerPosition = navigationPanelDividerPosition; } protected Integer getDefaultSplitPane1RightSize() { return 375; } protected Integer getDefaultSplitPane3RightSize() { Dimension size = getDefaultFrameSize(); return (int) (size.height * 0.4); } public String getLastClosedExpConfPath() { return lastClosedExpConfPath; } public void setLastClosedExpConfPath(String lastClosedExpConfPath) { this.lastClosedExpConfPath = lastClosedExpConfPath; } /** * ************************************************************************************************ */ public String getLastExportImportConfPath() { return lastExportImportConfPath; } public void setLastExportImportConfPath(String lastExportImportConfPath) { this.lastExportImportConfPath = lastExportImportConfPath; } /** Find text */ public StringPickList getFindPickList() { if (findPickList == null) { findPickList = new StringPickList(FindTextPanel.MAX_FIND_ITEMS); } return findPickList; } public void setFindPickList(StringPickList findPickList) { this.findPickList = findPickList; } /** Library Visibility */ public StringPickList getLibraryVisibilityIncludePickList() { if (libraryVisibilityIncludeFilterPickList == null) { libraryVisibilityIncludeFilterPickList = new StringPickList(FindTextPanel.MAX_FIND_ITEMS); } return libraryVisibilityIncludeFilterPickList; } public void setLibraryVisibilityIncludePickList( StringPickList libraryVisibilityIncludeFilterPickList) { this.libraryVisibilityIncludeFilterPickList = libraryVisibilityIncludeFilterPickList; } public String getLibraryVisibilityIncludeFilter() { return currentLibraryVisibilityIncludeFilter; } public void setLibraryVisibilityIncludeFilter(String currentLibraryVisibilityIncludeFilter) { this.currentLibraryVisibilityIncludeFilter = currentLibraryVisibilityIncludeFilter; } public StringPickList getLibraryVisibilityExcludePickList() { if (libraryVisibilityExcludeFilterPickList == null) { libraryVisibilityExcludeFilterPickList = new StringPickList(FindTextPanel.MAX_FIND_ITEMS); } return libraryVisibilityExcludeFilterPickList; } public void setLibraryVisibilityExcludePickList( StringPickList libraryVisibilityExcludeFilterPickList) { this.libraryVisibilityExcludeFilterPickList = libraryVisibilityExcludeFilterPickList; } public String getCurrenLibraryVisibilityExcludeFilter() { return currentLibraryVisibilityExcludeFilter; } public void setCurrentLibraryVisibilityExcludeFilter( String currentLibraryVisibilityExcludeFilter) { this.currentLibraryVisibilityExcludeFilter = currentLibraryVisibilityExcludeFilter; } public boolean getLibraryVisibilityJava() { if (libraryVisibilityJava == null) { libraryVisibilityJava = getLibraryVisibilityJavaDefault(); } return libraryVisibilityJava; } public void setLibraryVisibilityJava(boolean libraryVisibilityJava) { this.libraryVisibilityJava = libraryVisibilityJava; } public boolean getLibraryVisibilityJavaDefault() { return false; } /** Call Tree threshold */ public int getCallStackThreshold() { if (callStackThreshold == null) { callStackThreshold = getCallStackThresholdDefault(); } return callStackThreshold; } public void setCallStackThreshold(int callStackThreshold) { this.callStackThreshold = callStackThreshold; } public int getCallStackThresholdDefault() { return CallTreeSetting.getDefaultThreshold(); } /** Formats View Mode */ public int getFormatsViewMode() { if (formatsViewMode == null) { formatsViewMode = getFormatsViewModeDefault(); } return formatsViewMode; } public void setFormatsViewMode(int formatsViewMode) { this.formatsViewMode = formatsViewMode; } public int getFormatsViewModeDefault() { return ViewModeSetting.getDefaultViewMode().value(); } /** Formats Style */ public int getFormatsStyle() { if (formatsStyle == null) { formatsStyle = getFormatsStyleDefault(); } return formatsStyle; } public void setFormatsStyle(int formatsStyle) { this.formatsStyle = formatsStyle; } public int getFormatsStyleDefault() { return FormatSetting.getDefaultStyle().value(); } /** Formats AppendSoName */ public boolean getFormatsAppendSoName() { if (formatsAppendSoName == null) { formatsAppendSoName = getFormatsAppendSoNameDefault(); } return formatsAppendSoName; } public void setFormatsAppendSoName(boolean formatsAppendSoName) { this.formatsAppendSoName = formatsAppendSoName; } public boolean getFormatsAppendSoNameDefault() { return FormatSetting.getDefaultAppendSoName(); } /** Formats Compare Mode */ public int getFormatsCompareMode() { if (compareMode == null) { compareMode = getFormatsCompareModeDefault(); } return compareMode; } public void setFormatsCompareMode(int compareMode) { this.compareMode = compareMode; } public int getFormatsCompareModeDefault() { return CompareModeSetting.getDefaultCompareMode().value(); } /** source Disassembly Settings */ public int[] getSourceDisassemblySettings() { if (sourceDisassemblySettings == null) { sourceDisassemblySettings = getSourceDisassemblySettingsDefault(); } return sourceDisassemblySettings; } public void setSourceDisassemblySettings(int[] sourceDisassembySettings) { this.sourceDisassemblySettings = sourceDisassembySettings; } public int[] getSourceDisassemblySettingsDefault() { return SourceDisassemblySetting.getDefaultSourceDisassemblySetting(); } /** Views order */ public List getViewPanelOrder() { return viewPanelOrder; } public void setViewPanelOrder(List viewPanelOrder) { this.viewPanelOrder = viewPanelOrder; } public static class ViewPanelOrder { private String name; private boolean shown; public ViewPanelOrder(String name, boolean shown) { this.name = name; this.shown = shown; } /** * @return the name */ public String getName() { return name; } /** * @return the shown */ public boolean isShown() { return shown; } } /** Machine model */ public String getMachineModel() { return machineModel; } public void setMachineModel(String machineModel) { this.machineModel = machineModel; } /** Index and Memory Objects */ public List getCustomIndexObjects() { return customIndexObjects; } public void setCustomIndexObjects(List indexObjects) { this.customIndexObjects = indexObjects; } public List getCustomMemoryObjects() { return customMemoryObjects; } public void setCustomMemoryObjects(List memoryObjects) { this.customMemoryObjects = memoryObjects; } public static void setUserDir(String aUserDir) { userDirFromCommandLine = aUserDir; } /** Function Colors */ public List getActiveColorRules() { if (activeColorRules != null) { return activeColorRules; } else { return getActiveColorRulesDefault(); } } public List getActiveColorRulesDefault() { return new ArrayList(); } public void setActiveColorRules(List activeColorRules) { this.activeColorRules = activeColorRules; } /** Metrics */ public List getMetricSelectionList() { return metricSelectionList; } public void setMetricSelectionList(List metricOrder) { this.metricSelectionList = metricOrder; } public boolean getMetricReversedSort() { if (metricReversedSort != null) { return metricReversedSort; } else { return getMetricReversedSortDefault(); } } public boolean getMetricReversedSortDefault() { return false; } public void setMetricReversedSort(Boolean metricReversedSort) { this.metricReversedSort = metricReversedSort; } public MetricType[] getMetricSortByMTypeList() { return metricSortByMTypeList; } public void setMetricSortByMTypeList(MetricType[] metricSortMType) { this.metricSortByMTypeList = metricSortMType; } public List[] getMetricOrderLists() { return metricOrderLists; } public void setMetricOrderLists(List[] metricOrderLists) { this.metricOrderLists = metricOrderLists; } /** Timeline */ public String getTimelineGroupDataByButtonName() { if (timelineGroupDataByButtonName != null) { return timelineGroupDataByButtonName; } else { return getTimelineGroupDataByButtonNameDefault(); } } public String getTimelineGroupDataByButtonNameDefault() { return TimelineSetting.getDefaultGroupDataByButtonName(); } public void setTimelineGroupDataByButtonName(String timelineGroupDataByButtonName) { this.timelineGroupDataByButtonName = timelineGroupDataByButtonName; } public String getTimelineTLDataCmd() { if (timelineTLDataCmd != null) { return timelineTLDataCmd; } else { return getTimelineTLDataCmdDefault(); } } public String getTimelineTLDataCmdDefault() { return TimelineSetting.getDefaultTLDataCmd(); } public void setTimelineTLDataCmd(String timelineTLDataCmd) { this.timelineTLDataCmd = timelineTLDataCmd; } public int getTimelineStackAlign() { if (timelineStackAlign != null) { return timelineStackAlign; } else { return getDefaultTimelineStackAlign(); } } public int getDefaultTimelineStackAlign() { return TimelineSetting.getDefaultStackAlign(); } public void setTimelineStackAlign(Integer timelineStackAlign) { this.timelineStackAlign = timelineStackAlign; } public int getTimelineStackDepth() { if (timelineStackDepth != null) { return timelineStackDepth; } else { return getTimelineStackDepthDefault(); } } public int getTimelineStackDepthDefault() { return TimelineSetting.getDefaultStackDepth(); } public void setTimelineStackDepth(Integer timelineStackDepth) { this.timelineStackDepth = timelineStackDepth; } public int getTimelineStackFramePixels() { if (timelineStackFramePixels != null) { return timelineStackFramePixels; } else { return getTimelineStackFramePixelsDefault(); } } public int getTimelineStackFramePixelsDefault() { return TimelineSetting.getDefaultStackFramePixels(); } public void setTimelineStackFramePixels(Integer timelineStackFramePixels) { this.timelineStackFramePixels = timelineStackFramePixels; } public boolean getTimelineShowEventStates() { if (timelineShowEventStates != null) { return timelineShowEventStates; } else { return getTimelineShowEventStatesDefault(); } } public boolean getTimelineShowEventStatesDefault() { return TimelineSetting.getTimelineShowEventStatesDefault(); } public void setTimelineShowEventStates(Boolean timelineShowEventStates) { this.timelineShowEventStates = timelineShowEventStates; } public boolean getTimelineShowEventDensity() { if (timelineShowEventDensity != null) { return timelineShowEventDensity; } else { return getTimelineShowEventDensityDefault(); } } public boolean getTimelineShowEventDensityDefault() { return TimelineSetting.getTimelineShowEventDensityDefault(); } public void setTimelineShowEventDensity(Boolean timelineShowEventDensity) { this.timelineShowEventDensity = timelineShowEventDensity; } public List getLibraryVisibilitySettings() { return libraryVisibilitySettings; } public void setLibraryVisibilitySettings(List loadObjectSettings) { this.libraryVisibilitySettings = loadObjectSettings; } public List getSearchPath() { if (searchPath == null) { return getSearchPathDefault(); } else { return searchPath; } } public List getSearchPathDefault() { return SearchPathSetting.getDefaultSearchPath(); } public void setSearchPath(List searchPath) { this.searchPath = searchPath; } public String[][] getPathmap() { if (pathmap == null) { return getPathmapDefault(); } else { return pathmap; } } public String[][] getPathmapDefault() { return PathMapSetting.getDefaultPathmap(); } public void setPathmap(String[][] pathmap) { this.pathmap = pathmap; } public List getCustomMetricColors() { return customMetricColors; } public void setCustomMetricColors(List customMetricColors) { this.customMetricColors = customMetricColors; } public boolean showCompareSourceWarning() { if (showCompareSourceWarning == null) { showCompareSourceWarning = showCompareSourceWarningDefault(); } return showCompareSourceWarning; } public boolean showCompareSourceWarningDefault() { return true; } public void setShowCompareSourceWarning(boolean showCompareSourceWarning) { this.showCompareSourceWarning = showCompareSourceWarning; } public Boolean wrapMetricNamesInTables() { if (wrapMetricNamesInTables == null) { wrapMetricNamesInTables = wrapMetricNamesInTablesDefault(); } return wrapMetricNamesInTables; } public void setWrapMetricNamesInTables(Boolean wrapMetricNamesInTables) { this.wrapMetricNamesInTables = wrapMetricNamesInTables; } public Boolean wrapMetricNamesInTablesDefault() { return TableSettings.wrapMetricNamesDefault(); } /** * ************************************************************************************************ */ public void save(String configFilePath, List what) { AnWindow anWindow = AnWindow.getInstance(); JFrame anFrame = anWindow.getFrame(); // Copy states back in to UserPref if (what.contains(UserPref.What.USER)) { setFrameSize(anFrame.getSize()); setFrameLocation(anFrame.getLocation()); setNavigationPanelDividerPosition( anWindow.getNavigationPanelSplitPane().getDividerLocationWhenShowing()); getSplitPane1().setSize(anWindow.getMainViewPanel().getSplitPane1().getSizeInPixels()); getSplitPane2().setSize(anWindow.getMainViewPanel().getSplitPane2().getSizeInPixels()); getSplitPane3().setSize(anWindow.getMainViewPanel().getSplitPane3().getSizeInPixels()); getNavigationFilterSplitPane() .setSize(anWindow.getNavigationPanel().getNavigationSplitPaneSizeInPixels()); } if (!what.contains(UserPref.What.USER) && what.size() > 0 || what.contains(UserPref.What.USER) && what.size() > 1) { if (!anWindow.getViewsPanel().onlyStaticViews()) { setViewPanelOrder(anWindow.getViewsPanel().getViewPanelOrderPref()); } setCallStackThreshold(anWindow.getSettings().getCallTreeSetting().getThreshold()); setFormatsViewMode(anWindow.getSettings().getViewModeSetting().get().value()); setFormatsStyle(anWindow.getSettings().getFormatSetting().getStyle().value()); setFormatsAppendSoName(anWindow.getSettings().getFormatSetting().getAppendSoName()); if (anWindow.getSettings().getCompareModeSetting().comparingExperiments()) { setFormatsCompareMode(anWindow.getSettings().getCompareModeSetting().get().value()); } setSourceDisassemblySettings(anWindow.getSettings().getSourceDisassemblySetting().get()); setMachineModel(anWindow.getSettings().getViewsSetting().getMachineModel()); setCustomIndexObjects(anWindow.getSettings().getViewsSetting().getCustomIndexObjects()); setCustomMemoryObjects(anWindow.getSettings().getViewsSetting().getCustomMemoryObjects()); setActiveColorRules(anWindow.getColorChooser().getColorMap().getActiveRules()); setMetricSelectionList(anWindow.getSettings().getMetricsSetting().getMetricOrder()); setMetricReversedSort( anWindow.getSettings().getMetricsSetting().getMetricStates().isReverseDirectionSorting()); setMetricSortByMTypeList( anWindow.getSettings().getMetricsSetting().getMetricStates().getMetricSortByMType()); setMetricOrderLists( anWindow.getSettings().getMetricsSetting().getMetricStates().getMetricOrderLists()); setTimelineStackDepth(anWindow.getSettings().getTimelineSetting().getTLStackDepth()); setTimelineStackFramePixels( anWindow.getSettings().getTimelineSetting().getTLStackFramePixels()); setTimelineGroupDataByButtonName( anWindow.getSettings().getTimelineSetting().getGroupDataByButtonName()); setTimelineTLDataCmd(anWindow.getSettings().getTimelineSetting().getTLDataCmd()); setTimelineStackAlign(anWindow.getSettings().getTimelineSetting().getStackAlign()); setTimelineShowEventStates(anWindow.getSettings().getTimelineSetting().getShowEventStates()); setTimelineShowEventDensity( anWindow.getSettings().getTimelineSetting().getShowEventDensity()); setLibraryVisibilitySettings( AnWindow.getInstance().getSettings().getLibraryVisibilitySetting().getStates()); setLibraryVisibilityJava(anWindow.getLibraryVisibilityDialog().isJava()); setSearchPath(anWindow.getSettings().getSearchPathSetting().get()); setPathmap(anWindow.getSettings().getPathMapSetting().get()); setWrapMetricNamesInTables(anWindow.getSettings().getTableSettings().wrapMetricNames()); } // Save states in config file new UserPrefPersistence().saveSettings(configFilePath, this, what); } public void restore(String configFilePath) { new UserPrefPersistence().restoreSettings(configFilePath, this); } public void resetExperimentPreferences() { findPickList.removeAllElements(); callStackThreshold = null; formatsViewMode = null; formatsAppendSoName = null; formatsStyle = null; sourceDisassemblySettings = null; machineModel = null; compareMode = null; customIndexObjects = null; customMemoryObjects = null; activeColorRules = null; viewPanelOrder = null; metricSelectionList = null; metricReversedSort = null; metricSortByMTypeList = null; metricOrderLists = null; timelineStackDepth = null; timelineStackFramePixels = null; timelineGroupDataByButtonName = null; timelineTLDataCmd = null; timelineStackAlign = null; timelineShowEventStates = null; timelineShowEventDensity = null; libraryVisibilitySettings = null; searchPath = null; pathmap = null; libraryVisibilityIncludeFilterPickList = null; currentLibraryVisibilityIncludeFilter = null; libraryVisibilityExcludeFilterPickList = null; currentLibraryVisibilityExcludeFilter = null; libraryVisibilityJava = null; wrapMetricNamesInTables = null; } /** Remove config files that are older than threeMonth (3 month)... */ public void cleanupAsWhenClosedFolder() { File asWhenClosedFile = new File(getAsWhenClosedConfigDirPath()); if (asWhenClosedFile.exists()) { File[] files = asWhenClosedFile.listFiles(); long oldTimeStamp = new Date().getTime() - threeMonth; for (File file : files) { if (!file.isDirectory() && file.getName().endsWith(configurationSuffix)) { long lastModified = file.lastModified(); if (lastModified < oldTimeStamp) { file.delete(); AnLog.log("Old config file removed: " + file.getAbsolutePath()); } } } } } /** * FIXUP: Should move this code to AnUtility but AnUtility doesn't run this early due to class * loader issue! * * @param fromDirectoryFile * @param toDirectoryFile * @throws IOException */ public static void copyDirectory(File fromDirectoryFile, File toDirectoryFile) throws IOException { if (fromDirectoryFile.exists() && fromDirectoryFile.isDirectory()) { if (!toDirectoryFile.exists()) { toDirectoryFile.mkdirs(); } String[] children = fromDirectoryFile.list(); for (int i = 0; i < children.length; i++) { File fromFile = new File(fromDirectoryFile, children[i]); if (fromFile.getName().equals(UserPref.configAsWhenClosedName)) { // Don't copy these files just yet.... continue; } File toFile = new File(toDirectoryFile, children[i]); if (fromFile.isDirectory()) { copyDirectory(fromFile, toFile); } else { copyFile(fromFile, toFile); } } } else { // FIXUP: do something reasonable } } public static void copyFile(File fromFile, File toFile) throws IOException { if (fromFile.exists() && !fromFile.isDirectory()) { InputStream inputStream = new FileInputStream(fromFile); OutputStream outputStream = new FileOutputStream(toFile); byte[] buffer = new byte[1024]; int nbytes; while ((nbytes = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, nbytes); } inputStream.close(); outputStream.close(); toFile.setLastModified(fromFile.lastModified()); } else { // FIXUP: do something reasonable } } } gprofng-gui-1.0/org/gprofng/mpmt/HotGapPanel.java0000644000175000017500000000700214517772113016741 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JPanel; import javax.swing.KeyStroke; public class HotGapPanel extends JPanel { int height = 0; private final FuncListDisp funcListDisp; public HotGapPanel(FuncListDisp funcListDisp) { this.funcListDisp = funcListDisp; init(47); } private void init(int height) { this.height = height; JPanel buttonPan = new JPanel(new GridBagLayout()); buttonPan.setBackground(Color.WHITE); final JButton upButton = new AnIconButton(AnUtility.goUpIcon); final JButton downButton = new AnIconButton(AnUtility.goDownIcon); upButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { funcListDisp.find(null, false, true); funcListDisp.gap.update(); } }); downButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { funcListDisp.find(null, true, true); funcListDisp.gap.update(); } }); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = 0; buttonPan.add(upButton, gridBagConstraints); gridBagConstraints.gridy = 1; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.weighty = 1.0; buttonPan.add(downButton, gridBagConstraints); Dimension dim = new Dimension(AnHotGap.HOTGAP_WIDTH, height); buttonPan.setPreferredSize(dim); setLayout(new BorderLayout()); add(buttonPan, BorderLayout.NORTH); final AnHotGap gap = new AnHotGap(funcListDisp, height); add(gap, BorderLayout.CENTER); funcListDisp.gap = gap; // Hmmm????? setBorder(BorderFactory.createMatteBorder(0, 1, 0, 0, AnEnvironment.SCROLLBAR_BORDER_COLOR)); // Previous Hot Line KeyStroke keyStrokeUp = KeyboardShortcuts.sourcePreviousHotLineActionShortcut; upButton.setToolTipText( AnLocale.getString("Previous Hot Line") + AnUtility.keyStrokeToStringFormatted(keyStrokeUp)); // Next Hot Line KeyStroke keyStrokeDown = KeyboardShortcuts.sourceNextHotLineActionShortcut; downButton.setToolTipText( AnLocale.getString("Next Hot Line") + AnUtility.keyStrokeToStringFormatted(keyStrokeDown)); } public void headerheightChanged(int height) { if (height < 40) { height = 40; } if (this.height == height) { return; } removeAll(); init(height); funcListDisp.updateGap(); } } gprofng-gui-1.0/org/gprofng/mpmt/ResolveFilePathDialog.java0000644000175000017500000002221614517772113020757 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.util.gui.AnDialog2; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.gui.ToolTipPopup; import java.awt.Frame; import javax.swing.JLabel; public class ResolveFilePathDialog extends AnDialog2 { private ResolveFilePathPanel resolveFilePathPanel; private String unResolvedPath; private long obj_id; public ResolveFilePathDialog(Frame owner, String unResolvedPath, long obj_id) { super(owner, owner, AnLocale.getString("Resolve Source File")); this.unResolvedPath = unResolvedPath; this.obj_id = obj_id; setHelpTag(AnVariable.HELP_ResolveSourceFile); resolveFilePathPanel = new ResolveFilePathPanel(this, unResolvedPath); setCustomPanel(resolveFilePathPanel); // getHelpButton().setVisible(false); // getHelpButton().setEnabled(false); } @Override protected void setStatus(AnDialog2.Status status) { super.setStatus(status); if (status == AnDialog2.Status.OK) { String resolvedPath = resolveFilePathPanel.getResolvedPath(); if (resolveFilePathPanel.archiveFiles()) { if (resolveFilePathPanel.resolveThisFileOnly()) { long[] ids = new long[1]; String[] paths = new String[1]; ids[0] = obj_id; paths[0] = resolvedPath; archive(ids, paths); } else { String unresolvedDir = AnUtility.dirname(unResolvedPath); String resolvedDir = AnUtility.dirname(resolvedPath); // System.out.println("unresolvedDir: " + unresolvedDir); // System.out.println("resolvedDir: " + resolvedDir); archiveAll(unresolvedDir, resolvedDir); } } else { // if (resolveFilePathPanel.resolveThisFileOnly()) { // String[] oldPaths = new String[1]; // String[] newPaths = new String[1]; // oldPaths[0] = unResolvedPath; // newPaths[0] = resolvedPath; // setLocations(oldPaths, newPaths); // } else { if (unResolvedPath.startsWith("/")) { // Use Path Map (native) int slash = 0; int unResolvedLength = unResolvedPath.length(); int resolvedLength = resolvedPath.length(); for (int i = 1; i < resolvedLength; i++) { if (resolvedPath.charAt(resolvedLength - i) == '/') { slash = i; } if (unResolvedPath.charAt(unResolvedLength - i) != resolvedPath.charAt(resolvedLength - i)) { break; } } String from = unResolvedPath.substring(0, unResolvedLength - slash); String to = resolvedPath.substring(0, resolvedLength - slash); addPathmap(from, to); } else { // Use Search Path (Java) String searchPath; if (resolvedPath.endsWith(unResolvedPath)) { searchPath = resolvedPath.substring(0, resolvedPath.length() - unResolvedPath.length() - 1); } else { searchPath = resolvedPath; } addSearchPath(searchPath); } } // } } } private void addSearchPath(String searchPath) { // System.out.println("Search Path: " + searchPath); AnWindow.getInstance().getSettings().getSearchPathSetting().add(this, searchPath); String ttText = "" + searchPath + " " + AnLocale.getString("added to Search Path settings"); JLabel label = new JLabel(ttText); ToolTipPopup toolTipPopup = new ToolTipPopup( AnWindow.getInstance().getViews().getCurrentViewDisplay(), label, ToolTipPopup.Location.CENTER, true); toolTipPopup.show(0, 4000); } private void addPathmap(final String from, final String to) { // System.out.println("Pathmap: " + from + " -> " + to); AnWindow.getInstance().getSettings().getPathMapSetting().addPathMap(this, from, to); String ttText = "" + from + " -> " + to + " " + AnLocale.getString("added to Pathmap settings"); JLabel label = new JLabel(ttText); ToolTipPopup toolTipPopup = new ToolTipPopup( AnWindow.getInstance().getViews().getCurrentViewDisplay(), label, ToolTipPopup.Location.CENTER, true); toolTipPopup.show(0, 4000); } public void archiveAll(final String unresolvedDir, final String resolvedDir) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { synchronized (AnVariable.mainFlowLock) { Object[] o = dbeResolvedWith_pathmap(unresolvedDir, resolvedDir); // IPC if (o == null) { return; // BUG? } String[] oldPaths = (String[]) o[0]; String[] newPaths = (String[]) o[1]; long[] ids = (long[]) o[2]; archive(ids, newPaths); AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(this, AnChangeEvent.Type.SOURCE_FINDING_CHANGING)); dbe_archive(ids, newPaths); // IPC AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(this, AnChangeEvent.Type.SOURCE_FINDING_CHANGED)); } } }, "Archive All thread"); } public void archive(final long[] ids, final String[] paths) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { synchronized (AnVariable.mainFlowLock) { AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(this, AnChangeEvent.Type.SOURCE_FINDING_CHANGING)); dbe_archive(ids, paths); // IPC AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(this, AnChangeEvent.Type.SOURCE_FINDING_CHANGED)); } } }, "Archive thread"); } public void setLocations(final String fnames[], final String locations[]) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { synchronized (AnVariable.mainFlowLock) { AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(this, AnChangeEvent.Type.SOURCE_FINDING_CHANGING)); dbeSetLocations(fnames, locations); // IPC AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(this, AnChangeEvent.Type.SOURCE_FINDING_CHANGED)); } } }, "set source locations thread"); } protected void dbe_archive(final long ids[], final String locations[]) { AnWindow window = AnWindow.getInstance(); synchronized (IPC.lock) { window.IPC().send("dbe_archive"); window.IPC().send(ids); window.IPC().send(locations); window.IPC().recvVoid(); } } protected void dbeSetLocations(final String fnames[], final String locations[]) { AnWindow window = AnWindow.getInstance(); synchronized (IPC.lock) { window.IPC().send("dbeSetLocations"); window.IPC().send(fnames); window.IPC().send(locations); window.IPC().recvVoid(); } } protected Object[] dbeResolvedWith_setpath(final String path) { AnWindow window = AnWindow.getInstance(); // obj[0] - list of old pathes // obj[1] - list of new pathes // obj[2] - list of ids synchronized (IPC.lock) { window.IPC().send("dbeResolvedWith_setpath"); window.IPC().send(path); return (Object[]) window.IPC().recvObject(); } } protected Object[] dbeResolvedWith_pathmap(final String old_prefix, final String new_prefix) { AnWindow window = AnWindow.getInstance(); // obj[0] - list of old pathes // obj[1] - list of new pathes // obj[2] - list of ids synchronized (IPC.lock) { window.IPC().send("dbeResolvedWith_pathmap"); window.IPC().send(old_prefix); window.IPC().send(new_prefix); return (Object[]) window.IPC().recvObject(); } } } gprofng-gui-1.0/org/gprofng/mpmt/AnEvent.java0000644000175000017500000000710514517772113016143 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import java.util.EventObject; public final class AnEvent extends EventObject { public static final int EVT_COMPUTE = 1; // AnTable, Settings: when double-clicking on already selected row in caller/callee, // Settings: when applying any change public static final int EVT_UPDATE = 2; // ColorMap: when channging colors, AnTable: when ???? // public final static int EVT_NEWFMT = 3; // Settings: Formats have changed // public final static int EVT_NEWSRC = 4; // Settings: Search Path/Pathmap changed, AnTable: // when double-clicking in row // public final static int EVT_NEWDIS = 5; // Settings: Search Path/Pathmap changed // public final static int EVT_NEWTM = 6; // Settings: when timeline properties have changed // public final static int EVT_RUN = 7; // Settings: when applying any change public static final int EVT_SET = 8; // Antable: ????? public static final int EVT_SELECT = 9; // AnTable: when selecting row in AnTable (single/multi) public static final int EVT_SORT = 10; // AnTable, Settings: when sorting column by clicking in table header // public final static int EVT_ORDER = 11; // Settings: when switching column order in // AnTable public static final int EVT_SCROLL = 12; // AnTable: initial when Caller/Callee opened public static final int EVT_SWITCH = 13; // AnTable: when switching column order in AnTable public static final int EVT_RESET = 14; // AnTable: not used public static final int EVT_SETHEAD = 15; // AnTable: Set Head from Caller/Callee context menu public static final int EVT_SETTAIL = 16; // AnTable: Set Tail from Caller/Callee context menu public static final int EVT_BACK = 17; // AnTable: when clicking Forward public static final int EVT_FORWARD = 18; // AnTable: when clicking Backward public static final int EVT_COPY_ALL = 19; // AnTable: when clicking Copy All public static final int EVT_COPY_SEL = 20; // AnTable: when clicking Copy Selected public static final int EVT_RESIZE = 99; // Should not clash with display types private final int type, dsp_type; private final int value; private final Object aux; public AnEvent(final Object source, final int type, final int value, final Object aux) { super(source); this.type = type; this.value = value; this.dsp_type = AnDisplay.DSP_Null; this.aux = aux; } public AnEvent( final Object source, final int type, final int value, final int dsp_type, final Object aux) { super(source); this.type = type; this.dsp_type = dsp_type; this.value = value; this.aux = aux; } public int getType() { return type; } public int getDispType() { return dsp_type; } public int getValue() { return value; } public Object getAux() { return aux; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append(type); return sb.toString(); } } gprofng-gui-1.0/org/gprofng/mpmt/NoMetricsSelectedPanel.form0000644000175000017500000001057514517772113021166 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/AnDisplay.java0000644000175000017500000004637114517772113016477 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnTable.UpdateAction; import org.gprofng.mpmt.AnWindow.AnDispTab; import org.gprofng.mpmt.Analyzer.HelpAction; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.filter.CustomFilterAction; import org.gprofng.mpmt.filter.RedoFilterAction; import org.gprofng.mpmt.filter.RemoveAllFilterAction; import org.gprofng.mpmt.filter.UndoFilterAction; import org.gprofng.mpmt.ipc.IPCCancelledException; import org.gprofng.mpmt.ipc.IPCContext; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Component; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.util.ArrayList; import java.util.List; import javax.accessibility.AccessibleContext; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import javax.swing.SwingConstants; import javax.swing.border.LineBorder; public abstract class AnDisplay extends JPanel { public final AnWindow window; private static JFrame jframe; protected final int type; protected final int subtype; protected int parent_type = -1; protected boolean available; // true if view is available protected boolean selected; // true if view is selected and showing protected boolean computed; // true if view's data has been computed and is up-to-date protected UpdateAction tailAction; protected boolean inCompute; protected boolean forceCompute; protected final boolean can_sort; public AnHotGap gap; private String help_id; private AnDispTab anDispTab; // Constructor protected AnDisplay(final AnWindow window, final int type, final String help_id) { this(window, type, 0, help_id); } protected AnDisplay( final AnWindow window, final int type, final int subtype, final String help_id) { this.window = window; jframe = window.getFrame(); this.type = type; this.subtype = subtype; this.help_id = help_id; selected = false; computed = false; inCompute = false; forceCompute = false; can_sort = ((type != DSP_Source) && (type != DSP_Disassembly) && (type != DSP_SourceV2) && (type != DSP_DisassemblyV2)); // FIXUP: REARCH tailAction = null; // Initialize GUI components & set preferred size initComponents(); setHelpAction(help_id); setBorder(new LineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR, 0)); } // Initialize GUI components protected abstract void initComponents(); // Should be overridden if ... public JPopupMenu getFilterPopup() { return null; } protected void copyToClipboard(String text) { StringSelection data = new StringSelection(text); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(data, data); } // abstract JPopupMenu getFilterPopup(); public void showFilterPopup(Component parent) { JPopupMenu popup; popup = getFilterPopup(); if (popup == null) { popup = getDefaultFilterPopup(); } if (popup != null) { if (parent == null || !parent.isShowing()) { parent = this; } popup.show(parent, 15, 15); } } private void setHelpAction(final String help_id) { // if (help_id != null) { HelpAction helpAction = new HelpAction(help_id); registerKeyboardAction( helpAction, "help", KeyboardShortcuts.helpActionShortcut, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); registerKeyboardAction( helpAction, "help", KeyboardShortcuts.helpActionShortcut, JComponent.WHEN_FOCUSED); registerKeyboardAction( helpAction, "help", KeyboardShortcuts.helpActionShortcut, JComponent.WHEN_IN_FOCUSED_WINDOW); // } } public void showHelp() { Analyzer.showHelp(help_id); } public String getHelpID() { return help_id; } // Display type public final int getType() { return type; } // Is current selected tab? public void setSelected(final boolean set) { selected = set; } public final boolean isSelected() { return selected; } // Need re-compute? public void setComputed(final boolean set) { computed = set; } public final boolean isComputed() { return computed; } // Clear display protected void clear() { // FIXUP: RE_ARCH } // Clear navigation history protected void clearHistory() { // FIXUP: RE_ARCH } public void setNavigationAction(final UpdateAction action) { tailAction = action; } // Update view specific tool bar public void updateToolBar() {} // sync src&dis view public void syncSrcDisWin() {} // Reset display protected void reset() { clear(); } public final void computeOnAWorkerThread() { computeOnAWorkerThread(null, null); } /** * Do long-running task in a separate thread * * @param context */ public final void computeOnAWorkerThread( final IPCContext context, final AbstractAction postComputeAction) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { compute(context, postComputeAction); } }, "Display_thread"); ; } public void compute(final IPCContext context, final AbstractAction postComputeAction) { synchronized (AnVariable.mainFlowLock) { IPCContext currentContext = context; if (currentContext == null) { currentContext = IPCContext.newCurrentContext(null, IPCContext.Scope.SESSION, false, window); } // System.out.println("\n============= AnDisplay compute Start" + // currentContext.getTaskName() + " Channel: " + currentContext.getChannel()); Object progressBarHandle = window.getSystemProgressPanel().progressBarStart(AnLocale.getString("Computing")); try { // in case there will be an exception inside doCompute doCompute(); // on worker thread and synchronized (AnVariable.mainFlowLock) } catch (IPCCancelledException ex) { System.out.println("\ncompute cancelled..."); inCompute = false; computed = false; } finally { currentContext = IPCContext.newCurrentContext(null, IPCContext.Scope.SESSION, false, window); // System.out.println("\n============= AnDisplay compute End" + // currentContext.getTaskName() + " Channel: " + currentContext.getChannel()); } if (postComputeAction != null) { postComputeAction.actionPerformed(null); } window.getSystemProgressPanel().progressBarStop(progressBarHandle); } } /* * Change selection */ public void changeSelection(AnTable table, int index) { return; } /** * Override and return true if text find is supported * * @return */ protected boolean supportsFindText() { return false; } // Find public int find(final String str, final boolean next, boolean caseSensitive) { return -1; } // Check if "Back" action is available public boolean isBackActionAvailable() { return false; } // Check if "Forward" action is available public boolean isForwardActionAvailable() { return false; } // Compute & update display public abstract void doCompute(); public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String text = "not implemented"; return text; } // Display error string on the status area protected final void showError(final String msg) { window.showError(msg); } // Display warning string on the status area protected final void showWarning(final String msg) { window.showWarning(msg); } /** * @return the anDispTab */ public AnDispTab getAnDispTab() { return anDispTab; } /** * @param anDispTab the anDispTab to set */ public void setAnDispTab(AnDispTab anDispTab) { this.anDispTab = anDispTab; } public JPopupMenu getDefaultFilterPopup() { List menuItems = getDefaultFilterMenuItems(); JPopupMenu popup = new JPopupMenu(); for (JComponent menuItem : menuItems) { popup.add(menuItem); } return popup; } public List getDefaultFilterMenuItems() { List menuItems = new ArrayList(); JMenuItem menuItem; CustomFilterAction customFilter = new CustomFilterAction(); menuItem = new JMenuItem(customFilter); customFilter.jmi = menuItem; menuItem.setEnabled(true); menuItems.add(menuItem); menuItems.add(new JSeparator(SwingConstants.HORIZONTAL)); UndoFilterAction undoFilter = new UndoFilterAction(); menuItem = new JMenuItem(undoFilter); undoFilter.jmi = menuItem; menuItem.setEnabled(window.getFilters().canUndoLastFilter()); menuItems.add(menuItem); RedoFilterAction redoFilter = new RedoFilterAction(); menuItem = new JMenuItem(redoFilter); redoFilter.jmi = menuItem; menuItem.setEnabled(window.getFilters().canRedoLastFilter()); menuItems.add(menuItem); RemoveAllFilterAction removeAllFilter = new RemoveAllFilterAction(); menuItem = new JMenuItem(removeAllFilter); removeAllFilter.jmi = menuItem; menuItem.setEnabled(window.getFilters().canRemoveAllFilters()); menuItems.add(menuItem); if (window.getFilters().anyFilters()) { menuItems.add(window.getFilters().removeFilterMenuItem()); } return menuItems; } public List getVisibleSubviews() { return new ArrayList(); } public List getSelectedSubviews() { return null; } public JPanel getToolbarPanel() { return null; } protected void setAccessibility(String name) { AccessibleContext context = getAccessibleContext(); context.setAccessibleName(name); context.setAccessibleDescription(name); } /** * @return the available */ protected boolean isAvailable() { return available; } /** * @param available the available to set */ protected void setAvailable(boolean available) { this.available = available; } /** * Some views show only 'Values' and not Exclusive and Inclusive in tables. * Fixup: they come in as 'Exclusive' but are not really 'Exclusive'. * Should be fixed in gp-display-text * * @return */ public boolean showOnlyValuesInTables() { return type == DSP_MemoryObject || type == DSP_DataObjects || type == DSP_DataLayout || type == DSP_IndexObject || type == DSP_IO || type == DSP_IOFileDescriptors || type == DSP_IOCallStacks || type == DSP_Heap; } /** * Some views show only 'Included' and not Exclusive and Inclusive in tables. * Fixup: Should be in gp-display-text. * * @return */ public boolean showOnlyIncludedInTables() { return type == DSP_Source || type == DSP_Disassembly || type == DSP_SourceDisassembly; } /** * Some views show only 'Attributed' and not Exclusive and Inclusive in tables. * Fixup: they come in as 'Exclusive' but are not really 'Exclusive'. * Should be fixed in gp-display-text * * @return */ public boolean showOnlyAttributedInTables() { return type == DSP_Callers; } protected void debug() { if (getAnDispTab() != null) { System.out.println("AnDisplay: " + getAnDispTab().getTCmd()); } else { System.out.println("AnDisplay: " + getClass().getName()); } System.out.println(" available: " + available); System.out.println(" selected: " + selected); System.out.println(" computed: " + computed); } /*------ Constants shared with enums.h (KEEP IN SYNC!) ---------------*/ public static final int DSP_Welcome = -3; // not used by DBE, not in enums.h public static final int DSP_Null = 0; // ??? public static final int DSP_Functions = 1; public static final int DSP_Lines = 2; public static final int DSP_PCs = 3; public static final int DSP_Source = 4; public static final int DSP_Disassembly = 5; public static final int DSP_CallerCalleeSelf = 6; public static final int DSP_Callers = 7; public static final int DSP_Callees = 8; public static final int DSP_CallTree = 9; public static final int DSP_Timeline = 10; public static final int DSP_Statistics = 11; public static final int DSP_Experiments = 12; public static final int DSP_MemoryObject = 14; public static final int DSP_DataObjects = 15; public static final int DSP_DataLayout = 16; public static final int DSP_SourceSelectedObject = 17; public static final int DSP_InstructionFrequency = 18; public static final int DSP_Races = 19; public static final int DSP_IndexObject = 20; public static final int DSP_DualSource = 21; public static final int DSP_SourceDisassembly = 22; public static final int DSP_Deadlocks = 23; public static final int DSP_MPITimeline = 24; public static final int DSP_MPIChart = 25; public static final int DSP_SourceV2 = 27; public static final int DSP_DisassemblyV2 = 28; public static final int DSP_IO = 31; public static final int DSP_Overview = 32; public static final int DSP_IOFileDescriptors = 33; public static final int DSP_IOCallStacks = 34; public static final int DSP_MiniFunctions = 35; public static final int DSP_MiniCallerCalleeSelf = 36; public static final int DSP_MiniCaller = 37; public static final int DSP_MiniCallee = 38; public static final int DSP_Heap = 39; public static final int DSP_CallFlame = 40; public static final int DSP_MAX = DSP_CallFlame; // Always the highest number /* By Type: AnDisplay Type Family Variable User Name Internal Name ---- ------ ----------------- ------------------------ ----------------- -3 0 DSP_WELCOME Welcome welcome 1 0 DSP_FUNCTION Functions functions 2 0 DSP_LINE Lines lines 3 0 DSP_PC PCs pcs 4 7 DSP_SOURCE Source source 5 7 DSP_DISASM Disassembly disasm 6 0 DSP_SELF 7 1 DSP_CALLER Callers-Callees callers-callees 8 0 DSP_CALLEE 9 4 DSP_CALLTREE Call Tree calltree 10 0 DSP_TIMELINE Timeline timeline 11 0 DSP_STATIS Statistics statistics 12 0 DSP_EXP Experiments header 13 14 2 DSP_MEMOBJ Generic Memory Object Views 15 2 DSP_DATAOBJ Data Objects data_objects 16 2 DSP_DLAYOUT Data Layout data_layout 17 0 DSP_SRC_FILE ***Not used anymore ???*** 18 0 DSP_IFREQ Instruction Frequency ifreq 19 0 DSP_RACES Races races 20 3 DSP_INDXOBJ Generic Index Object Views 21 0 DSP_RACESOURCE Dual Source dsrc 22 0 DSP_SOURCE_DISASM Source/Disassembly srcdis 23 0 DSP_DEADLOCKS Deadlocks deadlocks 24 0 DSP_MPVIEW_TL MPI Timeline mpi_timeline 25 0 DSP_MPVIEW_CHART MPI Chart mpi_chart 26 27 7 DSP_SOURCE_V2 ***Not used anymore ???*** 28 7 DSP_DISASM_V2 ***Not used anymore ???*** 29 30 31 6 DSP_IOACTIVITY I/O ioactivity 32 0 DSP_OVERVIEW Overview overview 33 6 DSP_IOVFD ***Not used anymore ???*** 34 6 DSP_IOCALLSTACK ***Not used anymore ???*** 35 0 DSP_MINIFUNCTION 36 0 DSP_MINISELF 37 0 DSP_MINICALLER 38 0 DSP_MINICALLEE 39 8 DSP_HEAP Heap heap By Family: AnDisplay Type Family Variable User Name Internal Name ---- ------ ----------------- ------------------------ ----------------- -3 0 DSP_WELCOME Welcome welcome 1 0 DSP_FUNCTION Functions functions 2 0 DSP_LINE Lines lines 3 0 DSP_PC PCs pcs 6 0 DSP_SELF 8 0 DSP_CALLEE 10 0 DSP_TIMELINE Timeline timeline 11 0 DSP_STATIS Statistics statistics 12 0 DSP_EXP Experiments header 17 0 DSP_SRC_FILE ***Not used anymore ???*** 18 0 DSP_IFREQ Instruction Frequency ifreq 19 0 DSP_RACES Races races 21 0 DSP_RACESOURCE Dual Source dsrc 22 0 DSP_SOURCE_DISASM Source/Disassembly srcdis 23 0 DSP_DEADLOCKS Deadlocks deadlocks 24 0 DSP_MPVIEW_TL MPI Timeline mpi_timeline 25 0 DSP_MPVIEW_CHART MPI Chart mpi_chart 32 0 DSP_OVERVIEW Overview overview 35 0 DSP_MINIFUNCTION 36 0 DSP_MINISELF 37 0 DSP_MINICALLER 38 0 DSP_MINICALLEE 7 1 DSP_CALLER Callers-Callees callers-callees 14 2 DSP_MEMOBJ Generic Memory Object Views 15 2 DSP_DATAOBJ Data Objects data_objects 16 2 DSP_DLAYOUT Data Layout data_layout 20 3 DSP_INDXOBJ Generic Index Object Views 9 4 DSP_CALLTREE Call Tree calltree 31 6 DSP_IOACTIVITY I/O ioactivity 33 6 DSP_IOVFD ***Not used anymore ???*** 34 6 DSP_IOCALLSTACK ***Not used anymore ???*** 4 7 DSP_SOURCE Source source 5 7 DSP_DISASM Disassembly disasm 27 7 DSP_SOURCE_V2 ***Not used anymore ???*** 28 7 DSP_DISASM_V2 ***Not used anymore ???*** 39 8 DSP_HEAP Heap heap */ } gprofng-gui-1.0/org/gprofng/mpmt/metrics/0000755000175000017500000000000014517775726015500 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/metrics/MetricLabel.java0000644000175000017500000000746014517772113020440 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnObject; import org.gprofng.mpmt.settings.CompareModeSetting.CompareMode; import org.gprofng.mpmt.util.gui.AnUtility; import javax.swing.ImageIcon; public class MetricLabel { private ImageIcon icon; private ImageIcon sortIcon; private String[] titleLines; private String tip; private String unit; private double clock; private double total; private AnObject maxAnObject; private AnMetric anMetric; public MetricLabel( AnMetric anMetric, String tip, String unit, double clock, double total, AnObject maxAnObject, ImageIcon sortIcon) { this.anMetric = anMetric; this.tip = tip; this.unit = unit; this.clock = clock; this.total = total; this.maxAnObject = maxAnObject; this.sortIcon = sortIcon; titleLines = new String[2]; titleLines[1] = anMetric.getUserName(); String compareModifier = ""; if (anMetric.getCompareMode() == CompareMode.CMP_DELTA) { compareModifier = " " + AnLocale.getString("Delta"); } else if (anMetric.getCompareMode() == CompareMode.CMP_RATIO) { compareModifier = " " + AnLocale.getString("Ratio"); } if (this.anMetric.getSubType() == AnMetric.EXCLUSIVE) { titleLines[0] = AnLocale.getString("Exclusive") + compareModifier; icon = AnUtility.excl_icon; } else if (this.anMetric.getSubType() == AnMetric.INCLUSIVE) { titleLines[0] = AnLocale.getString("Inclusive") + compareModifier; icon = AnUtility.incl_icon; } else if (this.anMetric.getSubType() == 8) { // 8 = ATTRIBUTED titleLines[0] = AnLocale.getString("Attributed") + compareModifier; icon = null; } else { titleLines[0] = ""; icon = null; } // } } public String getText() { return getTip(); } public final ImageIcon getIcon() { return icon; } public final String[] getLegendAndTitleLines() { if (getAnMetric() != null) { if (getAnMetric().legend != null && getAnMetric().legend.length() > 0) { String[] t = new String[getTitleLines().length + 1]; t[0] = getAnMetric().legend; for (int i = 0; i < getTitleLines().length; i++) { t[i + 1] = getTitleLines()[i]; } return t; // title } } return getTitleLines(); } public AnMetric getAnMetric() { return anMetric; } public double getClock() { return clock; } public String getUnit() { return unit; } public ImageIcon getSortIcon() { return sortIcon; } public String[] getTitleLines() { return titleLines; } public String getTip() { return tip; } public double getTotal() { return total; } public AnObject getMaxAnObject() { return maxAnObject; } /** * @param maxAnObject the maxAnObject to set */ public void setMaxAnObject(AnObject maxAnObject) { this.maxAnObject = maxAnObject; } public void dump() { System.out.print("MetricLabel: "); for (int i = 0; i < titleLines.length; i++) { System.out.print(titleLines[i] + " "); } System.out.println(); } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/MetricsGUI.java0000644000175000017500000012151314517772113020224 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.overview.AnBarTree; import org.gprofng.mpmt.overview.AnBarTree.BarNode; import org.gprofng.mpmt.overview.Bar; import org.gprofng.mpmt.overview.Bar.ValueColor; import org.gprofng.mpmt.overview.BarPanel; import org.gprofng.mpmt.overview.CheckBoxBarPanel; import org.gprofng.mpmt.overview.Overview; import org.gprofng.mpmt.overview.TurnerLabelPanel; import org.gprofng.mpmt.overview.TurnerPanel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Image; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Formatter; import java.util.Iterator; import java.util.List; import java.util.Stack; import java.util.Vector; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTree; public class MetricsGUI { public static final boolean SHOW_ATTRIBUTES_IN_OVERVIEW = false; private int metricDisplayNameBaseWidth = 500; private int metricCheckBoxesPosition = 425; private Image exclusiveIcon = AnUtility.excl_icon.getImage(); private Image inclusiveIcon = AnUtility.incl_icon.getImage(); private static MetricsGUI instance = null; private MetricNode rootNode; private AnWindow window; private JTree tree; private JPanel rootPanel; public MetricsGUI(MetricNode rootNode, AnWindow window) { instance = this; this.rootNode = rootNode; this.window = window; } public static MetricsGUI getInstance() { return instance; } public int getMetricDisplayNameBaseWidth() { // int longestName = longestName(rootNode, 0); return metricDisplayNameBaseWidth; } public void refreshMetricsPanel() { // tree.validate(); // tree.repaint(100); if (tree != null) { for (int i = 0; i < tree.getRowCount(); i++) { // FIXUP: hack..... if (tree.isExpanded(i)) { tree.collapseRow(i); tree.expandRow(i); } else { tree.expandRow(i); tree.collapseRow(i); } } } rootPanel.repaint(); } public void setTreeNodeStateSelected( SelectableMetricNode selectableMetricNode, boolean selected) { if (tree != null) { ((AnBarTree) tree).setTreeNodeStateSelected(selectableMetricNode, selected); } } public void expandAllNodes() { if (tree != null) { for (int i = 0; i < tree.getRowCount(); i++) { tree.expandRow(i); } } } public void collapseAllNodes() { if (tree != null) { for (int i = tree.getRowCount() - 1; i >= 0; i--) { tree.collapseRow(i); } } } public JPanel createAvailableMetricsPanel() { rootPanel = new PanelWithHeaders(); rootPanel.setLayout(new GridBagLayout()); rootPanel.setBackground(Color.WHITE); JLabel titleLabel = new JLabel(AnLocale.getString("Available Metrics")); AnUtility.setAccessibleContext(titleLabel.getAccessibleContext(), titleLabel.getText()); titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD)); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.anchor = GridBagConstraints.WEST; rootPanel.add(titleLabel, gridBagConstraints); if (!SHOW_ATTRIBUTES_IN_OVERVIEW) { int titleLabelWidth = titleLabel.getPreferredSize().width; int fontSize = new JLabel().getFont().getSize(); int xOffset = 550 - titleLabelWidth; if (window.getSettings().getCompareModeSetting().comparingExperiments()) { xOffset += 100; } if (fontSize <= 12) { } else { xOffset += (fontSize - 12) * 25; } JPanel buttonPanel = createButtonPanel(); xOffset = xOffset - (buttonPanel.getPreferredSize().width / 2); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(0, xOffset, 0, 0); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; rootPanel.add(buttonPanel, gridBagConstraints); } JPanel barPanel = createBarPanel(rootNode); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; rootPanel.add(barPanel, gridBagConstraints); // panel.setBorder(new LineBorder(Color.green)); return rootPanel; } private class PanelWithHeaders extends JPanel { private final int fontHeight = getFontMetrics(getFont()).getHeight(); private int selectedLabelX = -1; private final int selectedLabelWidth = 60; private final int exclusiveLabelX = 82; private final int exclusiveLabelWidth = 80; private final int inclusiveLabelX = 102; private final int inclusiveLabelWidth = 80; private final int labelsY = 30; private int getFirstLabelX() { if (selectedLabelX <= 0) { int fontSize = new JLabel().getFont().getSize(); selectedLabelX = window.getSettings().getCompareModeSetting().comparingExperiments() ? getMetricDisplayNameBaseWidth() + 126 : getMetricDisplayNameBaseWidth() + 25; if (fontSize <= 12) { } else { selectedLabelX += (fontSize - 12) * 25; } } return selectedLabelX; } @Override public void paint(Graphics g) { super.paint(g); if (SHOW_ATTRIBUTES_IN_OVERVIEW) { int x; int y = labelsY; g.setFont( g.getFont() .deriveFont((float) 12)); // Always use size 12 font to paint headers (for now!) g.setColor(Color.BLACK); x = getFirstLabelX(); x = x - 20; // g.drawString(AnLocale.getString("Show in views"), x, y); g.drawString(AnLocale.getString("Show in views"), x, y + 14); x += exclusiveLabelX; x = x + 20; g.drawImage(exclusiveIcon, x, y - exclusiveIcon.getHeight(null) + 2, null); g.drawString(AnLocale.getString("Exclusive"), x + exclusiveIcon.getHeight(null) + 2, y); g.drawString(AnLocale.getString("Time Value %"), x - 5, y + 14); x += inclusiveLabelX; g.drawImage(inclusiveIcon, x, y - exclusiveIcon.getHeight(null) + 2, null); g.drawString(AnLocale.getString("Inclusive"), x + exclusiveIcon.getHeight(null) + 2, y); g.drawString(AnLocale.getString("Time Value %"), x - 5, y + 14); addMouseMotionListener( new MouseAdapter() { @Override public void mouseMoved(MouseEvent e) { int x = e.getX(); int y = e.getY(); if (x >= getFirstLabelX() && x <= (getFirstLabelX() + selectedLabelWidth) && y >= (labelsY - fontHeight) && y <= labelsY + fontHeight) { setToolTipText(AnLocale.getString("Choose metrics to be shown in data views")); } else if (x >= getFirstLabelX() + exclusiveLabelX && x <= (getFirstLabelX() + exclusiveLabelX + exclusiveLabelWidth) && y >= (labelsY - fontHeight) && y <= labelsY + fontHeight) { setToolTipText( AnLocale.getString( "Exclusive metrics do not include activity in called functions")); } else if (x >= getFirstLabelX() + exclusiveLabelX + inclusiveLabelX && x <= (getFirstLabelX() + exclusiveLabelX + inclusiveLabelX + inclusiveLabelWidth) && y >= (labelsY - fontHeight) && y <= labelsY + fontHeight) { setToolTipText( AnLocale.getString("Inclusive metrics include activity in called functions")); } else { setToolTipText(null); } } }); } } } public JPanel createButtonPanel() { JPanel buttonPanel = new JPanel(); buttonPanel.setBackground(Color.WHITE); buttonPanel.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints; gridBagConstraints = new GridBagConstraints(); int gridx = 0; gridBagConstraints.gridx = gridx++; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 0, 0, 0); JButton hotButton = new OverviewButton(AnLocale.getString("Hot")); hotButton.setMnemonic(AnLocale.getString('o', "OverviewHotButtonMN")); hotButton.setIcon(AnUtility.hot_icon); hotButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().getSettings().getMetricsSetting().hotAction(); } }); hotButton.setToolTipText( AnLocale.getString( "Select only metrics with the highest activity levels (marked check boxes)")); // JPanel hotPanel = new JPanel(); // hotPanel.setLayout(new GridBagLayout()); // hotPanel.setBackground(AnEnvironment.METRIC_HOT_HIGHLIGHT); // hotPanel.setPreferredSize(new Dimension(hotButton.getPreferredSize().width+4, // hotButton.getPreferredSize().height+4)); // GridBagConstraints gridBagConstraints2 = new GridBagConstraints(); // gridBagConstraints2.anchor = GridBagConstraints.CENTER; // hotPanel.add(hotButton, gridBagConstraints2); buttonPanel.add(hotButton, gridBagConstraints); gridBagConstraints.gridx = gridx++; gridBagConstraints.anchor = GridBagConstraints.WEST; JButton defaultButton = new OverviewButton(AnLocale.getString("Reset")); defaultButton.setMnemonic(AnLocale.getString('R', "OverviewResetButtonMN")); defaultButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().getSettings().getMetricsSetting().resetAction(); } }); defaultButton.setToolTipText(AnLocale.getString("Select the default set of metrics")); gridBagConstraints.insets = new Insets(0, 6, 0, 0); buttonPanel.add(defaultButton, gridBagConstraints); gridBagConstraints.gridx = gridx++; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 6, 0, 0); gridBagConstraints.weightx = 1.0; JButton clearAllButton = new OverviewButton(AnLocale.getString("Clear All")); clearAllButton.setMnemonic(AnLocale.getString('A', "OverviewClearAllButtonMN")); clearAllButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().getSettings().getMetricsSetting().clearAction(); } }); clearAllButton.setToolTipText(AnLocale.getString("Deselect all metrics")); buttonPanel.add(clearAllButton, gridBagConstraints); // buttonPanel.setBorder(new LineBorder(Color.green)); return buttonPanel; } class OverviewButton extends JButton { public OverviewButton(String text) { super(text); setText(text); setFont(Overview.defaultPlainFont); setMargin(new Insets(0, 4, 0, 4)); setOpaque(false); setBackground(new Color(237, 240, 244)); } @Override protected void paintComponent(Graphics g) { g.setColor(Color.red); g.fillRect(0, 0, getWidth(), getHeight()); Graphics2D g2d = (Graphics2D) g; int x = 15; int y = 25; Color topColor = new Color(240, 245, 239 + 15); Color bottomColor = new Color(176 + 20, 189 + 20, 201 + 20); GradientPaint gp; gp = new GradientPaint(0, 0, bottomColor, 0, getHeight() / 2, topColor); g2d.setPaint(gp); g2d.fillRect(0, 0, getWidth(), getHeight() / 2); gp = new GradientPaint(0, getHeight() / 2, topColor, 0, getHeight(), bottomColor); g2d.setPaint(gp); g2d.fillRect(0, getHeight() / 2, getWidth(), getHeight()); super.paintComponent(g); } } // private int longestName(MetricNode node, int max) { // int len = 0; // if (node == null || node.getMetricBasic() == null || // node.getMetricBasic().getDisplayName() == null) { // len = 0; // } // else { // len = node.getMetricBasic().getDisplayName().length(); // } // System.out.println(node.getMetricBasic().getDisplayName() + " " + len); // if (len > max) { // max = len; // } // for (MetricNode child : node.getChildren()) { // max = longestName(child, max); // } // return max; // } private JPanel createBarPanel(MetricNode node) { JPanel metricsBottomComponent = new JPanel(); metricsBottomComponent.setOpaque(false); metricsBottomComponent.setLayout(new GridBagLayout()); int gridy = 0; if (node == null) { return metricsBottomComponent; } TurnerPanel hwCounterMetricTurnerPanel = null; for (MetricNode child : node.getChildren()) { JPanel metricsPanel = null; if (child.getMetricType() == MetricNode.MetricType.AGGREGATE_TREE_ROOT_CATEGORY) { TurnerLabelPanel metric1TopComponent = new TurnerLabelPanel(child.getMetricBasic().getDisplayName(), formatValueLabel(child)); metric1TopComponent.setOpaque(false); JPanel metric1BottomComponent = aggregateTreeRootCategory(child); metricsPanel = new TurnerPanel( metric1TopComponent, metric1BottomComponent, 4, true, true, Overview.METRICS_BACKGROUND); } else if (child.getMetricType() == MetricNode.MetricType.AGGREGATE_LIST_CATEGORY || child.getMetricType() == MetricNode.MetricType .AGGREGATE_TREE_CATEGORY) { // FIXUP: may not always be correct. Workaround for // Linux HWC (16575950). Perhaps th tree itself should // be changed. TurnerLabelPanel metric1TopComponent = new TurnerLabelPanel(child.getMetricBasic().getDisplayName(), formatValueLabel(child)); metric1TopComponent.setOpaque(false); JPanel metric1BottomComponent = aggregateListCategory(child); metricsPanel = new TurnerPanel( metric1TopComponent, metric1BottomComponent, 4, true, true, Overview.METRICS_BACKGROUND); } else if (child.getMetricType() == MetricNode.MetricType.PLAIN_LIST_CATEGORY) { if (!child.isHiddenInOverview()) { TurnerLabelPanel metric1TopComponent = new TurnerLabelPanel( child.getMetricBasic().getDisplayName(), formatValueLabel(child)); metric1TopComponent.setOpaque(false); JPanel metric1BottomComponent = createBarPanel(child); // recursive! metricsPanel = new TurnerPanel( metric1TopComponent, metric1BottomComponent, 4, true, true, Overview.METRICS_BACKGROUND); } } else if (child.getMetricType() == MetricNode.MetricType.PLAIN || child.getMetricType() == MetricNode.MetricType.PLAIN_ROOT || child.getMetricType() == MetricNode.MetricType.PLAIN_CHILD) { if (!child.isHiddenInOverview()) { String name = child.getMetricBasic().getName(); String displayName = child.getMetricBasic().getDisplayName(); String displayNameValue = displayName; String tooltip = displayNameValue; Bar bar = null; if (child instanceof ValueMetricNode) { ValueMetricNode childValueMetricNode = (ValueMetricNode) child; displayNameValue = displayName + ": " + formatValueUnit(childValueMetricNode); // "Bugs 16624403 and 19539622" (leave this string intact for searches) if (displayName.equals("Block Covered %") || displayName.equals("Instr Covered %")) { displayNameValue = displayName; // revert to name without value } tooltip = displayNameValue; CompareBarData[] compareBars = null; compareBars = getCompareValueColors(childValueMetricNode, childValueMetricNode.getValue(0)); if (compareBars != null && compareBars.length > 0) { tooltip = formatToolTip(childValueMetricNode); int percent = childValueMetricNode.getValue(0).gtZero() ? 100 : 0; bar = new Bar(MetricColors.getColor(name), percent, compareBars); } } int maxWidth = maxWidthInPixelsOfChildren(node) + 50; int nodeLevel = nodeLevel(child); if (child instanceof SelectableMetricNode) { if (child.getMetricType() == MetricNode.MetricType.PLAIN_ROOT || child.getMetricType() == MetricNode.MetricType.PLAIN_CHILD) { nodeLevel++; } CheckBoxBarPanel checkBoxBarPanel = new CheckBoxBarPanel( child, child.isSelected(), child.isHot(), displayNameValue, tooltip, bar, maxWidth, null, -1, nodeLevel); // FIXUP: add bar when we have tables.... if (child.getMetricType() == MetricNode.MetricType.PLAIN_ROOT) { hwCounterMetricTurnerPanel = new TurnerPanel(checkBoxBarPanel, null, 0, true, false, Color.white); metricsPanel = hwCounterMetricTurnerPanel; } else if (child.getMetricType() == MetricNode.MetricType.PLAIN_CHILD) { if (hwCounterMetricTurnerPanel != null) { hwCounterMetricTurnerPanel.setBottomPanelComponent(checkBoxBarPanel); } hwCounterMetricTurnerPanel = null; } else { metricsPanel = checkBoxBarPanel; } } else { metricsPanel = new BarPanel( child, child.isSelected(), child.isHot(), displayNameValue, tooltip, bar, maxWidth, null, -1, nodeLevel); // FIXUP: add bar when we have tables.... } } } else { System.err.println("MetricsPanel:getMetricsPanels() not handling " + child.getMetricType()); assert false; } if (metricsPanel != null) { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridy++; gridBagConstraints.weightx = 1; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); // gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.WEST; metricsBottomComponent.add(metricsPanel, gridBagConstraints); } } return metricsBottomComponent; } private JPanel aggregateListCategory(MetricNode node) { MetricValue totalValueNode = null; String totalValueNodeText = null; if (node instanceof ValueMetricNode && ((ValueMetricNode) node).hasValues()) { ValueMetricNode parentValueMetricNode = (ValueMetricNode) node; totalValueNode = parentValueMetricNode.getValue(0); totalValueNodeText = parentValueMetricNode.getMetricBasic().getDisplayName(); } JPanel panel = new JPanel(); panel.setOpaque(false); panel.setLayout(new GridBagLayout()); int gridy = 0; for (MetricNode child : node.getChildren()) { if (child.getMetricType() == MetricNode.MetricType.PLAIN) { int percent = 0; CompareBarData[] compareBars = null; String toolTipText = null; if (child instanceof ValueMetricNode && totalValueNode != null) { ValueMetricNode childValueMetricNode = (ValueMetricNode) child; if (childValueMetricNode.hasValues()) { percent = childValueMetricNode.getValue(0).percentOf(totalValueNode); compareBars = getCompareValueColors(childValueMetricNode, totalValueNode); toolTipText = formatToolTip(childValueMetricNode, totalValueNode, totalValueNodeText); } } GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridy++; gridBagConstraints.insets = new Insets(0, 2, 0, 0); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; ValueColor[] valueColor = new Bar.ValueColor[] { new Bar.ValueColor(percent, MetricColors.getColor(child.getMetricBasic().getName())) }; Bar bar = new Bar(valueColor, percent, compareBars); CheckBoxBarPanel barPanel = new CheckBoxBarPanel( child, child.isSelected(), child.isHot(), child.getMetricBasic().getDisplayName(), toolTipText, bar, 31, null, -2, 3); panel.add(barPanel, gridBagConstraints); } } return panel; } private String formatToolTip(ValueMetricNode valueMetricNode) { return formatToolTip(valueMetricNode, null, null); } private String formatToolTip( ValueMetricNode valueMetricNode, MetricValue refMetric, String refMetricName) { String tt = ""; if (valueMetricNode.getValues().size() > 0) { String metricDisplayName = valueMetricNode.getMetricBasic().getDisplayName(); if (valueMetricNode.getValues().size() == 1) { tt = metricDisplayName + ": " + formatMetricValue(valueMetricNode.getValue(0), refMetric, refMetricName); } else { StringBuilder buf = new StringBuilder(); buf.append(""); buf.append("" + metricDisplayName + ""); int n = 0; for (MetricValue metricValue : valueMetricNode.getValues()) { buf.append("
"); if (n == 0) { String valueTxt = formatMetricValue(metricValue, refMetric, refMetricName); buf.append("Baseline"); for (int i = 0; i < 19; i++) { buf.append(" "); } if (valueMetricNode.getValues().size() > 2) { for (int i = 0; i < 3; i++) { buf.append(" "); } } buf.append(": " + valueTxt); } else { String valueTxt = formatMetricValue(metricValue, valueMetricNode.getValues().get(0), null); if (valueMetricNode.getValues().size() == 2) { buf.append("Comparison Group: " + valueTxt); } else { buf.append("Comparison Group " + n + ": " + valueTxt); } } n++; } buf.append(""); tt = buf.toString(); } } return tt; } private String formatMetricValue( MetricValue metricValue, MetricValue refMetricValue, String refMetricName) { String valueUnit = metricValue.formatValueUnit(); if (metricValue.getValueType() == MetricValue.ValueType.LABEL_ONLY || refMetricValue == null) { // No comparison to a reference return valueUnit; } String compareText = ""; int percent = metricValue.percentOf(refMetricValue); String percentString; if (percent == MetricValue.PERCENT_NAN) { percentString = "+INF%"; } else { percentString = new Formatter().format("%d%%", percent).toString(); } if (refMetricName != null) { // show percent of some other total compareText = new Formatter() .format(", " + AnLocale.getString("%s of %s"), percentString, refMetricName) .toString(); } else { // show delta from base MetricValue diffValue = metricValue.clone(); diffValue.subtract(refMetricValue); String diffValueString = diffValue.formatValue(); if (!diffValue.ltZero()) { diffValueString = "+" + diffValueString; } compareText = new Formatter().format(" (%s, %s)", diffValueString, percentString).toString(); } String txt = new Formatter().format("%s%s", valueUnit, compareText).toString(); return txt; } private String formatValueLabel(MetricNode node) { String label = null; if (node instanceof ValueMetricNode) { ValueMetricNode valueMetricNode = (ValueMetricNode) node; if (valueMetricNode.hasValues()) { MetricValue metricValue = valueMetricNode.getValue(0); if (metricValue.getValueType() == MetricValue.ValueType.LABEL_ONLY) { label = metricValue.getLabel(); } else { label = new Formatter() .format( "%s: %s", valueMetricNode.getValue(0).getLabel(), valueMetricNode.getValue(0).formatValueUnit()) .toString(); } } } return label; } private String formatValueUnit(ValueMetricNode valueMetricNode) { String valueUnit = ""; if (valueMetricNode.hasValues()) { valueUnit = valueMetricNode.getValue(0).formatValueUnit(); } return valueUnit; } private static int stringWidthInPixels(String s) { int width = new JLabel(s).getPreferredSize().width; return width + 30; } private static int maxWidthInPixelsOfChildren(MetricNode node) { int maxWidth = 0; { for (MetricNode child : node.getChildren()) { String displayName = child.getMetricBasic().getDisplayName(); int width = stringWidthInPixels(displayName); if (width > maxWidth) { maxWidth = width; } } } return maxWidth; } private static void maxWidthInPixelsOfChildren( MetricNode node, int level, int maxWidthAtLevel[]) { for (MetricNode child : node.getChildren()) { String displayName = child.getMetricBasic().getDisplayName(); int width = stringWidthInPixels(displayName); if (width > maxWidthAtLevel[level]) { maxWidthAtLevel[level] = width; } if (!child.getChildren().isEmpty()) { maxWidthInPixelsOfChildren(child, level + 1, maxWidthAtLevel); } } } private static int maxWidthInPixels(int maxWidthAtLevel[]) { int max = 0; for (int i = 0; i < maxWidthAtLevel.length; i++) { if (maxWidthAtLevel[i] > max) { max = maxWidthAtLevel[i]; } } return max; } private JPanel aggregateTreeRootCategory(MetricNode node) { List rootNodes = new ArrayList(); int maxWidthAtLevel[] = new int[10]; int level = 0; maxWidthInPixelsOfChildren(node, level + 1, maxWidthAtLevel); for (MetricNode child : node.getChildren()) { if (child.getMetricType() == MetricNode.MetricType.AGGREGATE_TREE_CATEGORY) { Vector treeNode = aggregateTreeCategory(node, child, maxWidthAtLevel, level + 1); rootNodes.add(treeNode); } else if (child.getMetricType() == MetricNode.MetricType.PLAIN) { // Vector treeNode = aggregateTreeCategory(node, child, // maxWidthAtLevel, level+1); MetricValue totalValueNode = null; String totalValueNodeText = null; if (node instanceof ValueMetricNode && ((ValueMetricNode) node).hasValues()) { totalValueNode = ((ValueMetricNode) node).getValue(0); totalValueNodeText = node.getMetricBasic().getDisplayName(); } int percent = 0; CompareBarData[] compareBars = null; String toolTipText = null; if (child instanceof ValueMetricNode) { ValueMetricNode nodeValueMetricNode = (ValueMetricNode) child; if (nodeValueMetricNode.hasValues() && totalValueNode != null) { percent = nodeValueMetricNode.getValue(0).percentOf(totalValueNode); compareBars = getCompareValueColors(nodeValueMetricNode, totalValueNode); toolTipText = formatToolTip(nodeValueMetricNode, totalValueNode, totalValueNodeText); } } int maxWidth = maxWidthInPixelsOfChildren(node); List barValueColors = new ArrayList(); barValueColors.add( new Bar.ValueColor(percent, MetricColors.getColor(child.getMetricBasic().getName()))); Bar cpuBar = new Bar(barValueColors, percent, compareBars); Vector plainNode = new AnBarTree.BarNode( child, false, toolTipText, cpuBar, maxWidth, 0); rootNodes.add(plainNode); } else { System.err.println( "MetricsPanel:aggregateTreeRootCategory() not handling " + child.getMetricType()); assert false; } } Vector rootVector = new AnBarTree.BarNode( node, true, null, null, rootNodes, maxWidthInPixels(maxWidthAtLevel), level); // GUI tree = new AnBarTree(rootVector); JPanel panel = new JPanel(); panel.setOpaque(false); panel.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints; gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); panel.add(tree, gridBagConstraints); // expandBranchesWithSelections(node, tree); // Hack to get rid of all turners on leaf nodes expandAllNodes(); collapseAllNodes(); // Expand only root node tree.expandRow(0); return panel; } // private void expandBranchesWithSelections(MetricNode rootNode, JTree tree) { // if (tree == null) { // return; // } // Stack levels = new Stack(); // levels.push(-1); // expandBranchesWithSelectionsOrIsHot(levels, rootNode, tree); // } private void expandBranchesWithSelectionsOrIsHot( Stack levels, MetricNode node, JTree tree) { if (node instanceof SelectableMetricNode) { boolean hasSelectionsOrHot = node.isSelected() || node.isHot(); if (hasSelectionsOrHot) { Iterator iterator = levels.iterator(); while (iterator.hasNext()) { int level = iterator.next().intValue(); if (iterator.hasNext() && level >= 0) { tree.expandRow(level); } } } } int currentLevel = levels.peek().intValue(); levels.push(currentLevel + 1); for (MetricNode child : node.getChildren()) { expandBranchesWithSelectionsOrIsHot(levels, child, tree); } levels.pop(); } private int nodeLevel(MetricNode targetNode) { int level = nodeLevel(rootNode, targetNode, 0); return level; } private int nodeLevel(MetricNode node, MetricNode targetNode, int level) { for (MetricNode child : node.getChildren()) { if (child == targetNode) { return level + 1; } int l = nodeLevel(child, targetNode, level + 1); if (l > 0) { return l; } } return -1; } private CompareBarData[] getCompareValueColors(ValueMetricNode node, MetricValue totalValueNode) { if (node.hasValues()) { if (node.getValues().size() <= 1) { return null; } else { CompareBarData[] compareValueColors = new CompareBarData[node.getValues().size() - 1]; for (int valueNo = 1; valueNo < node.getValues().size(); valueNo++) { MetricValue metricValue = node.getValues().get(valueNo); int percent = metricValue.percentOf(totalValueNode); List valueColorList = new ArrayList(); if (node.getChildren() != null && !node.getChildren().isEmpty()) { for (MetricNode child : node.getChildren()) { if (child.getChildren() != null && !child.getChildren().isEmpty()) { for (MetricNode grandchildren : child .getChildren()) { // handles User/System/trap CPU time //YM: Should probably // be recursive MetricValue metricValue2 = ((ValueMetricNode) grandchildren).getValues().get(valueNo); int percent2 = metricValue2.percentOf(node.getValue(valueNo)); ValueColor valueColor = new ValueColor( percent2, MetricColors.getColor(grandchildren.getMetricBasic().getName())); valueColorList.add(valueColor); } } else { MetricValue metricValue2 = ((ValueMetricNode) child).getValues().get(valueNo); int percent2 = metricValue2.percentOf(node.getValue(valueNo)); ValueColor valueColor = new ValueColor( percent2, MetricColors.getColor(child.getMetricBasic().getName())); valueColorList.add(valueColor); } } } else { ValueColor valueColor = new ValueColor(100, MetricColors.getColor(node.getMetricBasic().getName())); valueColorList.add(valueColor); } compareValueColors[valueNo - 1] = new CompareBarData(percent, valueColorList); } // dumpCompareValueColors(node, compareValueColors); return compareValueColors; // for (int i = 1; i < node.getValues().size(); i++) { // MetricValue metricValue = node.getValues().get(i); // int percent = metricValue.percentOf(totalValueNode); // // List valueColorList = new ArrayList(); // ValueColor valueColor = new ValueColor(50, Bar.BAR_COMPARE_COLORS[i % // 2]); // valueColorList.add(valueColor); // valueColor = new ValueColor(50, Bar.BAR_COMPARE_COLORS[(i+1) % 2]); // valueColorList.add(valueColor); // // compareValueColors[i - 1] = new CompareBarData(percent, // valueColorList); // } // dumpCompareValueColors(node, compareValueColors); // return compareValueColors; } } return null; } private void dumpCompareValueColors(ValueMetricNode node, CompareBarData[] compareValueColors) { System.out.println("compareValueColors: " + node.getMetricBasic().getDisplayName()); for (CompareBarData cbd : compareValueColors) { System.out.print("CompareBarData:" + cbd.getPercentOfTotal()); for (ValueColor vc : cbd.getValueColors()) { System.out.print(" ["); System.out.print(vc.getValue() + " " + vc.getColor()); System.out.print("]"); } System.out.println(); } } private Vector aggregateTreeCategory( MetricNode rootNode, MetricNode node, int maxWidthAtLevel[], int level) { MetricValue totalValueNode = null; String totalValueNodeText = null; if (rootNode instanceof ValueMetricNode && ((ValueMetricNode) rootNode).hasValues()) { totalValueNode = ((ValueMetricNode) rootNode).getValue(0); totalValueNodeText = rootNode.getMetricBasic().getDisplayName(); } List barNodes = new ArrayList(); List barValueColors = new ArrayList(); List children = node.getChildren(); for (MetricNode child : children) { if (child.getMetricType() == MetricNode.MetricType.PLAIN) { int percent = 0; CompareBarData[] compareBars = null; String toolTipText = null; if (child instanceof ValueMetricNode) { ValueMetricNode childValueMetricNode = (ValueMetricNode) child; if (childValueMetricNode.hasValues()) { percent = childValueMetricNode.getValue(0).percentOf(totalValueNode); compareBars = getCompareValueColors(childValueMetricNode, totalValueNode); toolTipText = formatToolTip(childValueMetricNode, totalValueNode, totalValueNodeText); } } barNodes.add( new BarNode( child, child.isSelected(), toolTipText, new Bar( new Bar.ValueColor[] { new Bar.ValueColor( percent, MetricColors.getColor(child.getMetricBasic().getName())) }, percent, compareBars), maxWidthInPixels(maxWidthAtLevel), level + 1)); barValueColors.add( new Bar.ValueColor(percent, MetricColors.getColor(child.getMetricBasic().getName()))); } else if (child.getMetricType() == MetricNode.MetricType.AGGREGATE_TREE_CATEGORY) { int percent = 0; CompareBarData[] compareBars = null; String toolTipText = null; if (child instanceof ValueMetricNode) { ValueMetricNode childValueMetricNode = (ValueMetricNode) child; if (childValueMetricNode.hasValues()) { percent = childValueMetricNode.getValue(0).percentOf(totalValueNode); compareBars = getCompareValueColors(childValueMetricNode, totalValueNode); toolTipText = formatToolTip(childValueMetricNode, totalValueNode, totalValueNodeText); } } Vector vector = aggregateTreeCategory(rootNode, child, maxWidthAtLevel, level + 1); List barValueColorsThisBar = new ArrayList(); for (AnBarTree.BarNode barNode : vector) { List valueColorList = barNode.getBar().getValueColor(); for (ValueColor valueColor : valueColorList) { barValueColors.add(valueColor); barValueColorsThisBar.add(valueColor); } } barNodes.add( new BarNode( child, child.isSelected(), toolTipText, new Bar(barValueColorsThisBar, percent, compareBars), vector, maxWidthInPixels(maxWidthAtLevel), level + 1)); } } int percent = 0; CompareBarData[] compareBars = null; String toolTipText = null; if (node instanceof ValueMetricNode) { ValueMetricNode nodeValueMetricNode = (ValueMetricNode) node; if (nodeValueMetricNode.hasValues() && totalValueNode != null) { percent = nodeValueMetricNode.getValue(0).percentOf(totalValueNode); compareBars = getCompareValueColors(nodeValueMetricNode, totalValueNode); toolTipText = formatToolTip(nodeValueMetricNode, totalValueNode, totalValueNodeText); } } Bar cpuBar = new Bar(barValueColors, percent, compareBars); Vector cpuNode = new AnBarTree.BarNode( node, node.isSelected(), toolTipText, cpuBar, barNodes, maxWidthInPixels(maxWidthAtLevel), level); return cpuNode; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/BasicMetric.java0000644000175000017500000000303514517772113020434 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; public class BasicMetric { private final String name; // BaseMetric.cc:cmd (aux for hwcs) example: "datapagefault", not I18N private final String shortDescription; // BaseMetricTreeNode.cc: May be null. private final String displayName; // BaseMetric.cc:user_name "Data Page Fault" public BasicMetric(String name, String description, String displayName) { this.name = name; this.shortDescription = description; this.displayName = displayName; } public String getName() { return name; } public String getShortDescription() { // may return null return shortDescription; } public String getDisplayName() { return displayName; } @Override public BasicMetric clone() { BasicMetric clone = new BasicMetric(getName(), getShortDescription(), getDisplayName()); return clone; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/MetricColors.java0000644000175000017500000000767014517772113020665 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import java.awt.Color; import java.util.HashMap; public class MetricColors { private static Color defaultSingle = new Color(145, 145, 145); private static Color defaultMissing = defaultSingle; public static final Color GREEN = new Color(95, 200, 48); public static final Color LIGHT_GREEN = new Color(0xcc, 0xff, 0x00); public static final Color GOLDEN_YELLOW = new Color(0xfd, 0xde, 0x00); public static final Color FUSCHIA = new Color(242, 0, 255); public static final Color PLUM = new Color(169, 19, 182); public static final Color BLUE_VIOLET = new Color(116, 1, 223); public static final Color ORANGE = new Color(0xff, 0x96, 0x09); public static final Color RED = new Color(255, 18, 0); public static final Color COBALT = new Color(0, 34, 255); public static final Color DARK_GREY = new Color(112, 119, 137); public static final Color CYAN = Color.CYAN; public static final Color BLUE = Color.BLUE; public static final Color GRAY = Color.GRAY; public static final Color BLACK = Color.BLACK; private static final HashMap colorHashMap = new HashMap(); static { // SOLARIS MICROSTATES colorHashMap.put("user".hashCode(), GREEN); colorHashMap.put("system".hashCode(), LIGHT_GREEN); colorHashMap.put("trap".hashCode(), GOLDEN_YELLOW); colorHashMap.put("datapfault".hashCode(), FUSCHIA); colorHashMap.put("textpfault".hashCode(), PLUM); colorHashMap.put("kernelpfault".hashCode(), BLUE_VIOLET); colorHashMap.put("stop".hashCode(), ORANGE); colorHashMap.put("wait".hashCode(), RED); colorHashMap.put("sleep".hashCode(), COBALT); colorHashMap.put("lock".hashCode(), DARK_GREY); // colorHashMap.put("totalcpu".hashCode(), colorHashMap.get("user".hashCode())); // TBR? colorHashMap.put("owait".hashCode(), colorHashMap.get("wait".hashCode())); // TBR? // DEAD_CODE? colorHashMap.put("readiobytes".hashCode(), new Color(219, 87, 100)); colorHashMap.put("writeiobytes".hashCode(), new Color(252, 88, 78)); // DEAD_CODE END colorHashMap.put("heapalloccnt".hashCode(), defaultSingle); colorHashMap.put("heapallocbytes".hashCode(), defaultSingle); colorHashMap.put("heapleakcnt".hashCode(), defaultSingle); colorHashMap.put("heapleakbytes".hashCode(), defaultSingle); } public static void setCustomMetricColor(String name, Color color) { if (name.equals("default")) { defaultSingle = color; defaultMissing = color; } else { colorHashMap.put(name.hashCode(), color); } } public static Color getColor(String name) { int hashCode = name.hashCode(); Color color = colorHashMap.get(hashCode); if (color == null) { // System.err.println("MetricsColors.getColor \'" + name + "\' not found in color // map!"); color = defaultMissing; } return color; } public static class MetricColor { private String metricName; private Color color; public MetricColor(String metricName, Color color) { this.metricName = metricName; this.color = color; } /** * @return the metricName */ public String getMetricName() { return metricName; } /** * @return the color */ public Color getColor() { return color; } } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/MetricOption.java0000644000175000017500000000505114517772113020663 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import org.gprofng.mpmt.AnMetric; public class MetricOption { private final MetricAttr capable; // static capability private MetricAttr selected; // frontend sets these private final MetricAttr defaultAttrs; public MetricOption(MetricAttr capable, MetricAttr defaultValues) { this.capable = capable; this.selected = defaultValues.clone(); this.defaultAttrs = defaultValues; validateSelected(); } private void validateSelected() { int selectedBits = selected.getVisibleAttrs(); int allowedBits = selectedBits & capable.getVisibleAttrs(); if (selectedBits != allowedBits) { // illegal selected bits! // for time values, meaning of .er.rc dmetrics command's . and + symbols is swapped. if (capable.isTime() && selected.isValue()) { selected.setAttrs(allowedBits | AnMetric.VAL_TIMEVAL); // YXXX lame } else { selected.setAttrs(allowedBits); // unexpected, should bail out here? } } } /** * @return the capable */ public MetricAttr getCapable() { return capable; } /** * @return the selected */ public MetricAttr getSelected() { return selected; } /** * @param selected the selected to set */ public void setSelected(MetricAttr selected) { this.selected = selected; } /** * @return the selected */ public boolean hasSelections() { if (selected == null) { return false; } return selected.hasVisibleAttrs(); } /** * @return the userSavedValues */ public MetricAttr getDefaultAttrs() { return defaultAttrs; } public MetricOption clone() { MetricAttr capableClone = getCapable().clone(); // MetricAttr selectedClone = getSelected().clone(); MetricAttr defaultAttrsClone = defaultAttrs.clone(); MetricOption clone = new MetricOption(capableClone, defaultAttrsClone); return clone; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/MetricAttr.java0000644000175000017500000000573614517772113020337 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import org.gprofng.mpmt.AnMetric; public class MetricAttr { // AKA DBE ValueStyle bitmask private int enabledAttrs; // bitmask, e.g. AnMetric.VAL_TIMEVAL public MetricAttr(boolean is_hidden, boolean time, boolean value, boolean percent) { setAttrs(is_hidden, time, value, percent); } public MetricAttr(int value_styles) { enabledAttrs = value_styles; } /** * @return set the enabledAttrs */ public void setAttrs(int value_styles) { enabledAttrs = value_styles; } public void setAttrs(boolean is_hidden, boolean time, boolean value, boolean percent) { enabledAttrs = 0; if (is_hidden) { enabledAttrs |= AnMetric.VAL_HIDE_ALL; } if (time) { enabledAttrs |= AnMetric.VAL_TIMEVAL; } if (value) { enabledAttrs |= AnMetric.VAL_VALUE; } if (percent) { enabledAttrs |= AnMetric.VAL_PERCENT; } } public void setTime(boolean time) { setAttrs(isHidden(), time, isValue(), isPercent()); } public void setValue(boolean value) { setAttrs(isHidden(), isTime(), value, isPercent()); } public void setPercent(boolean percent) { setAttrs(isHidden(), isTime(), isValue(), percent); } /** * @return the hidden */ public boolean isHidden() { boolean hidden = (enabledAttrs & AnMetric.VAL_HIDE_ALL) != 0; return hidden; } /** * @return the time */ public boolean isTime() { boolean time = (enabledAttrs & AnMetric.VAL_TIMEVAL) != 0; return time; } /** * @return the value */ public boolean isValue() { boolean value = (enabledAttrs & AnMetric.VAL_VALUE) != 0; return value; } /** * @return the percent */ public boolean isPercent() { boolean percent = (enabledAttrs & AnMetric.VAL_PERCENT) != 0; return percent; } /** * @return true if any Attrs enabled */ public boolean hasVisibleAttrs() { int visibleAttrs = getVisibleAttrs(); boolean enabled = (visibleAttrs != 0); return enabled; } /** * @return the enabledAttrs */ public int getVisibleAttrs() { if (isHidden()) { return AnMetric.VAL_NA; } int visibleAttrs = (enabledAttrs & ~AnMetric.VAL_HIDE_ALL); return visibleAttrs; } public MetricAttr clone() { MetricAttr clone = new MetricAttr(enabledAttrs); return clone; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/MetricNode.java0000644000175000017500000001740414517772113020305 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnWindow; import java.util.ArrayList; import java.util.List; public class MetricNode { public static final int ALL_LIST_ID = 0; public static final int IO_LIST_ID = 16; public static final int HEAP_LIST_ID = 43; public static final int DATASPACE_HWC_LIST_ID = 72; public enum MetricType { PLAIN_CATEGORY, PLAIN_LIST_CATEGORY, AGGREGATE_LIST_CATEGORY, PLAIN_TREE_CATEGORY, AGGREGATE_TREE_ROOT_CATEGORY, AGGREGATE_TREE_CATEGORY, PLAIN, PLAIN_ROOT, PLAIN_CHILD }; private final BasicMetric metricBasic; private MetricType metricType; private final List children; private boolean hiddenInOverview; // never show this in overview public MetricNode(BasicMetric metricBasic, MetricType metricType) { this.metricBasic = metricBasic; this.metricType = metricType; this.children = new ArrayList(); this.hiddenInOverview = false; } public void setHiddenInOverview(boolean hiddenInOverview) { this.hiddenInOverview = hiddenInOverview; } /** * @return the hiddenInOverview */ public boolean isHiddenInOverview() { return hiddenInOverview; } public void addChild(MetricNode metricNode) { children.add(metricNode); } public List getChildren() { return children; } public BasicMetric getMetricBasic() { return metricBasic; } public MetricType getMetricType() { return metricType; } public void setMetricType(MetricType metricType) { this.metricType = metricType; } public List findByName(String name) { List list = new ArrayList(); findByName(name, list); return list; } private void findByName(String name, List list) { if (getMetricBasic().getName() != null && getMetricBasic().getName().equals(name)) { list.add(this); } for (MetricNode child : getChildren()) { child.findByName(name, list); } } public void postProcessRoot() { // only call this on root! for (MetricNode child : getChildren()) { postProcess(child); } } private void postProcess(MetricNode node) { // System.out.println("MetricNode.postProcess " + node.getMetricType() + " " + // node.getMetricBasic().getName()); // HACK BEGIN: AGGREGATE_TREE_ROOT_CATEGORY has the wrong value. should have tsame value as // first AGGREGATE_TREE_CATEGORY if (node.getMetricType() == MetricNode.MetricType.AGGREGATE_TREE_ROOT_CATEGORY) { for (MetricNode child : node.getChildren()) { if (child.getMetricType() == MetricNode.MetricType.AGGREGATE_TREE_CATEGORY && child instanceof ValueMetricNode && ((ValueMetricNode) child).hasValues()) { double totalValue = ((ValueMetricNode) child).getValue(0).getDValue(); ((ValueMetricNode) node).getValue(0).setDValue(totalValue); } } } // HACK END // Insert child node in those AGGREGATE_TREE_CATEGORY that don't have children if (node.getMetricType() == MetricNode.MetricType.AGGREGATE_TREE_CATEGORY) { if (node.getChildren() == null || node.getChildren().isEmpty()) { if (node instanceof SelectableMetricNode) { // Add identical node as a MetricType.PLAIN child SelectableMetricNode selectableMetricNode = (SelectableMetricNode) node; BasicMetric basicMetricClone = node.getMetricBasic().clone(); MetricOption exclusiveClone = selectableMetricNode.getExclusive().clone(); MetricOption inclusiveClone = selectableMetricNode.getInclusive().clone(); SelectableMetricNode child = new SelectableMetricNode( basicMetricClone, MetricNode.MetricType.PLAIN, exclusiveClone, inclusiveClone, selectableMetricNode.getValueType()); node.addChild(child); // Set the same value List list = new ArrayList(); for (MetricValue metricValue : selectableMetricNode.getValues()) { MetricValue metricValueClone = metricValue.clone(); list.add(metricValueClone); } child.setValues(list); } } } // Transfer 'hot' to AnMetrics so others can know if (node instanceof SelectableMetricNode) { SelectableMetricNode smnode = (SelectableMetricNode) node; AnWindow.getInstance() .getSettings() .getMetricsSetting() .setHotMetric(smnode.getMetricBasic().getName(), smnode.isHot()); } // Look for HW Counter pairs pairs. They come in pairs like "tcycles"/"cycles". Mark them as // PLAIN_ROOT/PLAIN_CHILD. AnMetric[] availableMetrics = AnWindow.getInstance().getSettings().getMetricsSetting().getAvailableAnMetrics(); if (node.getMetricType() == MetricNode.MetricType.PLAIN_LIST_CATEGORY) { // FIXUP List children = node.getChildren(); for (int i = 0; i < children.size(); i++) { String name = children.get(i).getMetricBasic().getName(); AnMetric anMetric = AnWindow.getInstance().getSettings().getMetricsSetting().getAvailableAnMetric(name); if (anMetric != null) { String aux = anMetric.getAux(); if (aux != null && !name.equals(aux)) { for (int j = 0; j < children.size(); j++) { if (children.get(j).getMetricBasic().getName().equals(aux)) { children.get(i).setMetricType(MetricType.PLAIN_ROOT); children.get(j).setMetricType(MetricType.PLAIN_CHILD); break; } } } } // if (name.startsWith("t") && i < (children.size()-1) && // name.substring(1).equals(children.get(i+1).getMetricBasic().getName())) { // children.get(i).setMetricType(MetricType.PLAIN_ROOT); // children.get(i+1).setMetricType(MetricType.PLAIN_CHILD); // i++; // } } } for (MetricNode child : node.getChildren()) { postProcess(child); } } public boolean hasSelections() { boolean hasSelections = false; if (this instanceof SelectableMetricNode) { SelectableMetricNode selectableMetricNode = (SelectableMetricNode) this; hasSelections = selectableMetricNode.hasSelections(); } return hasSelections; } public boolean isSelected() { boolean selected = false; if (this instanceof SelectableMetricNode) { SelectableMetricNode selectableMetricNode = (SelectableMetricNode) this; selected = selectableMetricNode.isSelected(); } return selected; } public boolean isHot() { boolean isHot = false; if (this instanceof SelectableMetricNode) { ValueMetricNode valueMetricNode = (ValueMetricNode) this; List values = valueMetricNode.getValues(); for (MetricValue value : values) { if (value.getHighlight()) { isHot = true; break; } } } return isHot; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/IPCMetricsAPI.java0000644000175000017500000002633514517772113020553 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import java.util.ArrayList; import java.util.List; public class IPCMetricsAPI { public static boolean isJavaEnabled = false; public static boolean getJavaEnableIPC() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getJavaEnable"); // New ipc request! IPCResult ipcResult = ipcHandle.sendRequest(); if (ipcResult.getCC() == IPCResult.CC.SUCCESS) { // blocking // Things are fine isJavaEnabled = ipcResult.getBoolean(); return isJavaEnabled; } return false; } public static MetricNode getAllAvailableMetricsIPC(int dbevindex) { // Getting list of metrics from backend boolean include_unregistered_metrics = false; IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getRefMetricTree"); // New ipc request! ipcHandle.append(dbevindex); ipcHandle.append(include_unregistered_metrics); IPCResult ipcResult = ipcHandle.sendRequest(); if (ipcResult.getCC() == IPCResult.CC.SUCCESS) { // blocking // Things are fine Object[] data = (Object[]) ipcResult.getObject(); MetricNode nodeTree = parseRefMetricTreeIpcData(null, data, 0); return nodeTree; } else { int i = 0; // for breakpoint // error handling } return null; } private static MetricNode parseRefMetricTreeIpcData(String parentName, Object[] data, int level) { Object fields[] = (Object[]) data[0]; Object children[] = (Object[]) data[1]; String name = ((String[]) fields[0])[0]; String username = ((String[]) fields[1])[0]; String description = ((String[]) fields[2])[0]; int flavors = ((int[]) fields[3])[0]; // bitmask e.g. EXCLUSIVE int vtype = ((int[]) fields[4])[0]; // e.g.AnVariable:VT_INT int vstyles_capable = ((int[]) fields[5])[0]; // bitmask e.g.VAL_TIMEVAL int vstyles_e_default_values = ((int[]) fields[6])[0]; // excl defaults: VAL_TIME, etc. int vstyles_i_default_values = ((int[]) fields[7])[0]; // incl defaults: VAL_TIME, etc. boolean registered = ((boolean[]) fields[8])[0]; boolean aggregation = ((boolean[]) fields[9])[0]; boolean has_value = ((boolean[]) fields[10])[0]; String unit = ((String[]) fields[11])[0]; String unit_uname = ((String[]) fields[12])[0]; if (name != null && name.equals("name")) { // YXXX where should we put this special case? return null; } boolean is_total_time = false; // YXXX Yuck. where should we put Thomas' special case? if (name != null) { if (name.equals("total")) { is_total_time = true; } if (name.equals("totalcpu") && parentName != null && !parentName.equals( "total")) { // See 18378636 - Overview is insufficient to pick metrics for er_kernel // experiments is_total_time = true; } } boolean isHiddenInOverview = ((flavors & AnMetric.STATIC) != 0); if (name != null && name.equals("PROFDATA_TYPE_STATIC")) { isHiddenInOverview = true; } if (!isJavaEnabled && name != null && name.equals("PROFDATA_TYPE_GCDURATION")) { isHiddenInOverview = true; } boolean selectable = (vstyles_capable != 0) ? true : false; MetricNode.MetricType mtype; if (name == null) { // unnamed node mtype = MetricNode.MetricType.PLAIN_CATEGORY; } else if (aggregation) { mtype = MetricNode.MetricType.AGGREGATE_TREE_CATEGORY; } else if (children.length > 0) { mtype = MetricNode.MetricType.PLAIN_LIST_CATEGORY; } else { // System.out.println("=================== " + vtype + " " + name); mtype = MetricNode.MetricType.PLAIN; } BasicMetric basicMetric = new BasicMetric(name, description, username); MetricNode node; if (selectable) { MetricOption exclusive = new MetricOption( new MetricAttr(vstyles_capable), new MetricAttr(vstyles_e_default_values)); MetricOption inclusive = new MetricOption( new MetricAttr(vstyles_capable), new MetricAttr(vstyles_i_default_values)); node = new SelectableMetricNode(basicMetric, mtype, exclusive, inclusive, vtype); } else if (has_value) { node = new ValueMetricNode(basicMetric, mtype, unit, unit_uname); } else { node = new MetricNode(basicMetric, mtype); } node.setHiddenInOverview(isHiddenInOverview); // YXXX yuck: if is_total, insert a dummy "total thread time" node MetricNode parentNode = node; if (is_total_time && aggregation) { BasicMetric totalBMetric = new BasicMetric("YXXX_TOTAL_TIME_PLUS_THREADS", description, username); parentNode = new ValueMetricNode(totalBMetric, MetricNode.MetricType.AGGREGATE_TREE_ROOT_CATEGORY); parentNode.addChild(node); } // debug printing if (false) { for (int jj = 0; jj < level; jj++) { System.out.printf(" "); } System.out.printf( "%c L%d, %s, %s, %s\n", registered ? '*' : ' ', level, username, name, mtype); System.out.printf( "\taggregation=%d\thas_val=%d\tflavors=%d\t" + "vtype=%d\tviz_capable=%d\te_viz=%d\ti_viz=%d\n", aggregation ? 1 : 0, has_value ? 1 : 0, flavors, vtype, vstyles_capable, vstyles_e_default_values, vstyles_i_default_values); } for (int ii = 0; ii < children.length; ii++) { Object[] child_data = (Object[]) children[ii]; MetricNode child = parseRefMetricTreeIpcData(name, child_data, level + 1); if (child != null) { // child may decide it is invisible node.addChild(child); } } return parentNode; } public static boolean updateMetricValues(int dbevindex, List valueMetricList) { // System.out.println("updateMetricValues:"); // split into lists of nodes w/ metrics and nodes that just have values List selectableMetrics = new ArrayList(); List valueMetricsOnly = new ArrayList(); for (ValueMetricNode valueMetricNode : valueMetricList) { if (valueMetricNode instanceof SelectableMetricNode) { selectableMetrics.add((SelectableMetricNode) valueMetricNode); } else { valueMetricsOnly.add(valueMetricNode); } } boolean rc; rc = ipcGetRefMetricTreeValues(dbevindex, selectableMetrics, valueMetricsOnly); return rc; } private static boolean ipcGetRefMetricTreeValues( int dbevindex, List metlist, List nonmetlist) { if (metlist.isEmpty() && nonmetlist.isEmpty()) { return false; } String mcmds[] = new String[metlist.size()]; int ii = 0; for (SelectableMetricNode item : metlist) { String mcmd = item.getMetricBasic().getName(); mcmds[ii++] = mcmd; } String nmcmds[] = new String[nonmetlist.size()]; ii = 0; for (ValueMetricNode item : nonmetlist) { String mcmd = item.getMetricBasic().getName(); nmcmds[ii++] = mcmd; } IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getRefMetricTreeValues"); // New ipc request! ipcHandle.append(dbevindex); ipcHandle.append(mcmds); ipcHandle.append(nmcmds); IPCResult ipcResult = ipcHandle.sendRequest(); if (ipcResult.getCC() == IPCResult.CC.SUCCESS) { // blocking // Things are fine Object[] data = (Object[]) ipcResult.getObject(); return parseRefMetricValuesIpcData(data, metlist, nonmetlist); } else { int i = 0; // for breakpoint // error handling } return true; // YXXX not sure the meaning of this } private static boolean parseRefMetricValuesIpcData( final Object[] rawData, List metlist, List nonmetlist) { int nc = metlist.size() + nonmetlist.size(); // num columns (one for each value) Object[] valueColumns = (Object[]) rawData[0]; Object[] highlightColumns = (Object[]) rawData[1]; if (nc != valueColumns.length || nc != highlightColumns.length) { return true; // YXXX weird, broken } int metIndex = 0; int nonMetIndex = 0; for (int i = 0; i < nc; i++) { ValueMetricNode node; ArrayList mvlist = new ArrayList(); String label; if (i < metlist.size()) { node = metlist.get(metIndex++); label = node.getMetricBasic().getDisplayName(); } else { node = nonmetlist.get(nonMetIndex++); label = node.getMetricBasic().getDisplayName(); } String unit = null; if (node instanceof SelectableMetricNode) { MetricOption excl = ((SelectableMetricNode) node).getExclusive(); if (excl.getCapable().isTime()) { unit = AnLocale.getString("Seconds"); } } else if (node instanceof ValueMetricNode) { String vmunit = ((ValueMetricNode) node).getUnit(); if (vmunit != null && vmunit.compareTo("SECONDS") == 0) { unit = AnLocale.getString("Seconds"); } } if (valueColumns[i] instanceof double[]) { double[] dd = (double[]) valueColumns[i]; for (int jj = 0; jj < dd.length; jj++) { mvlist.add(new MetricValue(label, dd[jj], MetricValue.ValueType.DOUBLE, unit)); } } else if (valueColumns[i] instanceof int[]) { int[] ii = (int[]) valueColumns[i]; for (int jj = 0; jj < ii.length; jj++) { mvlist.add(new MetricValue(label, ii[jj], MetricValue.ValueType.LONG, unit)); } } else if (valueColumns[i] instanceof long[]) { long[] ii = (long[]) valueColumns[i]; for (int jj = 0; jj < ii.length; jj++) { mvlist.add(new MetricValue(label, ii[jj], MetricValue.ValueType.LONG, unit)); } // May need to handle AnAddress here } else if (valueColumns[i] instanceof String[]) { String[] ii = (String[]) valueColumns[i]; for (int jj = 0; jj < ii.length; jj++) { mvlist.add(new MetricValue(ii[jj], MetricValue.ValueType.LABEL_ONLY)); } } else { int jj = 0; // happens if there are no experiments loaded } for (int jj = 0; jj < mvlist.size(); jj++) { boolean[] highlights = (boolean[]) highlightColumns[i]; MetricValue mv = mvlist.get(jj); boolean highlight = highlights[jj]; mv.setHighlight(highlight); } node.setValues(mvlist); } return false; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/MetricValue.java0000644000175000017500000001652114517772113020473 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import java.util.Formatter; public class MetricValue { public static final int PERCENT_NAN = Integer.MAX_VALUE; public enum ValueType { LONG, DOUBLE, LABEL_ONLY /* no value or unit */ }; private String label; // "I/O Bytes" private double dValue; // 12.345 private long lValue; // 12345 private final ValueType valueType; // LONG/DOUBLE private final String unit; // "MB" private boolean highlight; // Metric value is "hot" public MetricValue(String label, long lValue, ValueType valueType, String unit) { this.label = label; this.lValue = lValue; this.dValue = 0; this.valueType = valueType; this.unit = unit; if (valueType != ValueType.LONG) { System.err.println("MetricValue error: value doesn't match value type!"); } highlight = false; } public MetricValue(String label, double dValue, ValueType valueType, String unit) { this.label = label; this.lValue = 0; this.dValue = dValue; this.valueType = valueType; this.unit = unit; if (valueType != ValueType.DOUBLE) { System.err.println("MetricValue error: value doesn't match value type!"); } highlight = false; } public MetricValue(String label, ValueType valueType) { this.label = label; this.lValue = 0; this.dValue = 0; this.valueType = valueType; this.unit = null; if (valueType != ValueType.LABEL_ONLY) { System.err.println("MetricValue error: value doesn't match value type!"); } highlight = false; } public void setHighlight(boolean highlight) { this.highlight = highlight; } public boolean getHighlight() { return highlight; } public String getLabel() { return label; } public double getDValue() { return dValue; } public void setDValue(double value) { this.dValue = value; // Reformat label, if necessary // Hack. See 18378636 - Overview is insufficient to pick metrics for er_kernel experiments if (valueType == ValueType.LABEL_ONLY) { String valueString = new Formatter().format("%.3f", getDValue()).toString(); if (label != null && !label.startsWith(valueString)) { int spaceIndex = label.lastIndexOf(' '); if (spaceIndex > 0) { label = valueString + label.substring(spaceIndex); } } } } public long getLValue() { return lValue; } public void setLValue(long lValue) { this.lValue = lValue; } public ValueType getValueType() { return valueType; } public String getUnit() { return unit; } public String formatValue() { String value = ""; if (null != getValueType()) { switch (getValueType()) { case LONG: value = "" + getLValue(); break; case DOUBLE: value = new Formatter().format("%.3f", getDValue()).toString(); break; case LABEL_ONLY: value = ""; // nothing to add break; default: value = ""; assert false; // should not happen break; } } return value; } public String formatValueUnit() { String valueUnit = formatValue(); if (getUnit() != null) { valueUnit += " " + getUnit(); } return valueUnit; } public boolean gtZero() { if (null != getValueType()) { switch (getValueType()) { case DOUBLE: return getDValue() > 0; case LONG: return getLValue() > 0; case LABEL_ONLY: return false; default: System.err.println("MetricValue:percentOf() not handling type " + getValueType()); assert false; break; } } return false; } public boolean ltZero() { if (null != getValueType()) { switch (getValueType()) { case DOUBLE: return getDValue() < 0; case LONG: return getLValue() < 0; case LABEL_ONLY: return false; default: System.err.println("MetricValue:percentOf() not handling type " + getValueType()); assert false; break; } } return false; } public void subtract(MetricValue opNode) { if (null != getValueType()) { switch (getValueType()) { case DOUBLE: dValue -= opNode.getDValue(); break; case LONG: lValue -= opNode.getLValue(); break; case LABEL_ONLY: break; default: System.err.println("MetricValue:percentOf() not handling type " + getValueType()); assert false; break; } } } public int percentOf(MetricValue totalValueNode) { int percent = 0; if (null != getValueType()) { switch (getValueType()) { case DOUBLE: { double totalValue = totalValueNode.getDValue(); double childValue = getDValue(); if (totalValue == 0) { if (childValue == 0) { percent = 0; } else { percent = PERCENT_NAN; } } else { percent = (int) ((childValue * 100) / totalValue + 0.5f); // YXXX Thomas, comment on why add 0.5 to a double? } break; } case LONG: { long totalValue = totalValueNode.getLValue(); long childValue = getLValue(); if (totalValue == 0) { if (childValue == 0) { percent = 0; } else { percent = PERCENT_NAN; } } else { percent = (int) ((childValue * 100) / totalValue + 0.5f); // YXXX don't you want to convert to double before division? } break; } case LABEL_ONLY: percent = PERCENT_NAN; break; default: System.err.println("MetricValue:percentOf() not handling type " + getValueType()); assert false; break; } } return percent; } public MetricValue clone() { MetricValue clone = null; if (null != getValueType()) { switch (getValueType()) { case DOUBLE: clone = new MetricValue(getLabel(), getDValue(), getValueType(), getUnit()); break; case LONG: clone = new MetricValue(getLabel(), getLValue(), getValueType(), getUnit()); break; case LABEL_ONLY: clone = new MetricValue(getLabel(), getValueType()); break; default: System.err.println("MetricValue:clone() error"); assert false; break; } } return clone; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/SelectableMetricNode.java0000644000175000017500000001503014517772113022262 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import org.gprofng.mpmt.AnWindow; import java.util.ArrayList; import java.util.List; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class SelectableMetricNode extends ValueMetricNode { private final MetricOption exclusive; // presentation's exclusive checkboxes private final MetricOption inclusive; // presentation's inclusive checkboxes private final int valueType; // YXXX placeholder. For now, AnVariable.VT_INT, etc. private List changeListeners = new ArrayList(); public SelectableMetricNode( BasicMetric metricBasic, MetricType metricsGroupType, MetricOption exclusive, MetricOption inclusive, int valueType) { super(metricBasic, metricsGroupType); this.exclusive = exclusive; this.inclusive = inclusive; this.valueType = valueType; } /** * @return the exclusive */ public MetricOption getExclusive() { return exclusive; } /** * @return the inclusive */ public MetricOption getInclusive() { return inclusive; } /** * @return the hasSelections */ @Override public boolean hasSelections() { boolean exclIsSelected = exclusive != null ? exclusive.hasSelections() : false; boolean inclIsSelected = inclusive != null ? inclusive.hasSelections() : false; return exclIsSelected || inclIsSelected; } /** * @return true if selected */ @Override public boolean isSelected() { boolean selected = AnWindow.getInstance() .getSettings() .getMetricsSetting() .isSelected(getMetricBasic().getName()); return selected; } public int getValueType() { return valueType; } private boolean[] internalSetSelected(boolean detailsCheckBox, boolean forceDefaults) { // System.out.println("setSelected:" + selected + " " + apply + " " + detailsCheckBox); // dumpAttr(this); // AnWindow anWindow = AnWindow.getInstance(); boolean eT = exclusive.getCapable().isTime() && exclusive.getSelected().isTime(); boolean eV = exclusive.getCapable().isValue() && exclusive.getSelected().isValue(); boolean eP = exclusive.getCapable().isPercent() && exclusive.getSelected().isPercent(); boolean iT = inclusive.getCapable().isTime() && inclusive.getSelected().isTime(); boolean iV = inclusive.getCapable().isValue() && inclusive.getSelected().isValue(); boolean iP = inclusive.getCapable().isPercent() && inclusive.getSelected().isPercent(); if (!detailsCheckBox) { if (forceDefaults || !(eT || eV || eP || iT || iV || iP)) { // nothing selected, fall back to saved defaults eT = exclusive.getCapable().isTime() && exclusive.getDefaultAttrs().isTime(); eV = exclusive.getCapable().isValue() && exclusive.getDefaultAttrs().isValue(); eP = exclusive.getCapable().isPercent() && exclusive.getDefaultAttrs().isPercent(); iT = inclusive.getCapable().isTime() && inclusive.getDefaultAttrs().isTime(); iV = inclusive.getCapable().isValue() && inclusive.getDefaultAttrs().isValue(); iP = inclusive.getCapable().isPercent() && inclusive.getDefaultAttrs().isPercent(); } if (!(eT || eV || eP || iT || iV || iP)) { // still nothing, select something using heuristics eT = exclusive.getCapable().isTime(); if (!eT) { eV = exclusive.getCapable().isValue(); } if (!eT && !eV) { eP = exclusive.getCapable().isPercent(); } // iT = inclusive.getCapable().isTime(); // if (!iT) { // iV = inclusive.getCapable().isValue(); // } } } // Save the changes exclusive.getSelected().setAttrs(false, eT, eV, eP); inclusive.getSelected().setAttrs(false, iT, iV, iP); boolean[] exclusiveIncluseValues = new boolean[] {eT, eV, eP, iT, iV, iP}; return exclusiveIncluseValues; } public boolean[] setSelected(boolean selected, boolean detailsCheckBox) { return internalSetSelected(detailsCheckBox, false); } public boolean[] setDefaults() { return internalSetSelected(false, true); } public void addChangeListener(ChangeListener changeListener) { changeListeners.add(changeListener); } public void removeChangeListener(ChangeListener changeListener) { changeListeners.remove(changeListener); } public void fireChange() { for (ChangeListener changeListener : changeListeners) { ChangeEvent changeEvent = new ChangeEvent(this); changeListener.stateChanged(changeEvent); } } private static void dumpAttr(SelectableMetricNode selectableMetricNode) { System.err.println( selectableMetricNode.getMetricBasic().getDisplayName() + " - " + selectableMetricNode.getMetricBasic().getDisplayName()); System.err.println(" Exclusive Inclusive"); System.err.println(" Time Value % Time Value % "); dumpAttr( "Sel", selectableMetricNode.getExclusive().getSelected(), selectableMetricNode.getInclusive().getSelected()); dumpAttr( "Cap", selectableMetricNode.getExclusive().getCapable(), selectableMetricNode.getInclusive().getCapable()); } private static void dumpAttr(String what, MetricAttr exEtricAttr, MetricAttr inEtricAttr) { System.err.print(what); System.err.print(" " + dumpAttr(exEtricAttr.isTime())); System.err.print(" " + dumpAttr(exEtricAttr.isValue())); System.err.print(" " + dumpAttr(exEtricAttr.isPercent())); System.err.print(" "); System.err.print(" " + dumpAttr(inEtricAttr.isTime())); System.err.print(" " + dumpAttr(inEtricAttr.isValue())); System.err.print(" " + dumpAttr(inEtricAttr.isPercent())); System.err.println(); } private static String dumpAttr(boolean b) { return b ? "x" : " "; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/ValueMetricNode.java0000644000175000017500000000372014517772113021276 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import java.util.ArrayList; import java.util.List; public class ValueMetricNode extends MetricNode { private List values; private String unit; private String unit_uname; public ValueMetricNode( BasicMetric metricBasic, MetricType metricsGroupType, String unit, String unit_uname) { super(metricBasic, metricsGroupType); this.values = new ArrayList(); this.unit = unit; this.unit_uname = unit_uname; } public ValueMetricNode(BasicMetric metricBasic, MetricType metricsGroupType) { super(metricBasic, metricsGroupType); this.values = new ArrayList(); this.unit = null; this.unit_uname = null; } public String getUnit() { return unit; } public String getUnitUname() { return unit_uname; } /** * @return the value */ public MetricValue getValue(int no) { if (no < values.size()) { return values.get(no); } else { return null; } } /** * @return whether it has the value set */ public boolean hasValues() { return !values.isEmpty(); } /** * @return the value */ public List getValues() { return values; } /** * @param value the value to set */ public void setValues(List values) { this.values = values; } } gprofng-gui-1.0/org/gprofng/mpmt/metrics/CompareBarData.java0000644000175000017500000000236514517772113021061 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.metrics; import org.gprofng.mpmt.overview.Bar.ValueColor; import java.util.List; /** * @author tpreisle */ public class CompareBarData { private int percentOfTotal; // private List valueColors; public CompareBarData(int percent, List valueColors) { this.percentOfTotal = percent; this.valueColors = valueColors; } /** * @return the percent */ public int getPercentOfTotal() { return percentOfTotal; } /** * @return the valueColors */ public List getValueColors() { return valueColors; } } gprofng-gui-1.0/org/gprofng/mpmt/DisassemblyView.java0000644000175000017500000001113614517772113017714 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.settings.AnSettingChangeEvent; public final class DisassemblyView extends AnCompDisp implements AnChangeListener { public DisassemblyView() { super(AnWindow.getInstance(), AnDisplay.DSP_Disassembly, AnVariable.HELP_TabsDisassembly); setAccessibility(AnLocale.getString("Disassembly")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("DisassemblyView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: setComputed(false); clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: addExperiment(); if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: if (selected) { filterChanged(); } setComputed(false); if (selected) { computeOnAWorkerThread(); } break; case SOURCE_FINDING_CHANGING: setComputed(false); if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.SRC_DIS || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.SEARCH_PATH || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.PATH_MAP || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { setComputed(false); if (oneDispPanel != null) { oneDispPanel.forceCompute = true; // ?????? } if (selected) { computeOnAWorkerThread(); } } break; case SELECTED_OBJECT_CHANGED: if (selected) { computeOnAWorkerThread(); } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void setComputed(boolean set) { super.setComputed(set); AnWindow.getInstance().getCalledByCallsDisassemblyView().setComputed(set); } @Override protected void setAvailable(boolean set) { super.setAvailable(set); AnWindow.getInstance().getCalledByCallsDisassemblyView().setAvailable(set); } } gprofng-gui-1.0/org/gprofng/mpmt/export/0000755000175000017500000000000014517775727015354 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/export/ExportPanel.form0000644000175000017500000003100214517772113020400 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/export/ExportDialog.java0000644000175000017500000000370714517772113020531 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.export; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.util.gui.AnDialog2; import java.awt.Frame; public class ExportDialog extends AnDialog2 { private final ExportPanel exportPanel; public ExportDialog(Frame owner, ExportSupport exportSupport) { super(owner, owner, AnLocale.getString("Export")); exportPanel = new ExportPanel(this, exportSupport); setCustomPanel(exportPanel); setHelpTag(AnVariable.HELP_Export); getOKButton().setText(AnLocale.getString("Export")); // getOKButton().setMnemonic(AnLocale.getString('E', "EXPORT_DIALOG_SAVE_MN")); ); getOKButton().setToolTipText(AnLocale.getString("Save the file")); } public String getOutputFilePath() { return exportPanel.getOutputFilePath(); } public ExportSupport.ExportFormat getExportFormat() { return exportPanel.getExportFormat(); } public Character getDelimiter() { return exportPanel.getDelimiter(); } public Integer getLimit() { return exportPanel.getLimit(); } public Boolean getIncludeSubviews() { return exportPanel.getIncludeSubviews(); } @Override protected void setStatus(Status status) { super.setStatus(status); if (status == Status.OK) { exportPanel.saveStates(); } } } gprofng-gui-1.0/org/gprofng/mpmt/export/Export.java0000644000175000017500000001351514517772113017407 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.export; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.export.ExportSupport.ExportFormat; import java.awt.Component; import java.awt.image.BufferedImage; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import javax.imageio.ImageIO; public class Export { public static void exportText(String text, String outputFilePath) { printTextToFile(text, outputFilePath); } public static void exportImage(Component component, String outputFilePath) { printImageToFile(component, outputFilePath); } // ---------------------------------------------------------------------------------------------------- // private static AnWindow getAnWindow() { // return (AnWindow) Analyzer.getInstance().win_list.get(0); // } // Print display private static void printTextToFile(String textImage, String file) { if (file == null || file.equals("")) { // Print to standard output System.out.println(textImage); } else { File of = null; try { of = new File(file); // Write to temp file BufferedWriter bw = new BufferedWriter(new FileWriter(of)); bw.write(textImage); bw.close(); } catch (IOException e) { String s = "analyzer: error: cannot write to file " + of.getAbsolutePath(); // FIXUP } } } private static String printImageToFile(Component display, String file) { String s = null; if (display == null) { return null; } if (file != null) { if (file.equals("")) { s = "Please, specify file name (recommended suffix .jpg)"; return s; } else { File of = null; try { of = new File(file); // Capture image to output file captureComponentToJpeg(display, of); } catch (IOException e) { s = "analyzer: error: cannot write to file " + of.getAbsolutePath(); return s; } } } return null; } private static void captureComponentToJpeg(Component c, File destFile) throws IOException { BufferedImage image = new BufferedImage(c.getWidth(), c.getHeight(), BufferedImage.TYPE_INT_RGB); c.paint(image.createGraphics()); ImageIO.write(image, "JPEG", destFile); } private static ExportFormat getFormat() { ExportFormat format = null; int printMode = getPrintMode(); if (printMode == 0) { format = ExportFormat.TEXT; } else if (printMode == 1) { format = ExportFormat.HTML; } else if (printMode == 2) { format = ExportFormat.CSV; } else { assert true; } return format; } public static void setFormat(ExportFormat format, Character delimiter) { String printMode = null; if (format == ExportFormat.TEXT) { printMode = "text"; } else if (format == ExportFormat.HTML) { printMode = "html"; } else if (format == ExportFormat.CSV) { printMode = "" + delimiter; } else { assert true; } setPrintMode(printMode); } private static Integer getLimit() { Integer limit = null; int lim = getPrintLimit(); if (lim != 0) { limit = lim; } return limit; } public static void setLimit(Integer limit) { int lim = 0; if (limit != null) { lim = limit.intValue(); } setPrintLimit(lim); } private String getDelimiter() { return getPrintDelim(); } public static String printData( final int type, final int subtype, final String printer, final String file) { AnWindow window = AnWindow.getInstance(); synchronized (IPC.lock) { window.IPC().send("printData"); window.IPC().send(0); window.IPC().send(type); window.IPC().send(subtype); window.IPC().send(printer); window.IPC().send(file); return window.IPC().recvString(); } } private static int getPrintLimit() { AnWindow window = AnWindow.getInstance(); synchronized (IPC.lock) { window.IPC().send("getPrintLimit"); window.IPC().send(0); return window.IPC().recvInt(); } } private static String setPrintLimit(int limit) { AnWindow window = AnWindow.getInstance(); synchronized (IPC.lock) { window.IPC().send("setPrintLimit"); window.IPC().send(0); window.IPC().send(limit); return (String) window.IPC().recvString(); } } private static String setPrintMode(final String m) { AnWindow window = AnWindow.getInstance(); synchronized (IPC.lock) { window.IPC().send("setPrintMode"); window.IPC().send(0); window.IPC().send(m); return window.IPC().recvString(); } } private static int getPrintMode() { AnWindow window = AnWindow.getInstance(); synchronized (IPC.lock) { window.IPC().send("getPrintMode"); window.IPC().send(0); return window.IPC().recvInt(); } } private static String getPrintDelim() { AnWindow window = AnWindow.getInstance(); synchronized (IPC.lock) { window.IPC().send("getPrintDelim"); window.IPC().send(0); String s = window.IPC().recvString(); if (s == null) { return ","; } return s; } } } gprofng-gui-1.0/org/gprofng/mpmt/export/ExportPanel.java0000644000175000017500000005373614517772113020400 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.export; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.export.ExportSupport.ExportFormat; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.List; import javax.swing.JFileChooser; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; /** * @author tpreisle */ public class ExportPanel extends javax.swing.JPanel { private static final Color errorColor = Color.red; private static final Color warningColor = new Color(255, 150, 0); private ExportDialog exportDialog; private JFileChooser fileChooser; private ExportSupport exportSupport; private static Integer limitSaved = null; private static ExportFormat formatSaved = null; private static File directorySaved = null; private static String fileNameSaved = "output"; private static Character delimiterSaved = ','; private static Boolean includeSubviews = false; /** Creates new form ExportPanel */ public ExportPanel(ExportDialog exportDialog, ExportSupport exportSupport) { setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); this.exportDialog = exportDialog; this.exportSupport = exportSupport; List formats = exportSupport.getSupportedExportFormats(); initComponents(); infoScrollPane.setBorder(null); // infoTextArea.setOpaque(false); infoTextArea.setEditable(false); infoTextArea.setRows(1); infoTextArea.setWrapStyleWord(true); infoTextArea.setLineWrap(true); infoTextArea.setText( AnLocale.getString( "Save the data shown in the current view to a file of the specified format.")); infoTextArea.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); AnUtility.setAccessibleContext( infoTextArea.getAccessibleContext(), AnLocale.getString("Info area")); // fileBrowseButton.setIcon(AnUtility.brws_icon); // fileBrowseButton.setToolTipText(AnLocale.getString("Browse for file")); // ToolBarButton.setBehaviour(fileBrowseButton); // errorLabel.setFont(exportDialog.getDialogFont()); // fileBrowseButton.setFont(exportDialog.getDialogFont()); // dirLabel.setFont(exportDialog.getDialogFont()); // dirTextFeild.setFont(exportDialog.getDialogFont()); // formatComboBox.setFont(exportDialog.getDialogFont()); // delimiterLabel.setFont(exportDialog.getDialogFont()); // delimiterTextField.setFont(exportDialog.getDialogFont()); // formatLabel.setFont(exportDialog.getDialogFont()); // limitLabel.setFont(exportDialog.getDialogFont()); // limitTextField.setFont(exportDialog.getDialogFont()); // pathLabelExt.setFont(exportDialog.getDialogFont()); pathLabelExt.setForeground(new Color(150, 150, 150)); nameLabel.setText(AnLocale.getString("File Name:")); String outputFileTT = AnLocale.getString("Name of output file"); nameLabel.setToolTipText(outputFileTT); nameTextField.setToolTipText(outputFileTT); nameLabel.setDisplayedMnemonic(AnLocale.getString('F', "ExportFileNameLabelMnemonic")); nameLabel.setLabelFor(nameTextField); nameTextField.setToolTipText(outputFileTT); dirLabel.setText(AnLocale.getString("Directory:")); dirLabel.setDisplayedMnemonic(AnLocale.getString('D', "ExportDirectoryLabelMemonic")); dirLabel.setLabelFor(dirTextField); String dirTT = AnLocale.getString("Directory where to store output file"); dirLabel.setToolTipText(dirTT); dirTextField.setToolTipText(dirTT); dirBrowseButton.setToolTipText(AnLocale.getString("Browse for Directory (ALT B)")); dirBrowseButton.setMnemonic(AnLocale.getString('B', "ExportBrowseButtonMnemonic")); formatLabel.setText(AnLocale.getString("Export as:")); formatLabel.setDisplayedMnemonic(AnLocale.getString('X', "ExportFormatLabelMnemonic")); formatLabel.setLabelFor(formatComboBox); String formatTT = AnLocale.getString("Format of the exported data or image"); formatLabel.setToolTipText(formatTT); formatComboBox.setToolTipText(formatTT); subviewsCheckBox.setText(AnLocale.getString("Include subviews")); subviewsCheckBox.setMnemonic(AnLocale.getString('I', "ExportIncludeSubviewsMnemonic")); subviewsCheckBox.setSelected(includeSubviews); limitLabel.setText(AnLocale.getString("Maximum:")); String limitTT = AnLocale.getString("Number of lines to export beginning from the top of the data display"); limitLabel.setToolTipText(limitTT); limitTextField.setToolTipText(limitTT); formatComboBox.removeAllItems(); for (ExportFormat format : formats) { formatComboBox.addItem(format); } delimiterLabel.setText(AnLocale.getString("Delimiter:")); String delimiterTT = AnLocale.getString("Character used to separate values"); delimiterLabel.setToolTipText(delimiterTT); delimiterTextField.setToolTipText(delimiterTT); delimiterTextField.setHorizontalAlignment(JTextField.CENTER); if (delimiterSaved != null) { delimiterTextField.setText("" + delimiterSaved); } else { delimiterTextField.setText("" + ','); } // Restore saved states if (limitSaved == null) { limitTextField.setText(""); } else { limitTextField.setText("" + limitSaved.intValue()); } if (formatSaved != null) { for (int i = 0; i < formatComboBox.getItemCount(); i++) { if (formatComboBox.getItemAt(i) == formatSaved) { formatComboBox.setSelectedIndex(i); break; } } } if (directorySaved == null) { directorySaved = new File(Analyzer.getInstance().getWorkingDirectory()); } dirTextField.setText(directorySaved.getAbsolutePath()); String defaultName = fileNameSaved; nameTextField.setText(defaultName); if (getFilePathWithExtension().exists()) { for (int i = 1; i < 999; i++) { nameTextField.setText(defaultName + "_" + i); if (!getFilePathWithExtension().exists()) { break; } } } validateInput(); nameTextField.getDocument().addDocumentListener(new DocListener()); dirTextField.getDocument().addDocumentListener(new DocListener()); delimiterTextField.getDocument().addDocumentListener(new DocListener()); limitTextField.getDocument().addDocumentListener(new DocListener()); dirBrowseButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { browse(); } }); formatComboBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { validateInput(); } }); } class DocListener implements DocumentListener { @Override public void changedUpdate(DocumentEvent e) { validateInput(); } @Override public void insertUpdate(DocumentEvent e) { validateInput(); } @Override public void removeUpdate(DocumentEvent e) { validateInput(); } } private void browse() { fileChooser = new JFileChooser(); File fp = getFilePathWithExtension(); fileChooser.setCurrentDirectory(fp.getParentFile()); fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { File selFile = fileChooser.getSelectedFile(); if (selFile.isDirectory()) { dirTextField.setText(selFile.getAbsolutePath()); } else { nameTextField.setText(selFile.getName()); dirTextField.setText(selFile.getParentFile().getAbsolutePath()); } } validateInput(); } private File getFilePathWithExtension() { String fileName = nameTextField.getText(); String dirName = dirTextField.getText(); String filePath = dirName + "/" + fileName; String ext = null; String newExt = null; int i = fileName.lastIndexOf('.'); if (i >= 0 && i < (fileName.length() - 1)) { ext = fileName.substring(i + 1); } if (ext == null || ext.length() == 0) { ExportFormat format = (ExportFormat) formatComboBox.getSelectedItem(); if (format == ExportFormat.CSV) { newExt = "csv"; } else if (format == ExportFormat.HTML) { newExt = "html"; } else if (format == ExportFormat.JPG) { newExt = "jpg"; } else if (format == ExportFormat.TEXT) { newExt = "txt"; } else { assert true; } } if (ext != null && ext.length() > 0) { // } else if (filePath.endsWith(".")) { filePath = filePath + newExt; } else { filePath = filePath + "." + newExt; } return new File(filePath); } public Character getDelimiter() { Character delim = ','; String delimText = delimiterTextField.getText(); if (delimText.length() == 1) { delim = delimText.charAt(0); } if (delimText.length() >= 2) { delim = null; } return delim; } private Integer getLineLimit() throws NumberFormatException { String limit = limitTextField.getText(); if (limit.length() == 0) { return null; } return new Integer(limit).intValue(); } private void validateInput() { ExportFormat format = (ExportFormat) formatComboBox.getSelectedItem(); List subviews = AnWindow.getInstance().getViews().getCurrentViewDisplay().getVisibleSubviews(); if (format == ExportFormat.JPG && subviews.size() > 0) { subviewsCheckBox.setVisible(true); } else { subviewsCheckBox.setVisible(false); } if (format == ExportFormat.JPG || !exportSupport.exportLimitSupported()) { if (limitLabel.isVisible()) { limitLabel.setVisible(false); limitTextField.setVisible(false); } } else { if (!limitLabel.isVisible()) { limitLabel.setVisible(true); limitTextField.setVisible(true); } } if (format == ExportFormat.CSV) { if (!delimiterLabel.isVisible()) { delimiterLabel.setVisible(true); delimiterTextField.setVisible(true); } } else { if (delimiterLabel.isVisible()) { delimiterLabel.setVisible(false); delimiterTextField.setVisible(false); } } AnUtility.setTextAndAccessibleContext(pathLabelExt, AnLocale.getString("Path used: ")); errorLabel.setText(" "); exportDialog.getOKButton().setEnabled(true); String outputFileName = nameTextField.getText(); if (outputFileName.length() == 0) { updateError(AnLocale.getString("File name missing")); return; } File fullPathFile = getFilePathWithExtension(); if (fullPathFile.exists() && fullPathFile.isDirectory()) { updateError(AnLocale.getString("File name missing")); return; } File outputFileParent = fullPathFile.getParentFile(); if (outputFileParent != null && !outputFileParent.exists()) { updateError(AnLocale.getString("Folder doesn't exist")); return; } pathLabelExt.setText(AnLocale.getString("Path used: ") + fullPathFile.getAbsolutePath()); if (fullPathFile.exists()) { updateWarning(AnLocale.getString("File name already exists")); } if (format == ExportFormat.CSV) { Character delim = getDelimiter(); if (delim == null) { updateError("Invalid delimiter character"); return; } } exportDialog.pack(); Integer limit = null; if (limitTextField.isVisible()) { try { limit = getLineLimit(); } catch (NumberFormatException nfe) { updateError(AnLocale.getString("Max Lines is not a valid number")); return; } } if (limit != null && limit <= 0) { updateError(AnLocale.getString("Max Lines should be empty or greater than 0")); return; } } private void updateWarning(String warningText) { errorLabel.setForeground(warningColor); errorLabel.setText(AnLocale.getString("Warning: ") + warningText); } private void updateError(String errorText) { errorLabel.setForeground(errorColor); errorLabel.setText(AnLocale.getString("Error: ") + errorText); exportDialog.getOKButton().setEnabled(false); } public String getOutputFilePath() { return getFilePathWithExtension().getAbsolutePath(); } public ExportSupport.ExportFormat getExportFormat() { return (ExportFormat) formatComboBox.getSelectedItem(); } public Integer getLimit() { return getLineLimit(); } public Boolean getIncludeSubviews() { return subviewsCheckBox.isSelected(); } protected void saveStates() { ExportFormat format = (ExportFormat) formatComboBox.getSelectedItem(); formatSaved = getExportFormat(); if (format != ExportFormat.JPG) { limitSaved = getLimit(); } if (format == ExportFormat.JPG) { includeSubviews = getIncludeSubviews(); } File outputFile = getFilePathWithExtension(); directorySaved = outputFile.getParentFile(); fileNameSaved = nameTextField.getText(); fileNameSaved = fileNameSaved.replaceAll("\\..*$", ""); fileNameSaved = fileNameSaved.replaceAll("_\\d*$", ""); if (format == ExportFormat.CSV) { delimiterSaved = getDelimiter(); } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; infoScrollPane = new javax.swing.JScrollPane(); infoTextArea = new javax.swing.JTextArea(); nameLabel = new javax.swing.JLabel(); nameTextField = new javax.swing.JTextField(); dirLabel = new javax.swing.JLabel(); dirTextField = new javax.swing.JTextField(); dirBrowseButton = new javax.swing.JButton(); formatLabel = new javax.swing.JLabel(); formatComboBox = new javax.swing.JComboBox(); delimiterLabel = new javax.swing.JLabel(); delimiterTextField = new javax.swing.JTextField(); subviewsCheckBox = new javax.swing.JCheckBox(); limitLabel = new javax.swing.JLabel(); limitTextField = new javax.swing.JTextField(); errorLabel = new javax.swing.JLabel(); pathLabelExt = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); infoTextArea.setColumns(20); infoTextArea.setRows(5); infoScrollPane.setViewportView(infoTextArea); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; add(infoScrollPane, gridBagConstraints); nameLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0); add(nameLabel, gridBagConstraints); nameTextField.setColumns(20); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 4, 0, 0); add(nameTextField, gridBagConstraints); dirLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0); add(dirLabel, gridBagConstraints); dirTextField.setColumns(60); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(10, 4, 0, 0); add(dirTextField, gridBagConstraints); dirBrowseButton.setText("..."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 4, 0, 0); add(dirBrowseButton, gridBagConstraints); formatLabel.setText("jLabel2"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0); add(formatLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 4, 0, 0); add(formatComboBox, gridBagConstraints); delimiterLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 5; gridBagConstraints.insets = new java.awt.Insets(10, 8, 0, 0); add(delimiterLabel, gridBagConstraints); delimiterTextField.setColumns(2); delimiterTextField.setText(","); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 4, 0, 0); add(delimiterTextField, gridBagConstraints); subviewsCheckBox.setText("jCheckBox1"); subviewsCheckBox.setOpaque(false); subviewsCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { subviewsCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 5; gridBagConstraints.insets = new java.awt.Insets(10, 8, 0, 0); add(subviewsCheckBox, gridBagConstraints); limitLabel.setText("jLabel3"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 6; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0); add(limitLabel, gridBagConstraints); limitTextField.setColumns(10); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 6; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(10, 4, 0, 0); add(limitTextField, gridBagConstraints); errorLabel.setForeground(new java.awt.Color(255, 0, 51)); errorLabel.setText("error"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 7; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0); add(errorLabel, gridBagConstraints); pathLabelExt.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(pathLabelExt, gridBagConstraints); } // //GEN-END:initComponents private void subviewsCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_subviewsCheckBoxActionPerformed // TODO add your handling code here: } // GEN-LAST:event_subviewsCheckBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel delimiterLabel; private javax.swing.JTextField delimiterTextField; private javax.swing.JButton dirBrowseButton; private javax.swing.JLabel dirLabel; private javax.swing.JTextField dirTextField; private javax.swing.JLabel errorLabel; private javax.swing.JComboBox formatComboBox; private javax.swing.JLabel formatLabel; private javax.swing.JScrollPane infoScrollPane; private javax.swing.JTextArea infoTextArea; private javax.swing.JLabel limitLabel; private javax.swing.JTextField limitTextField; private javax.swing.JLabel nameLabel; private javax.swing.JTextField nameTextField; private javax.swing.JLabel pathLabelExt; private javax.swing.JCheckBox subviewsCheckBox; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/export/ExportSupport.java0000644000175000017500000000261414517772113021002 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.export; import java.util.List; public interface ExportSupport { public enum ExportFormat { TEXT("Text (.txt)"), HTML("HTML (.html)"), CSV("CSV (.csv)"), JPG("JPEG (.jpg)"); private String name; private ExportFormat(String name) { this.name = name; } @Override public String toString() { return name; } } /** * @return list of supported export formats */ public List getSupportedExportFormats(); /** * Whether or not if this view supports limit * * @return true if limit is supported */ public boolean exportLimitSupported(); public String exportAsText(Integer limit, ExportSupport.ExportFormat format, Character delimiter); } gprofng-gui-1.0/org/gprofng/mpmt/progress/0000755000175000017500000000000014517775727015677 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/progress/CancelContext.java0000644000175000017500000000216114517772113021176 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.progress; public class CancelContext { private String taskName; private Cancellable cancellable; public CancelContext(String taskName, Cancellable cancellable) { this.taskName = taskName; this.cancellable = cancellable; } /** * @return the cancellable */ public Cancellable getCancellable() { return cancellable; } /** * @return the taskName */ public String getTaskName() { return taskName; } } gprofng-gui-1.0/org/gprofng/mpmt/progress/SystemProgressPanel.java0000644000175000017500000001133114517772113022434 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.progress; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.util.gui.AnUtility; import java.util.Stack; public class SystemProgressPanel extends ProgressPanel { private ProgressHandle progressHandle; private class Task { private String name; public Task(String name) { this.name = name; } public String getName() { return name; } } private Stack progressBars = new Stack(); public SystemProgressPanel() { super(); progressHandle = createHandle(); } public void reset() { finishProgress(); setProgressCancelContext(null); progressBars = new Stack(); } public synchronized Object progressBarStart(String taskName) { // IPCContext.newCurrentContext("Unknown task...", IPCContext.Scope.SESSION, this); <=== // FIXUP: need real name of task like "Opening Experiment..." if (progressBars.empty()) { startProgress(); } progressHandle.progress(taskName); Task task = new Task(taskName); progressBars.push(task); // System.out.println("SystemProgresspanel start: " + progressBars.size() + " " + // progressBars.peek().getName()); return task; } public synchronized void progressBarStop(Object id) { if (progressBars.empty()) { AnLog.log( "error: SystemProgresspanel:progressBarStop: progressBars is empty!. See bug 19598982"); return; } boolean didIt = progressBars.remove(id); if (!didIt) { AnLog.log( "error: SystemProgresspanel:progressBarStop: can't find id " + ((Task) id).getName()); } if (progressBars.empty()) { finishProgress(); // <=== FIXUP: should be done in IPCResult setProgressCancelContext(null); // <=== FIXUP: should be done in IPCResult } else { String taskName = progressBars.peek().getName(); progressHandle.progress(taskName); } // System.out.println("SystemProgresspanel stop : " + progressBars.size() + " " + // (progressBars.size() > 0 ? progressBars.peek().getName() : "-")); } private void startProgress() { AnUtility.invokeLaterOnSwingThread( new Runnable() { @Override public void run() { startProgressImpl(); } }); } private void startProgressImpl() { if (progressHandle == null) { return; } progressHandle.switchToIndeterminate(); progressHandle.start(); } public CancelContext getProgressCancelContext() { if (progressHandle == null) { return null; } else { return progressHandle.getCancelContext(); } } public void setProgressCancelContext(final CancelContext cancelContex) { AnUtility.invokeLaterOnSwingThread( new Runnable() { @Override public void run() { setProgressCancelContextImpl(cancelContex); // / } }); } private void setProgressCancelContextImpl(CancelContext cancelContex) { if (progressHandle == null) { return; } progressHandle.setCancelContext(cancelContex); } public void setProgress(final int percentage, final String proc_str) { AnUtility.invokeLaterOnSwingThread( new Runnable() { @Override public void run() { setProgressImpl(percentage, proc_str); } }); } private void setProgressImpl(final int percentage, final String proc_str) { if (progressHandle == null) { return; } if (percentage > 0) { progressHandle.switchToDeterminate(100); progressHandle.progress(proc_str, percentage); } else { progressHandle.switchToIndeterminate(); if (proc_str != null && proc_str.length() > 0) { progressHandle.progress(proc_str); } } } private void finishProgress() { AnUtility.invokeLaterOnSwingThread( new Runnable() { @Override public void run() { finishProgressImpl(); } }); } private void finishProgressImpl() { if (progressHandle == null) { return; } progressHandle.finish(); } } gprofng-gui-1.0/org/gprofng/mpmt/progress/ProgressPanel.java0000644000175000017500000002204214517772113021230 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.progress; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.guitesting.GUITesting; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; public class ProgressPanel extends JPanel implements MouseListener { private Cursor currentCursor; private InternalHandle internalHandle; public ProgressPanel() { initComponents(); label.setFont(label.getFont().deriveFont(Font.PLAIN)); progressBar.setIndeterminate(true); progressBar.setFont( progressBar.getFont().deriveFont((float) progressBar.getFont().getSize() - 2)); Dimension dim; dim = progressBar.getPreferredSize(); dim.height = 14; progressBar.setPreferredSize(dim); dim = new Dimension(0, 22); verticalFiller.setPreferredSize(dim); label.addMouseListener(this); progressBar.addMouseListener(this); cancelButton.addMouseListener(this); cancelButton.setToolTipText(AnLocale.getString("Click to cancel task...")); // cancelButton.setEnabled(false); setOpaque(false); } /** * Create a progress ui handle for a long lasting task. * * @param allowToCancel either null, if the task cannot be cancelled or an instance of {@link * org.openide.util.Cancellable} that will be called when user triggers cancel of the task. * @param displayName to be shown in the progress UI * @return an instance of {@link org.netbeans.api.progress.ProgressHandle}, initialized but not * started. */ public ProgressHandle createHandle(CancelContext cancelContext) { return new ProgressHandle(internalHandle = new InternalHandle(this, cancelContext)); } public ProgressHandle createHandle() { return createHandle(null); } protected void progress(String message, int workunit) { String txt = message; if (txt != null) { int len = txt.length(); if (len > 0) { if (len > 45) { txt = txt.substring(0, 45) + "..."; } label.setText(txt); label.setToolTipText(message); progressBar.setToolTipText(message); } } if (workunit > 0) { progressBar.setValue(workunit); } } protected void toDeterminate(int workunits, int xxx) { progressBar.setIndeterminate(false); progressBar.setMinimum(0); progressBar.setMaximum(workunits); progressBar.setStringPainted(true); } protected void toIndeterminate() { progressBar.setIndeterminate(true); progressBar.setStringPainted(false); } @Override public void setVisible(boolean b) { if (GUITesting.getInstance().isRunningUnderGUITesting()) { super.setVisible(b); } else { label.setVisible(b); progressBar.setVisible(b); cancelButton.setVisible(b); } } @Override public void mouseEntered(MouseEvent e) { currentCursor = getCursor(); setCursor(Cursor.getDefaultCursor()); } @Override public void mouseExited(MouseEvent e) { setCursor(currentCursor); } @Override public void mouseReleased(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseClicked(MouseEvent e) {} /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; label = new javax.swing.JLabel(); progressBar = new javax.swing.JProgressBar(); cancelButton = new javax.swing.JButton(); verticalFiller = new javax.swing.Box.Filler( new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0)); setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; add(label, gridBagConstraints); progressBar.setPreferredSize(new java.awt.Dimension(70, 16)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.ipadx = 138; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(progressBar, gridBagConstraints); cancelButton.setIcon( new javax.swing.ImageIcon( getClass().getResource("/org/gprofng/mpmt/icons/cancelProcess.png"))); cancelButton.setBorderPainted(false); cancelButton.setContentAreaFilled(false); cancelButton.setMargin(new java.awt.Insets(0, 0, 0, 0)); cancelButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cancelButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); add(cancelButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 0; add(verticalFiller, gridBagConstraints); } // //GEN-END:initComponents private void cancelButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_cancelButtonActionPerformed final CancelContext cancelContext = internalHandle.getCancelContext(); if (cancelContext == null) { return; } String msg = cancelContext.getTaskName() + "\n" + AnLocale.getString("Are you sure you want to cancel this task?"); JOptionPane optionPane = new JOptionPane(msg, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION); optionPane.setFont(optionPane.getFont().deriveFont(Font.PLAIN)); JDialog dialog = optionPane.createDialog( AnWindow.getInstance().getFrame(), AnLocale.getString("Cancel Task")); disableYesButtonAndChangeFont(optionPane); // FIXUP: hack dialog.setVisible(true); Object selectedValue = optionPane.getValue(); if (selectedValue != null && selectedValue instanceof Integer) { int ret = ((Integer) selectedValue).intValue(); if (ret == JOptionPane.YES_OPTION) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { cancelContext.getCancellable().cancel(); } }, "CancelTaskThread"); } } } // GEN-LAST:event_cancelButtonActionPerformed private void disableYesButtonAndChangeFont(JComponent component) { for (Component comp : component.getComponents()) { if (comp instanceof JComponent) { JComponent childComp = (JComponent) comp; if (childComp instanceof JButton || childComp instanceof JLabel) { childComp.setFont(childComp.getFont().deriveFont(Font.PLAIN)); // if (childComp instanceof JButton) { // JButton button = (JButton)childComp; // if (button.getText().equals("Yes")) { // button.setEnabled(false); // FIXUP: remove to enable // cancelling of tasks..... // } // } } disableYesButtonAndChangeFont((JComponent) childComp); } } } protected void setCancelButtonEnabled(boolean enable) { cancelButton.setEnabled(enable); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton cancelButton; private javax.swing.JLabel label; private javax.swing.JProgressBar progressBar; private javax.swing.Box.Filler verticalFiller; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/progress/ProgressPanel.form0000644000175000017500000001220314517772113021250 00000000000000
gprofng-gui-1.0/org/gprofng/mpmt/progress/ProgressHandle.java0000644000175000017500000001114714517772113021370 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.progress; /** * Instances provided by the ProgressHandleFactory allow the users of the API to notify the progress * bar UI about changes in the state of the running task. Progress component will be visualized only * after one of the start() methods. */ public final class ProgressHandle { private InternalHandle internal; /** Creates a new instance of ProgressHandle */ ProgressHandle(InternalHandle internal) { this.internal = internal; } /** * start the progress indication for indeterminate task. it will be visualized by a progress bar * in indeterminate mode. start method can be called just once. */ public void start() { start(0, -1); } /** * start the progress indication for a task with known number of steps. start method * can be called just once. * * @param workunits total number of workunits that will be processed */ public void start(int workunits) { start(workunits, -1); } /** * start the progress indication for a task with known number of steps and known time estimate for * completing the task. start method can be called just once. * * @param workunits total number of workunits that will be processed * @param estimate estimated time to process the task in seconds */ public void start(int workunits, long estimate) { internal.start("", workunits, estimate); } /** * Currently determinate task (with percentage or time estimate) can be switched to indeterminate * mode. This method has to be called after calling start method and before calling * finish method (the task has to be running). */ public void switchToIndeterminate() { internal.toIndeterminate(); } /** * Currently indeterminate task can be switched to show percentage completed. This method has to * be called after calling start method and before calling finish method * (the task has to be running). A common usecase is to calculate the amount of work in the * beginning showing in indeterminate mode and later switch to the progress with known steps * * @param workunits a definite number of complete units of work out of the total */ public void switchToDeterminate(int workunits) { internal.toDeterminate(workunits, -1); } /** * Finish the task, remove the task's component from the progress bar UI. This method has to be * called after calling start method (the task has to be running). */ public void finish() { internal.finish(); } /** * Notify the user about completed workunits. This method has to be called after calling * start method and before calling finish method (the task has to be running). * * @param workunit a cumulative number of workunits completed so far */ public void progress(int workunit) { progress(null, workunit); } /** * Notify the user about progress by showing message with details. This method has to be called * after calling start method and before calling finish method (the task * has to be running). * * @param message details about the status of the task */ public void progress(String message) { progress(message, -1); } /** * Notify the user about completed workunits and show additional detailed message. This method has * to be called after calling start method and before calling finish * method (the task has to be running). * * @param message details about the status of the task * @param workunit a cumulative number of workunits completed so far */ public void progress(String message, int workunit) { internal.progress(message, workunit); } public void setCancelContext(CancelContext cancelContext) { internal.setCancelContext(cancelContext); } public CancelContext getCancelContext() { return internal.getCancelContext(); } } gprofng-gui-1.0/org/gprofng/mpmt/progress/Cancellable.java0000644000175000017500000000171114517772113020631 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.progress; public interface Cancellable { /** * Cancel processing of the job. Called not more then once for specific job. * * @return true if the job was succesfully cancelled, false if job can't be cancelled for some * reason */ public boolean cancel(); } gprofng-gui-1.0/org/gprofng/mpmt/progress/InternalHandle.java0000644000175000017500000000463514517772113021344 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.progress; import javax.swing.SwingUtilities; class InternalHandle { private ProgressPanel progressPanel; private CancelContext cancelContext; protected InternalHandle(ProgressPanel progressPanel, CancelContext cancelContext) { this.progressPanel = progressPanel; setCancelContext(cancelContext); } protected void progress(final String message, final int workunit) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { progressPanel.progress(message, workunit); } }); } protected void finish() { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { progressPanel.setVisible(false); } }); } protected void toDeterminate(final int workunits, final int xxx) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { progressPanel.toDeterminate(workunits, xxx); } }); } protected void toIndeterminate() { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { progressPanel.toIndeterminate(); } }); } protected void start(String message, int workunits, long estimate) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { progressPanel.setVisible(true); } }); } protected void setCancelContext(CancelContext cancelContext) { this.cancelContext = cancelContext; progressPanel.setCancelButtonEnabled(cancelContext != null); } protected CancelContext getCancelContext() { return cancelContext; } } gprofng-gui-1.0/org/gprofng/mpmt/ConfigurationPanel.java0000644000175000017500000004576714517772113020412 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Component; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JSeparator; import javax.swing.ListCellRenderer; import javax.swing.filechooser.FileFilter; /** * @author tpreisle */ public class ConfigurationPanel extends javax.swing.JPanel { private File expFile = null; /** Creates new form ExtraPanel */ public ConfigurationPanel(boolean includeWorkingDir) { initComponents(); useConfCheckBox.setText(AnLocale.getString("Use this Configuration")); useConfCheckBox.setToolTipText( AnLocale.getString( "If checked, the experiment will be opened using the specified Configuration")); useConfCheckBox.setMnemonic( AnLocale.getString('U', "OpenExperimentDialogUseThisConfigurationCheckBox")); AnUtility.setAccessibleContext( useConfCheckBox.getAccessibleContext(), AnLocale.getString("Use this Configuration")); confComboBox.setRenderer(new ComboBoxRenderer()); AnUtility.setAccessibleContext( confComboBox.getAccessibleContext(), AnLocale.getString("Use this Configuration")); confBrowseButton.setToolTipText(AnLocale.getString("Browse for Configuration File")); alwaysCheckBox.setText( AnLocale.getString("Always re-open this experiment with this Configuration")); alwaysCheckBox.setToolTipText( AnLocale.getString( "If checked, the experiment will be opened using this Configuration when re-opened")); alwaysCheckBox.setMnemonic(AnLocale.getString('A', "OpenExperimentDialogAlwaysReopenCheckBox")); AnUtility.setAccessibleContext( alwaysCheckBox.getAccessibleContext(), AnLocale.getString("Always re-open this experiment with this Configuration")); if (includeWorkingDir) { workingDirCheckBox.setText(AnLocale.getString("Change Working Directory")); workingDirCheckBox.setSelected(true); workingDirCheckBox.setMnemonic( AnLocale.getString('W', "OpenExperimentDialogChangeWorkingDirectoryCheckBox")); workingDirLabel.setText(AnLocale.getString("Directory:")); wdBrowseButton.setToolTipText(AnLocale.getString("Browse for Working Directory")); AnUtility.setAccessibleContext( workingDirCheckBox.getAccessibleContext(), AnLocale.getString("Change Working Directory")); AnUtility.setAccessibleContext( wdBrowseButton.getAccessibleContext(), AnLocale.getString("Browse for Working Directory")); AnUtility.setAccessibleContext( workingDirLabel.getAccessibleContext(), AnLocale.getString("Directory:")); AnUtility.setAccessibleContext( workingDirTextField.getAccessibleContext(), AnLocale.getString("Working Directory")); } else { workingDirCheckBox.setVisible(false); workingDirLabel.setVisible(false); workingDirTextField.setVisible(false); wdBrowseButton.setVisible(false); } updateStates(); } public class ComboBoxRenderer implements ListCellRenderer { private final ListCellRenderer originalRenderer; public ComboBoxRenderer() { originalRenderer = confComboBox.getRenderer(); } @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { Component component = originalRenderer.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus); if (addSeparator(index)) { JPanel panel = new JPanel(); panel.setLayout(new BorderLayout()); panel.add(new JSeparator(), BorderLayout.NORTH); panel.add(component, BorderLayout.CENTER); return panel; } else { return component; } } private boolean addSeparator(int index) { if (confComboBox.getItemCount() <= 1) { return false; } if (index < 1) { return false; } String previousPath = ((ConfName) confComboBox.getItemAt(index - 1)).getPath(); String previousDir = AnUtility.dirname(previousPath); String thisPath = ((ConfName) confComboBox.getItemAt(index)).getPath(); String thisDir = AnUtility.dirname(thisPath); return !previousDir.equals(thisDir); } } private void updateStates() { boolean UseOn = useConfCheckBox.isSelected(); confBrowseButton.setEnabled(UseOn); confComboBox.setEnabled(UseOn); alwaysCheckBox.setEnabled(UseOn); boolean wdOn = workingDirCheckBox.isSelected(); workingDirLabel.setEnabled(wdOn); workingDirTextField.setEnabled(wdOn); wdBrowseButton.setEnabled(wdOn); } public void initConfigurationChoices(File file) { this.expFile = file; List list = new ArrayList(); File confDir; // look inside experiment confDir = new AnFile(UserPref.getConfigurationDirPath(file.getAbsolutePath())); // Local or remote addConfigFile(confDir, list); // look in parent folder confDir = new AnFile(file.getParentFile().getAbsolutePath()); // Local or remote addConfigFile(confDir, list); // look in Home folder confDir = new File(UserPref.getHomeConfigurationDirPath()); // Always local addConfigFile(confDir, list); // Add As Last Time This Experiment Closed String asClosedPath = null; asClosedPath = UserPref.getAsWhenClosedConfigPath(file.getAbsolutePath()); if (asClosedPath != null && new File(asClosedPath).exists()) { list.add( new ConfName(asClosedPath, AnLocale.getString("As This Experiment Closed Last Time"))); } // Add As Current Experiment String[][] experimentsGroups = AnWindow.getInstance().getExperimentGroups(); if (experimentsGroups != null && experimentsGroups.length > 0) { String asPreviousClosedPath = UserPref.getAsWhenClosedConfigPath(experimentsGroups[0][0]); String previousDisplayName = AnLocale.getString("As Current Experiment"); list.add(new ConfName(asPreviousClosedPath, previousDisplayName)); } // Add As Previous Experiment Closed else if (UserPref.getInstance().getLastClosedExpConfPath() != null && UserPref.getInstance().getLastClosedExpConfPath().length() > 0) { String asPreviousClosedPath = UserPref.getInstance().getLastClosedExpConfPath(); String previousDisplayName = AnLocale.getString("As Previous Experiment Closed"); list.add(new ConfName(asPreviousClosedPath, previousDisplayName)); } confComboBox.removeAllItems(); for (ConfName confName : list) { confComboBox.addItem(confName); } useConfCheckBox.setSelected(false); if (confComboBox.getItemCount() == 0) { useConfCheckBox.setEnabled(false); } // Look for default boolean defaultFound = false; for (int i = 0; i < confComboBox.getItemCount(); i++) { ConfName confName = (ConfName) confComboBox.getItemAt(i); if (confName.isDefault()) { confComboBox.setSelectedItem(confName); useConfCheckBox.setSelected(true); defaultFound = true; break; } } if (!defaultFound) { // Look for As Last Experiment Closed for (int i = 0; i < confComboBox.getItemCount(); i++) { ConfName confName = (ConfName) confComboBox.getItemAt(i); if (confName.isAsLast()) { confComboBox.setSelectedItem(confName); // useConfCheckBox.setSelected(true); // Don't select it by default. // It's cpnfusing! break; } } } updateStates(); } private void addConfigFile(File dir, List list) { if (!dir.exists() || !dir.isDirectory()) { return; } File[] found = dir.listFiles(); if (found != null) { for (File f : found) { if (f.getName().endsWith(UserPref.configurationSuffix) && !f.getName().contains(UserPref.configAsWhenClosedName)) { list.add(new ConfName(f.getAbsolutePath(), null)); } } } } public void setWorkingDirectory(String wd) { workingDirTextField.setText(wd); workingDirTextField.setCaretPosition(wd.length()); } public String getWorkingDirectory() { String wd = null; if (workingDirCheckBox.isSelected()) { wd = workingDirTextField.getText(); if (wd.length() == 0) { wd = null; } } return wd; } public String getConfiguration() { String configuration = null; if (useConfCheckBox.isSelected()) { ConfName confName = (ConfName) confComboBox.getSelectedItem(); if (confName != null) { configuration = confName.getPath(); } } return configuration; } public boolean alwaysUseThisConfiguration() { boolean always = alwaysCheckBox.isSelected(); return always; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; useConfCheckBox = new javax.swing.JCheckBox(); confComboBox = new javax.swing.JComboBox(); confBrowseButton = new javax.swing.JButton(); alwaysCheckBox = new javax.swing.JCheckBox(); workingDirCheckBox = new javax.swing.JCheckBox(); workingDirLabel = new javax.swing.JLabel(); workingDirTextField = new javax.swing.JTextField(); wdBrowseButton = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); useConfCheckBox.setText("NOI18N"); useConfCheckBox.setOpaque(false); useConfCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { useConfCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; add(useConfCheckBox, gridBagConstraints); confComboBox.setEditable(true); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 21, 0, 0); add(confComboBox, gridBagConstraints); confBrowseButton.setText("..."); confBrowseButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { confBrowseButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(confBrowseButton, gridBagConstraints); alwaysCheckBox.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 18, 0, 0); add(alwaysCheckBox, gridBagConstraints); workingDirCheckBox.setText("NOI18N"); workingDirCheckBox.setOpaque(false); workingDirCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { workingDirCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(workingDirCheckBox, gridBagConstraints); workingDirLabel.setText("NOI18N"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 21, 0, 0); add(workingDirLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 5; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(workingDirTextField, gridBagConstraints); wdBrowseButton.setText("..."); wdBrowseButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { wdBrowseButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(wdBrowseButton, gridBagConstraints); } // //GEN-END:initComponents private void wdBrowseButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_wdBrowseButtonActionPerformed String currentWD = workingDirTextField.getText(); AnChooser chooser = AnWindow.getInstance() .getAnChooser( AnLocale.getString("Working Directory"), AnChooser.DIR_CHOOSER, currentWD); int res = chooser.showDialog(AnWindow.getInstance().getFrame(), null); if (res == AnChooser.APPROVE_OPTION) { File wdFile = chooser.getSelectedAnFile(); String wd = wdFile.getAbsolutePath(); workingDirTextField.setText(wd); } } // GEN-LAST:event_wdBrowseButtonActionPerformed private void workingDirCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_workingDirCheckBoxActionPerformed updateStates(); } // GEN-LAST:event_workingDirCheckBoxActionPerformed private void useConfCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_useConfCheckBoxActionPerformed updateStates(); } // GEN-LAST:event_useConfCheckBoxActionPerformed private void confBrowseButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_confBrowseButtonActionPerformed AnChooser chooser = AnWindow.getInstance() .getAnChooser( AnLocale.getString("Configurations"), AnChooser.DIR_FILE_CHOOSER, expFile.getParent()); // JFileChooser chooser = new JFileChooser(expFile.getParent()); chooser.setFileFilter(new ConfigFilter()); chooser.setFileHidingEnabled(false); // FIXUP: ???? int res = chooser.showDialog(AnWindow.getInstance().getFrame(), null); if (res == AnChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); String path = file.getAbsolutePath(); ConfName confName = new ConfName(path, null); confComboBox.addItem(confName); confComboBox.setSelectedItem(confName); } } // GEN-LAST:event_confBrowseButtonActionPerformed private class ConfigFilter extends FileFilter { @Override public String getDescription() { return UserPref.configurationSuffix; } @Override public boolean accept(File f) { boolean accept = f.isDirectory() || (f.getName().endsWith(UserPref.configurationSuffix) && !f.getName().startsWith(UserPref.getAsWhenClosedConfigName())); return accept; } } private class ConfName { private String path; private String displayName; private boolean isDefault; private boolean isAsLast; public ConfName(String path, String displayName) { this.path = path; isDefault = false; isAsLast = false; String baseName = AnUtility.basename(path); if (path.contains("/" + UserPref.configAsWhenClosedName + "/")) { isAsLast = true; } else { if (baseName.equals(UserPref.getDefaultConfigurationName())) { isDefault = true; } } if (displayName != null) { this.displayName = displayName; } else { this.displayName = defaultDisplayName(baseName); } } private String defaultDisplayName(String baseName) { String defaultDisplayName; if (path.contains("/" + UserPref.configAsWhenClosedName + "/")) { defaultDisplayName = AnLocale.getString("As Last Experiment Closed"); } else { String confName = baseName; if (confName.endsWith(UserPref.configurationSuffix)) { confName = baseName.substring(0, confName.length() - UserPref.configurationSuffix.length()); } String displayPath = path; int n = displayPath.length(); if (n > 70) { displayPath = displayPath.substring(0, 25) + "....." + displayPath.substring(n - 45, n); } defaultDisplayName = confName + " - (" + displayPath + ")"; } return defaultDisplayName; } @Override public String toString() { return displayName; } public boolean isDefault() { return isDefault; } public boolean isAsLast() { return isAsLast; } public String getPath() { return path; } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox alwaysCheckBox; private javax.swing.JButton confBrowseButton; private javax.swing.JComboBox confComboBox; private javax.swing.JCheckBox useConfCheckBox; private javax.swing.JButton wdBrowseButton; private javax.swing.JCheckBox workingDirCheckBox; private javax.swing.JLabel workingDirLabel; private javax.swing.JTextField workingDirTextField; // End of variables declaration//GEN-END:variables } gprofng-gui-1.0/org/gprofng/mpmt/AnTable.java0000644000175000017500000060460714517772113016123 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt; import static org.gprofng.mpmt.event.AnChangeEvent.Type.DEBUG; import static org.gprofng.mpmt.event.AnChangeEvent.Type.EXPERIMENTS_LOADED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.EXPERIMENTS_LOADED_FAILED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.EXPERIMENTS_LOADING_ADDED_OR_REMOVED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.EXPERIMENTS_LOADING_NEW; import static org.gprofng.mpmt.event.AnChangeEvent.Type.FILTER_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.FILTER_CHANGING; import static org.gprofng.mpmt.event.AnChangeEvent.Type.MOST_RECENT_EXPERIMENT_LIST_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.REMOTE_CONNECTION_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.REMOTE_CONNECTION_CHANGING; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SELECTED_OBJECT_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SELECTION_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SELECTION_CHANGING; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SELECTION_UPDATE; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGING; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SOURCE_FINDING_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SOURCE_FINDING_CHANGING; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.DisasmDisp.DisRenderer; import org.gprofng.mpmt.SourceDisp.SrcRenderer; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.filter.FilterClause; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.table.AnJTable; import org.gprofng.mpmt.table.AnTableHeaderPanel; import org.gprofng.mpmt.table.AnTableScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.Serializable; import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import javax.accessibility.AccessibleContext; import javax.swing.AbstractAction; import javax.swing.AbstractCellEditor; import javax.swing.BorderFactory; import javax.swing.DefaultListSelectionModel; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.SwingUtilities; import javax.swing.border.EtchedBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.EventListenerList; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.TableColumnModelEvent; import javax.swing.event.TableColumnModelListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableColumnModel; import javax.swing.table.JTableHeader; import javax.swing.table.TableCellEditor; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; public final class AnTable extends AnTableScrollPane implements AnChangeListener { private static final int AT_LIST = 0; public static final int AT_SRC = 1; protected static final int AT_SRC_ONLY = 2; public static final int AT_DIS = 3; private static final int AT_COM = 4; public static final int AT_QUOTE = 5; protected static final int AT_FUNC = 6; private static final int AT_EMPTY = 7; protected static final int AT_DIS_ONLY = 8; private static final int NUMBER_SPACE = 3; private static Font TableFont; private static Font QuoteFont; static { JTable jtable = new JTable(); Font org_font = jtable.getFont(); TableFont = new Font("Monospaced", org_font.getStyle(), org_font.getSize()); QuoteFont = TableFont.deriveFont(Font.ITALIC); } // Action names private final String STR_ACTION_COPY_ALL = AnLocale.getString("Copy All"); private final String STR_ACTION_COPY_SEL = AnLocale.getString("Copy Selected"); private final String STR_ACTION_BACK = AnLocale.getString("Back"); private final String STR_ACTION_FORWARD = AnLocale.getString("Forward"); private final String STR_ACTION_SETHEAD = AnLocale.getString("Set Head"); private final String STR_ACTION_SETTAIL = AnLocale.getString("Set Tail"); private final String STR_ACTION_REMOVE = AnLocale.getString("Remove"); private final String STR_ACTION_PREPEND = AnLocale.getString("Add Caller"); private final String STR_ACTION_APPEND = AnLocale.getString("Add Callee"); private final String STR_ACTION_RECENTER = AnLocale.getString("Set Center"); private final String STR_ACTION_RESET = AnLocale.getString("Reset"); private final String STR_ACTION_SHOW_DISASM = AnLocale.getString("Show Disassembly"); private final String STR_ACTION_SHOW_SOURCE = AnLocale.getString("Show Source"); private final String STR_ACTION_SHOW_SELECTED_FUNCTION = AnLocale.getString("Show the Selected Function"); private final String STR_ACTION_SHOW_CALLER_DISASM = AnLocale.getString("Show Caller Disassembly"); protected static final String STR_ACTION_SHOW_CALLEE_DISASM = AnLocale.getString("Show Callee Disassembly"); private final String STR_ACTION_SHOW_CALLER_SOURCE = AnLocale.getString("Show Caller Source"); protected static final String STR_ACTION_SHOW_CALLEE_SOURCE = AnLocale.getString("Show Callee Source"); private static final String ADD_FILTER = AnLocale.getString("Add Filter"); private static final String FILTER_SIMILARLY_NAMED_SHORT_NAME = AnLocale.getString("Similarly Named"); private static final String FILTER_SIMILARLY_NAMED_LONG_NAME = AnLocale.getString("Include only stacks containing similarly-named functions"); private static final String FILTER_SIMILARLY_NAMED_ACTION_NAME = "FilterSimilarlyNamed"; private static final String FILTER_CALLSTACK_FRAGMENT_SHORT_NAME = AnLocale.getString("Callstack Fragment"); private static final String FILTER_CALLSTACK_FRAGMENT_LONG_NAME = AnLocale.getString("Include only stacks containing this callstack fragment"); private static final String FILTER_CALLSTACK_FRAGMENT_ACTION_NAME = "FilterCallstackFragment"; private static final String FILTER_NOT_CALLSTACK_FRAGMENT_SHORT_NAME = AnLocale.getString("Not Callstack Fragment"); private static final String FILTER_NOT_CALLSTACK_FRAGMENT_LONG_NAME = AnLocale.getString("Include only stacks not containing this callstack fragment"); private static final String FILTER_NOT_CALLSTACK_FRAGMENT_ACTION_NAME = "FilterNotCallstackFragment"; private static final String FILTER_SELECTED_FUNCTION_SHORT_NAME = AnLocale.getString("Selected Function"); private static final String FILTER_SELECTED_FUNCTION_LONG_NAME = AnLocale.getString("Include only stacks containing the selected function"); private static final String FILTER_SELECTED_FUNCTION_ACTION_NAME = "FilterSelectedFunction"; private static final String FILTER_SELECTED_FUNCTIONS_SHORT_NAME = AnLocale.getString("Selected Functions"); private static final String FILTER_SELECTED_FUNCTIONS_LONG_NAME = AnLocale.getString("Include only stacks containing the selected functions"); private static final String FILTER_SELECTED_FUNCTIONS_ACTION_NAME = "FilterSelectedFunctions"; private static final String FILTER_NOT_SELECTED_FUNCTION_SHORT_NAME = AnLocale.getString("Not Selected Function"); private static final String FILTER_NOT_SELECTED_FUNCTION_LONG_NAME = AnLocale.getString("Include only stacks not containing the selected function"); private static final String FILTER_NOT_SELECTED_FUNCTION_ACTION_NAME = "FilterNotSelectedFunction"; private static final String FILTER_NOT_SELECTED_FUNCTIONS_SHORT_NAME = AnLocale.getString("Not Selected Functions"); private static final String FILTER_NOT_SELECTED_FUNCTIONS_LONG_NAME = AnLocale.getString("Include only stacks not containing the selected functions"); private static final String FILTER_NOT_SELECTED_FUNCTIONS_ACTION_NAME = "FilterNotSelectedFunctions"; private static final String FILTER_LEAF_FUNCTION_SHORT_NAME = AnLocale.getString("Selected Leaf Function"); private static final String FILTER_LEAF_FUNCTION_LONG_NAME = AnLocale.getString("Include only stacks with the selected function as leaf"); private static final String FILTER_LEAF_FUNCTION_ACTION_NAME = "FilterSelectedLeafFunction"; private static final String FILTER_LEAF_FUNCTIONS_SHORT_NAME = AnLocale.getString("Selected Leaf Functions"); private static final String FILTER_LEAF_FUNCTIONS_LONG_NAME = AnLocale.getString("Include only stacks with the selected functions as leaf"); private static final String FILTER_LEAF_FUNCTIONS_ACTION_NAME = "FilterSelectedLeafFunctions"; private final String FILTER_SELECTED_LINE_SHORT_NAME = AnLocale.getString("Selected Line"); private final String FILTER_SELECTED_LINE_LONG_NAME = AnLocale.getString("Include only stacks containing the selected line"); private final String FILTER_SELECTED_LINE_ACTION_NAME = "FilterSelectedLine"; private final String FILTER_SELECTED_LINES_SHORT_NAME = AnLocale.getString("Selected Lines"); private final String FILTER_SELECTED_LINES_LONG_NAME = AnLocale.getString("Include only stacks containing the selected lines"); private final String FILTER_SELECTED_LINES_ACTION_NAME = AnLocale.getString("FilterSelectedLines"); private final String FILTER_NOT_SELECTED_LINE_SHORT_NAME = AnLocale.getString("Not Selected Line"); private final String FILTER_NOT_SELECTED_LINE_LONG_NAME = AnLocale.getString("Include only stacks not containing the selected line"); private final String FILTER_NOT_SELECTED_LINE_ACTION_NAME = "FilterNotSelectedLine"; private final String FILTER_NOT_SELECTED_LINES_SHORT_NAME = AnLocale.getString("Not Selected Lines"); private final String FILTER_NOT_SELECTED_LINES_LONG_NAME = AnLocale.getString("Include only stacks not containing the selected lines"); private final String FILTER_NOT_SELECTED_LINES_ACTION_NAME = "FilterNotSelectedLines"; private final String FILTER_SELECTED_PC_SHORT_NAME = AnLocale.getString("Selected PC"); private final String FILTER_SELECTED_PC_LONG_NAME = AnLocale.getString("Include only stacks containing the selected PC"); private final String FILTER_SELECTED_PC_ACTION_NAME = "FilterSelected PC"; private final String FILTER_SELECTED_PCS_SHORT_NAME = AnLocale.getString("Selected PCs"); private final String FILTER_SELECTED_PCS_LONG_NAME = AnLocale.getString("Include only stacks containing the selected PCs"); private final String FILTER_SELECTED_PCS_ACTION_NAME = "AddFilterSelectedPCs"; private final String FILTER_NOT_SELECTED_PC_SHORT_NAME = AnLocale.getString("Not Selected PC"); private final String FILTER_NOT_SELECTED_PC_LONG_NAME = AnLocale.getString("Include only stacks not containing the selected PC"); private final String FILTER_NOT_SELECTED_PC_ACTION_NAME = AnLocale.getString("FilterNotSelectedPC"); private final String FILTER_NOT_SELECTED_PCS_SHORT_NAME = AnLocale.getString("Not Selected PCs"); private final String FILTER_NOT_SELECTED_PCS_LONG_NAME = AnLocale.getString("Include only stacks not containing the selected PCs"); private final String FILTER_NOT_SELECTED_PCS_ACTION_NAME = AnLocale.getString("FilterNotSelected PCs"); private static final String FILTER_WITHOUT_SELECTED_ITEMS_SHORT_NAME = AnLocale.getString("Without Selected Items"); private static final String FILTER_WITHOUT_SELECTED_ITEMS_LONG_NAME = AnLocale.getString("Include only events without selected items"); private static final String FILTER_WITHOUT_SELECTED_ITEMS_ACTION_NAME = "FilterWithoutSelectedItems"; private static final String FILTER_WITH_SELECTED_ITEMS_SHORT_NAME = AnLocale.getString("With Selected Items"); private static final String FILTER_WITH_SELECTED_ITEMS_LONG_NAME = AnLocale.getString("Include only events with selected items"); private static final String FILTER_WITH_SELECTED_ITEMS_ACTION_NAME = "FilterWithSelectedItems"; private static final String FILTER_WITH_SELECTED_FILE_SHORT_NAME = AnLocale.getString("Selected Files"); private static final String FILTER_WITH_SELECTED_FILE_LONG_NAME = AnLocale.getString("Include only events containing the selected files"); private static final String FILTER_WITH_SELECTED_FILE_ACTION_NAME = "FilterWithSelectedFiles"; private static final String FILTER_NOT_SELECTED_FILE_SHORT_NAME = AnLocale.getString("Unselected Files"); private static final String FILTER_NOT_SELECTED_FILE_LONG_NAME = AnLocale.getString("Include only events not containing the selected files"); private static final String FILTER_NOT_SELECTED_FILE_ACTION_NAME = "FilterWithNotSelectedFiles"; private static final String FILTER_WITH_SELECTED_IOVFD_SHORT_NAME = AnLocale.getString("Selected File Descriptors"); private static final String FILTER_WITH_SELECTED_IOVFD_LONG_NAME = AnLocale.getString("Include only events containing the selected file descriptors"); private static final String FILTER_WITH_SELECTED_IOVFD_ACTION_NAME = "FilterWithSelectedFileDescriptors"; private static final String FILTER_NOT_SELECTED_IOVFD_SHORT_NAME = AnLocale.getString("Unselected File Descriptors"); private static final String FILTER_NOT_SELECTED_IOVFD_LONG_NAME = AnLocale.getString("Include only events not containing the selected file descriptors"); private static final String FILTER_NOT_SELECTED_IOVFD_ACTION_NAME = "FilterWithNotSelectedFileDescriptors"; private static final String FILTER_WITH_SELECTED_IOSTACK_SHORT_NAME = AnLocale.getString("Selected Stacks"); private static final String FILTER_WITH_SELECTED_IOSTACK_LONG_NAME = AnLocale.getString("Include only events containing the selected stacks"); private static final String FILTER_WITH_SELECTED_IOSTACK_ACTION_NAME = "FilterWithSelectedIOStacks"; private static final String FILTER_NOT_SELECTED_IOSTACK_SHORT_NAME = AnLocale.getString("Unselected Stacks"); private static final String FILTER_NOT_SELECTED_IOSTACK_LONG_NAME = AnLocale.getString("Include only events not containing the selected stacks"); private static final String FILTER_NOT_SELECTED_IOSTACK_ACTION_NAME = "FilterWithNotSelectedIOStacks"; private static final String FILTER_WITH_SELECTED_HEAPSTACK_SHORT_NAME = AnLocale.getString("Selected Stacks"); private static final String FILTER_WITH_SELECTED_HEAPSTACK_LONG_NAME = AnLocale.getString("Include only events containing the selected stacks"); private static final String FILTER_WITH_SELECTED_HEAPSTACK_ACTION_NAME = "FilterWithSelectedHeapStacks"; private static final String FILTER_NOT_SELECTED_HEAPSTACK_SHORT_NAME = AnLocale.getString("Unselected Stacks"); private static final String FILTER_NOT_SELECTED_HEAPSTACK_LONG_NAME = AnLocale.getString("Include only events not containing the selected stacks"); private static final String FILTER_NOT_SELECTED_HEAPSTACK_ACTION_NAME = "FilterWithNotSelectedHeapStacks"; private static final String FILTER_WITH_SELECTED_HEAPACTIVESTACK_SHORT_NAME = AnLocale.getString("Peak Active Allocations"); private static final String FILTER_WITH_SELECTED_HEAPACTIVESTACK_LONG_NAME = AnLocale.getString("Include only active allocations for the peak"); private static final String FILTER_WITH_SELECTED_HEAPACTIVESTACK_ACTION_NAME = "FilterActiveHeapAllocations"; private static final String FILTER_WITH_SELECTED_HEAPLEAKEDSTACK_SHORT_NAME = AnLocale.getString("Only Leaks"); private static final String FILTER_WITH_SELECTED_HEAPLEAKEDSTACK_LONG_NAME = AnLocale.getString("Include only allocations that leaked"); private static final String FILTER_WITH_SELECTED_HEAPLEAKEDSTACK_ACTION_NAME = "FilterHeapLeaked"; private static final String FILTER_NOT_SELECTED_HEAPLEAKEDSTACK_SHORT_NAME = AnLocale.getString("Exclude Leaks"); private static final String FILTER_NOT_SELECTED_HEAPLEAKEDSTACK_LONG_NAME = AnLocale.getString("Exclude allocations that leaked"); private static final String FILTER_NOT_SELECTED_HEAPLEAKEDSTACK_ACTION_NAME = "FilterHeapExcludeLeaked"; private static final String FILTER_WITH_SELECTED_JGROUP_SHORT_NAME = AnLocale.getString("Selected JGroup"); private static final String FILTER_WITH_SELECTED_JGROUP_LONG_NAME = AnLocale.getString("Include only JThreads in selected group"); private static final String FILTER_WITH_SELECTED_JGROUP_ACTION_NAME = "FilterWithSelectedJGroup"; private static final String FILTER_WITH_SELECTED_JPARENT_SHORT_NAME = AnLocale.getString("Selected JParent"); private static final String FILTER_WITH_SELECTED_JPARENT_LONG_NAME = AnLocale.getString("Include only JThreads in selected parent"); private static final String FILTER_WITH_SELECTED_JPARENT_ACTION_NAME = "FilterWithSelectedJParent"; private final String STR_ACTION_UNDOFILTER = AnLocale.getString("Undo Filter Action"); private final String STR_ACTION_REDOFILTER = AnLocale.getString("Redo Filter Action"); private final String STR_ACTION_REMOVE_ALL_FILTERS = AnLocale.getString("Remove All Filters"); private final String STR_ACTION_CUSTOM_FILTER = ADD_FILTER + ": " + AnLocale.getString("Advanced Custom Filter..."); private AnMenuListener menuListener; private AnTable anTable; private JTable table; private int type; private JTableHeader tableHeader; private FListTableModel tableModel; private FListColumnModel columnModel; private FontMetrics fontMetrics; private int[][] columnWidth; private int rowHeight; private String[] names; private int orgRow; // What is this? private int selectedRow; private int nameColumn; private int sortColumn; private int nameWidth; private boolean hasHeader; private boolean canSort; private boolean isSingle; private boolean colScroll; private boolean hasSelect; private boolean wrapMetricNames; public boolean columnsSaved = false; public int[] selected_indices; private String acName; private String acDesc; private JLabel acLabel; private AnDisplay parent = null; public AnHotGap gap; protected SrcRenderer srcRenderer = null; protected DisRenderer disRenderer = null; private NavigationHistoryPool navHistoryPool = null; private int groupId = 0; private JComponent allHeaderPanel = null; private static Integer MIN_CELL_WIDTH = null; private HotGapPanel hotGapPanel = null; /** * Returns a new instance of AnTable, which extends JScrollPane and contains a JTable inside. * *

This method always creates a new JTable, according to the specified requirements. It sets * Accessible Name, Accessible Description and Label for the JTable. * * @param type Type of AnDisplay, that creates AnTable (parent type) * @param hasHeader Boolean flag: if true, AnTable has header * @param can_sort Boolean flag: if true, information can be sorted * @param isSingle Boolean flag: if true, the table does not allow multiselection * @param colScroll Boolean flag: if true, set HorizontalScrollBar as needed (false - never) * @param hasSelect Boolean flag: if true, show selection * @param accessibleName Accessible Name for JTable * @param accessibleDescr Accessible Description for JTable * @param LabelFor Label for JTable * @return a new instance of AnTable * @see AnTable */ public AnTable( int type, boolean hasHeader, boolean hasColumnButton, boolean can_sort, boolean isSingle, boolean colScroll, boolean hasSelect, boolean wrapMetricNames, String accessibleName, String accessibleDescr, JLabel LabelFor) { super(type, hasColumnButton); this.type = type; this.hasHeader = hasHeader; this.canSort = can_sort; this.isSingle = isSingle; this.colScroll = colScroll; this.hasSelect = hasSelect; this.wrapMetricNames = wrapMetricNames; this.acName = accessibleName; this.acDesc = accessibleDescr; this.acLabel = LabelFor; anTable = this; fontMetrics = null; rowHeight = 20; orgRow = -1; selectedRow = 0; nameColumn = 0; sortColumn = -1; nameWidth = 0; columnWidth = new int[1][4]; columnWidth[0][0] = 30; columnWidth[0][1] = columnWidth[0][2] = columnWidth[0][3] = 10; initComponents(); AnEventManager.getInstance().addListener(this); } public void setHotGapPanel(HotGapPanel hotGapPanel) { this.hotGapPanel = hotGapPanel; } private static int getMinimumColumnWidth() { if (MIN_CELL_WIDTH == null) { MIN_CELL_WIDTH = AnTableHeaderPanel.getMinimumColumnWidth(); } return MIN_CELL_WIDTH; } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("IOView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: case EXPERIMENTS_LOADED_FAILED: case EXPERIMENTS_LOADED: case FILTER_CHANGED: case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.TABLE_FORMATS) { tableModel.updateTableHeaders(); } break; case DEBUG: break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } /* * Hack: Set parent * used to clear selections in all tables in Callers-Callees tab */ public void setParent(AnDisplay parent) { this.parent = parent; } public AnDisplay getAnParent() { return parent; } protected NavigationHistoryPool getNavigationHistoryPool() { return navHistoryPool; } public int getNameCol() { return nameColumn; } public int getType() { return anTable.type; } public boolean wrapMetricNames() { return wrapMetricNames; } public void setWrapMetricNames(boolean val) { wrapMetricNames = val; } protected AnMenuListener getMenuListener() { return menuListener; } // Initialize GUI components private void initComponents() { final Dimension psize; final ListSelectionModel sel_model; final CallHandler callHandler; final JLabel corner; switch (type) { case AnDisplay.DSP_Functions: navHistoryPool = new NavigationHistoryPool(); break; case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_DisassemblyV2: disRenderer = new DisRenderer(anTable); navHistoryPool = new NavigationHistoryPool(); break; case AnDisplay.DSP_Source: case AnDisplay.DSP_SourceV2: srcRenderer = new SrcRenderer(anTable); navHistoryPool = new NavigationHistoryPool(); break; } gap = null; tableModel = new FListTableModel(); columnModel = new FListColumnModel(); table = new AnJTable(tableModel, columnModel); AnUtility.setAccessibleContext( table.getAccessibleContext(), AnLocale.getString("Table")); // FIXUP: export table is using AccessibleContext in output! table.setBorder(null); // A11Y for tables AccessibleContext ac = table.getAccessibleContext(); if (acName != null) { ac.setAccessibleName(acName); } if (acDesc != null) { ac.setAccessibleDescription(acDesc); } if (acLabel != null) { acLabel.setLabelFor(table); } callHandler = new CallHandler(); table.registerKeyboardAction( new CallHandler(), "ENTER", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); // Popup menu menuListener = new AnMenuListener(this); table.addMouseListener(menuListener); this.addMouseListener(menuListener); KeyStroke ks = KeyboardShortcuts.contextMenuActionShortcut; table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, ks); table .getActionMap() .put( ks, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { JPopupMenu popup = initPopup(false); if (popup != null) { JTable src = (JTable) ev.getSource(); Rectangle cellRect, visRect; visRect = src.getVisibleRect(); cellRect = visRect; int selrow = src.getSelectedRow(); if (selrow >= 0) { cellRect = src.getCellRect(selrow, 0, false); } // if current view doesn't include selected row, scroll if (!visRect.contains(cellRect)) { // calculate middle based on selected row // being below or above current visible rows if (visRect.y < cellRect.y) { cellRect.y += visRect.height / 2; } else { cellRect.y -= visRect.height / 2; } src.scrollRectToVisible(cellRect); } popup.show(src, cellRect.x, cellRect.y + cellRect.height); } } }); // // Add hot keys for sorting // for (int i = 1; i < 10; i++) { // s = "ALT_" + i; // ks = KeyStroke.getKeyStroke(KeyEvent.VK_0 + i, InputEvent.ALT_DOWN_MASK, false); // SortMenu sortMenu = new SortMenu(i - 1); // table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, s); // table.getActionMap().put(s, sortMenu); // } // Add hot keys for navigation switch (type) { case AnDisplay.DSP_Source: case AnDisplay.DSP_SourceV2: case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_DisassemblyV2: // Previous Hot Line KeyStroke keyStrokeUp = KeyboardShortcuts.sourcePreviousHotLineActionShortcut; table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeUp, keyStrokeUp); table .getActionMap() .put( keyStrokeUp, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { gap.HG_Prev_Hot_Line(); } }); // Next Hot Line KeyStroke keyStrokeDown = KeyboardShortcuts.sourceNextHotLineActionShortcut; table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeDown, keyStrokeDown); table .getActionMap() .put( keyStrokeDown, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { gap.HG_Next_Hot_Line(); } }); // Next NZ Line KeyStroke keyStrokeNextNZ = KeyboardShortcuts.sourceNextNonZeroLineActionShortcut; table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeNextNZ, keyStrokeNextNZ); table .getActionMap() .put( keyStrokeNextNZ, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { gap.HG_Next_NZ_Line(); } }); // Previous NZ Line KeyStroke keyStrokePreviousNZ = KeyboardShortcuts.sourcePreviousNonZeroLineActionShortcut; table .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(keyStrokePreviousNZ, keyStrokePreviousNZ); table .getActionMap() .put( keyStrokePreviousNZ, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { gap.HG_Prev_NZ_Line(); } }); } table.setAutoCreateColumnsFromModel(true); table.setShowGrid(false); table.setIntercellSpacing(new Dimension(0, 0)); // table.setShowVerticalLines(true); // table.setGridColor(AnEnvironment.TABLE_VERTICAL_GRID_COLOR); table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); table.setAutoscrolls(false); if (isSingle) { psize = table.getPreferredScrollableViewportSize(); psize.height = TableFont.getSize() + table.getRowMargin() + 5; table.setPreferredScrollableViewportSize(psize); } // Set selecting mode & add events listener for row selecting sel_model = table.getSelectionModel(); // sel_model.setSelectionMode(canSort // ? ListSelectionModel.SINGLE_SELECTION // : ListSelectionModel.SINGLE_INTERVAL_SELECTION); if (!isSingle) { sel_model.addListSelectionListener(new CellHandler()); } if (!hasSelect) { table.addMouseListener(callHandler); table.registerKeyboardAction( callHandler, "SPACE", KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); } else { table.addMouseListener(new TableAdapter()); } // Set table font as proportionally-spaced table.setFont(TableFont); // Set default table cell renderer table.setDefaultRenderer(Object.class, new CellRenderer()); table.setDefaultEditor(Object.class, new CellEditor()); // Set table as the View component setViewportView(table); corner = new JLabel(); corner.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); setCorner(UPPER_RIGHT_CORNER, corner); setHorizontalScrollBarPolicy( colScroll ? HORIZONTAL_SCROLLBAR_AS_NEEDED : HORIZONTAL_SCROLLBAR_NEVER); setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_ALWAYS); if (isSingle) { getVerticalScrollBar().setEnabled(false); } // Add events listener for sorting (clicks on header), and // Set default header renderer tableHeader = table.getTableHeader(); if (hasHeader) { } else { table.setTableHeader(null); if (colScroll) { getHorizontalScrollBar().addAdjustmentListener(new ScrollHandler()); } } // Add resize listener addComponentListener(new TableListener()); } public JTable getTable() { return table; } /** * @param view Hack to prevent header panel to be overriden */ @Override public void setColumnHeaderView(Component view) { if (allHeaderPanel != null) { super.setColumnHeaderView(allHeaderPanel); } else { super.setColumnHeaderView(view); } } // Set header for table without real header public void setHeader(final AnTable other_table) { tableHeader = other_table.tableHeader; } // Set table as the View component public void setViewport() { setViewportView(table); } // Returns sort column public int getSortColumn() { return sortColumn; } public boolean canSort() { return canSort; } public String[] getNames() { return names; } public int getSrcType(int row) { if (tableModel != null) { return tableModel.getSrcType(row); } return AT_LIST; } public void goToLine(int row) { if (row < 0) { return; } switch (type) { case AnTable.AT_SRC: case AnTable.AT_DIS: case AnTable.AT_QUOTE: break; default: return; } Object[][] d = getTableData(); if (d.length <= row) { return; } setSelectedRow(row); } // Returns row count public int getRowCount() { if (null == table) { return -1; } return table.getRowCount(); } /** Performs default action for double click */ public void performDefaultAction() { // System.out.println("performDefaultAction"); // Switch Display switch (type) { case AnDisplay.DSP_Functions: case AnDisplay.DSP_Lines: { // Default action: Show Source parent.window.setSelectedView(AnDisplay.DSP_Source); break; } case AnDisplay.DSP_PCs: case AnDisplay.DSP_Source: case AnDisplay.DSP_SourceV2: { // Default action: Show Disassembly parent.window.setSelectedView(AnDisplay.DSP_Disassembly); break; } case AnDisplay.DSP_MiniFunctions: { parent.window.setSelectedView(AnDisplay.DSP_Functions); break; } case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_DisassemblyV2: { parent.window.getSettings().toggleDisFuncScope(); break; } case AnDisplay.DSP_MiniCaller: case AnDisplay.DSP_MiniCallee: { updateSelectedRow(table.getSelectedRow()); break; } } } /** Create text presentation of the table header. */ protected String printTableHeader(String sortedby, Object[][] MaximumValues) { JTable t = table; String empty = ""; String tname = empty; // Get table name (preferably localized) if (null != t.getAccessibleContext()) { tname = t.getAccessibleContext().getAccessibleName(); } else { // There should be some other way to get table name tname = t.getName(); } if (null == tname) { tname = empty; } return printTableHeader(tname, sortedby, MaximumValues); } private int spacesBetweenColumns = 3; private int spacesForPercentage = 10; /** Create text presentation of the table header. */ protected synchronized String printTableHeader( String tname, String sortedby, Object[][] MaximumValues) { // Prepare text presentation of the table String space = " "; String eol = "\n"; String empty = ""; String text = tname; if (canSort) { // text = "Functions sorted by metric: Exclusive Total CPU Time\n" int sc = getSortColumn(); if (sc >= 0) { MetricLabel m = getTableModel().getLabel(sc); String ltext = m.getAnMetric().getName(); text += space + sortedby + space + ltext + eol; } } if ((type == AnDisplay.DSP_Source) || (type == AnDisplay.DSP_SourceV2)) { // Print Source File name if (this.names != null && this.names.length > 0) { text = this.names[0]; // Source File: ... text += eol; } } if ((type == AnDisplay.DSP_Disassembly) || (type == AnDisplay.DSP_DisassemblyV2)) { // Print Load Object name if (this.names != null && this.names.length > 2) { text = this.names[2]; // Load Object: ... text += eol; } } text += eol; MetricLabel[] labels = tableModel.metricLabels; String[][] s = new String[labels.length][]; show_percentage = new boolean[labels.length]; for (int j = 0; j < labels.length; j++) { s[j] = labels[j].getLegendAndTitleLines(); if (labels[j].getAnMetric().isPVisible()) { // Show percentage show_percentage[j] = true; } else { show_percentage[j] = false; } } if (null != s) { int maxh[] = new int[s.length]; int maxv = 0; for (int i = 0; i < s.length; i++) { if (s[i].length > maxv) { maxv = s[i].length; } maxh[i] = 0; for (int j = 0; j < s[i].length; j++) { if (s[i][j].length() > maxh[i]) { maxh[i] = s[i][j].length(); } } } for (int i = 0; i < maxh.length; i++) { // choose max width between the label length and max value length int maxvalen = 0; if (null != MaximumValues) { if (labels[i].getAnMetric().isVVisible()) { // Show Value maxvalen = MaximumValues[1][i].toString().length(); } String value = empty; if (labels[i].getAnMetric().isTVisible()) { // Show Time if (labels[i].getClock() != -1.0) { // Can convert cycles to time value = ((AnObject) MaximumValues[1][i]).toFormTime(labels[i].getClock()); } else { value = MaximumValues[1][i].toString(); } } maxvalen += value.length(); if (labels[i].getAnMetric().isVVisible() && labels[i].getAnMetric().isTVisible()) { // Show Value and Time maxvalen += 1; // space between them } } if (labels[i].getAnMetric().isPVisible()) { // Show percentage maxvalen += spacesForPercentage; } if (maxvalen > maxh[i]) { maxh[i] = maxvalen; } // add spaces to separate header labels maxh[i] += spacesBetweenColumns; } for (int i = 0; i < maxv; i++) { for (int j = 0; j < s.length; j++) { int k = 0; if (s[j].length > i) { text += s[j][i]; // Print header label k = s[j][i].length(); } if (j + 1 < s.length) { // do not add spaces to the end // print formatting spaces for (; k < maxh[j]; k++) { text += space; } } } text += eol; } boolean needeol = false; String units = empty; for (int i = 0; i < labels.length; i++) { String un = labels[i].getUnit(); if (null == un) { un = empty; } if (un.length() > 0) { needeol = true; } units += un; if (i + 1 < labels.length) { // do not add spaces to the end for (int k = un.length(); k < maxh[i]; k++) { // print formatting spaces units += space; } } } if (needeol) { text += units; text += eol; } header_widths = maxh; } return text; } // Temporary solution. This array should be local variable of function, that includes function // above and below private int[] header_widths = null; private boolean[] show_percentage = null; /** Create text presentation of the table. */ protected int[] getTableHeaderWidths() { return header_widths; } /** Create text presentation of the table. */ protected boolean[] getPercentageArray() { return show_percentage; } /** Create text presentation of the table. */ protected String printTableContents(Object[][] MaximumValues, int printLimit) { boolean last_only = false; boolean selected_only = false; return printTableContents( MaximumValues, header_widths, printLimit, show_percentage, last_only, selected_only); } /** Create text presentation of the selected rows of the table. */ protected String printSelectedTableContents(Object[][] MaximumValues, int printLimit) { boolean last_only = false; boolean selected_only = true; return printTableContents( MaximumValues, header_widths, printLimit, show_percentage, last_only, selected_only); } /** Create text presentation of the table. */ protected synchronized String printTableContents( Object[][] MaximumValues, int[] header_widths, int printLimit, boolean[] show_percentage, boolean last_only, boolean selected_only) { // Prepare text presentation of the table JTable t = table; String space = " "; String empty = ""; String eol = "\n"; StringBuilder fileContent = new StringBuilder(); TableModel tModel = t.getModel(); int namecol = getNameCol(); int rows = tModel.getRowCount(); if (columnWidth.length <= 1) { return "\n" + AnLocale.getString("No metrics selected for this view") + "\n"; } if (printLimit > 0) { // print max printLimit if (printLimit < rows) { rows = printLimit; } } else if (printLimit < 0) { // print headers only rows = 0; } int sz = rows; if (selected_only) { if (null == selected_indices) { selected_indices = table.getSelectedRows(); } if (null == selected_indices) { return empty; } sz = selected_indices.length; } for (int index = 0; index < sz; index++) { int i = index; if (selected_only) { i = selected_indices[index]; } // Check if all values are empty boolean emptyValues = false; int src_type = tableModel.getSrcType(i); if (src_type < 0) { src_type = -src_type; } if ((src_type == AT_SRC_ONLY) || (src_type == AT_COM) || (src_type == AT_FUNC) || (src_type == AT_EMPTY) || (src_type == AT_DIS_ONLY)) { emptyValues = true; } for (int j = 0; j < tModel.getColumnCount(); j++) { // get the cell value Object cellValue = tModel.getValueAt(i, j); MetricLabel label = tableModel.getLabel(j); boolean showPercentage = false; String value = empty; // Used for empty values if (j == namecol) { // Name value = cellValue.toString(); } else { if (!emptyValues) { if (label.getAnMetric().isTVisible()) { // Show time value = cellValue.toString(); if (label.getClock() != -1.0) { // Can convert cycles to time value = ((AnObject) cellValue).toFormTime(label.getClock()); } } String value1 = empty; if (label.getAnMetric().isVVisible()) { // Show value value1 = cellValue.toString(); // number of cycles } if (label.getAnMetric().isPVisible()) { // Show percentage showPercentage = true; } if ((label.getClock() != -1.0) /* || (label.unit != null) */) { // CPU cycles String value2 = empty; if (showPercentage) { // calculate the weight of one percent double onepercent = 0.0; double total = 0.0; if (MaximumValues != null) { total = ((AnObject) MaximumValues[0][j]).doubleValue(); } if (total > 0.0) { onepercent = 100.0 / total; } // calculate the percentage value2 = ((AnObject) cellValue).toPercent(onepercent); value2 = "(" + value2 + "%)"; } // Insert formatting spaces int k = value.length() + value1.length() + value2.length() + 4; // 4 spaces if (k < header_widths[j]) { int len2 = 9 - value2.length(); // 9 - max percent length "(100.00%)" String maxvalue = ((AnObject) MaximumValues[1][j]).toFormTime(label.getClock()); int len = maxvalue.length() - value.length(); String spaces = empty; while (k++ < header_widths[j]) { spaces += space; if (showPercentage) { if (len2 > 0) { // percentage len2--; if (len2 == 0) { // add spaces to percentage value2 = spaces + value2; spaces = empty; } continue; } } if (len > 0) { // value len--; if (len == 0) { // add spaces to the left value = spaces + value; spaces = empty; } continue; } } value1 = spaces + value1; // add spaces to the middle } else { if (k > header_widths[j]) { String spaces = empty; // Is it a bug that we are here? while (k++ < header_widths[j]) { spaces += space; } value1 = spaces + value1; // add spaces to the middle } } value += space + value1 + space + value2 + space + space; } else { // Not CPU cycles if (showPercentage) { // Show pecentage double total = 0.0; if (MaximumValues != null) { total = ((AnObject) MaximumValues[0][j]).doubleValue(); } double percent = 0.0; if (total > 0.0) { percent = (((AnObject) cellValue).doubleValue() / total) * 100; } if (label.getAnMetric().isVVisible() || label.getAnMetric().isTVisible()) { // Show value and percentage value = ((AnObject) cellValue).toPercentQuote(percent); } else { // Show only percentage DecimalFormat format_percent = new DecimalFormat("0.00"); value = format_percent.format(percent); // Add formatting spaces int k = 6 - value.length(); String spaces = empty; while (k-- > 0) { spaces += space; } value = spaces + value; // add spaces to the left value = "(" + value + "%)"; k = 9; spaces = empty; while (k++ < header_widths[j]) { spaces += space; } value += spaces; // add spaces to the right } } else { // Show value value = cellValue.toString(); } } } else { // Do not show empty values // value = empty; } } // calculate formatting spaces int needspaces = 0; if (label.getAnMetric().isVVisible() || label.getAnMetric().isTVisible()) { // Show value if (MaximumValues != null) { needspaces = MaximumValues[1][j].toString().length(); } } if (showPercentage) { needspaces += spacesForPercentage; } int maxvalen = needspaces; if ((null != header_widths) && (needspaces < header_widths[j])) { needspaces = header_widths[j]; } if (j != namecol) { int k = maxvalen - value.length(); if (k > 0) { // insert formatting spaces needspaces -= k; while (k > 0) { fileContent.append(space); k--; } } } needspaces -= value.length(); if ((last_only) && (j != namecol) && (i + 1 != rows)) { // print spaces instead of values for (int k = 0; k < value.length(); k++) { fileContent.append(space); } } else { // append the cell value fileContent.append(value); } // append formatting spaces if (needspaces < 1) { needspaces = 1; } if ((j + 1) < tModel.getColumnCount()) { for (int k = 0; k < needspaces; k++) { fileContent.append(space); } } } fileContent.append(eol); } fileContent.append(eol); String text = fileContent.toString(); return text; } // Listener for resize private final class TableListener implements ComponentListener { @Override public final void componentResized(final ComponentEvent e) { tableModel.fitColumnResize(-1); if (nameColumn != (columnWidth.length - 1)) { // See 22289649 - table headers not aligned with numbers when window is resized TableColumnModel columnModel = table.getColumnModel(); TableColumn nameColumn = columnModel.getColumn(AnTable.this.nameColumn); if (AnTable.this.nameColumn >= 0 && AnTable.this.nameColumn < columnWidth.length - 1 && columnWidth[AnTable.this.nameColumn].length > 0) { if (columnWidth[AnTable.this.nameColumn][0] != nameColumn.getWidth()) { columnWidth[AnTable.this.nameColumn][0] = nameColumn.getWidth(); tableModel.updateTableHeaders(); // FIXUP: called too often in some cases.... } } } } @Override public void componentHidden(final ComponentEvent e) {} @Override public void componentMoved(final ComponentEvent e) {} @Override public void componentShown(final ComponentEvent e) {} } // Returns table model public FListTableModel getTableModel() { // public for mem/idx objs return tableModel; } // A JLabel for table cell private static final class FListLabel extends JLabel { final boolean is_number; public FListLabel(final String text, final JComponent cmp, final int horizontalAlignment) { super(text); getAccessibleContext().setAccessibleDescription(text); getAccessibleContext().setAccessibleName(text); setHorizontalAlignment(horizontalAlignment); setVerticalAlignment(TOP); setFont(cmp.getFont()); setBorder(AnVariable.labelBorder); setForeground(cmp.getForeground()); setBackground(cmp.getBackground()); is_number = (cmp instanceof JTable) && (horizontalAlignment == RIGHT); } protected final void paintComponent(final Graphics g) { final FontMetrics fm; final int ascent; int pos; final String str; String cstr; char ch; if (g == null) { System.err.println("NULL GRAPHICS"); } if (!is_number) { super.paintComponent(g); return; } fm = g.getFontMetrics(); ascent = fm.getAscent(); pos = getWidth() - getInsets().right; str = getText(); for (int i = str.length() - 1; i >= 0; i--) { ch = str.charAt(i); if (ch == '@') { pos -= NUMBER_SPACE; } else { cstr = String.valueOf(ch); pos -= fm.stringWidth(cstr); g.drawString(cstr, pos, ascent); } } } // Overridden for performance reasons. public final void validate() {} public final void revalidate() {} public final void repaint( final long tm, final int x, final int y, final int width, final int height) {} public final void repaint(final Rectangle r) {} protected final void firePropertyChange( final String propertyName, final Object oldValue, final Object newValue) { if (propertyName.equals("text")) { super.firePropertyChange(propertyName, oldValue, newValue); } } public final void firePropertyChange( final String propertyName, final boolean oldValue, final boolean newValue) {} } // A JPanel which may contain one or more values private final class CellPanel extends JPanel { public CellPanel(JTable table, boolean isSelected, int align) { setLayout(new FlowLayout(align, 0, 0)); if (isSelected || isSingle) { setForeground(table.getSelectionForeground()); setBackground(table.getSelectionBackground()); } else { setForeground(table.getForeground()); setBackground(table.getBackground()); } } } private final class CellEditor extends AbstractCellEditor implements TableCellEditor, Serializable { private CellRenderer cr = new CellRenderer(); public Component getTableCellEditorComponent( final JTable table, final Object value, final boolean isSelected, final int row, final int column) { return (cr.getTableCellRendererComponent(table, value, isSelected, true, row, column)); } @Override public Object getCellEditorValue() { return null; } } // Table cell renderer private final class CellRenderer implements TableCellRenderer, Serializable { @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { final CellPanel panel; final int mcolumn; int src_type; final int[] col_w; FListLabel fl; final MetricLabel label; Dimension psize; if (value == null) { JPanel panel2 = new JPanel(); panel2.setBackground(Color.red); return panel2; } panel = new CellPanel( table, isSelected, value instanceof String ? FlowLayout.LEFT : FlowLayout.CENTER); if (hasFocus) { panel.setBorder(AnVariable.tableFocusBorder); } // color background every other line if (!isSelected) { if (canSort() && column == sortColumn) { if (row % 2 == 1) { panel.setBackground(AnEnvironment.TABLE_LINE_BACKGROUND_SELECTED_COLUMN_COLOR_2); } else { panel.setBackground(AnEnvironment.TABLE_LINE_BACKGROUND_SELECTED_COLUMN_COLOR_1); } } else { if (!isSelected && row % 2 == 1) { panel.setBackground(AnEnvironment.TABLE_LINE_BACKGROUND_COLOR_2); } } } mcolumn = table.convertColumnIndexToModel(column); col_w = columnWidth[mcolumn]; panel.setOpaque(true); // Check if flagged as important src_type = tableModel.getSrcType(row); if (src_type < 0) { src_type = -src_type; } if (mcolumn != nameColumn) { HashMap mark = tableModel.hotMarks.get(row); if (mark != null) { Boolean bvalue = mark.get(mcolumn); if (bvalue != null && bvalue) { panel.setBackground(AnVariable.HILIT_COLOR); } } mark = tableModel.hotMarks_inc.get(row); if (mark != null) { Boolean bvalue = mark.get(mcolumn); if (bvalue != null && bvalue) { panel.setBackground(AnVariable.HILIT_INC_COLOR); } } } // Just single string if (value instanceof String) { if (type != AnDisplay.DSP_DataLayout) { if ((src_type == AT_SRC) || (src_type == AT_SRC_ONLY)) { // get rendered src panel from SourceDisp SrcRenderer.SrcTextPane st = null; if (srcRenderer != null) { st = srcRenderer.getSrcTextPane((String) value, table, row); } else if (disRenderer != null) { st = disRenderer.getSrcTextPane((String) value, table, row); } if (st != null) { psize = new Dimension(col_w[1], rowHeight); st.setPreferredSize(new Dimension(psize)); st.setMinimumSize(new Dimension(psize)); st.setMaximumSize(new Dimension(psize)); if (disRenderer != null) { panel.setBackground(AnVariable.SRCDIS_COLOR); } panel.add(st); return panel; } } else if ((src_type == AT_DIS) || (src_type == AT_DIS_ONLY)) { if (disRenderer != null) { DisRenderer.DisTextPane dt; dt = disRenderer.getDisTextPane((String) value, table, row); psize = new Dimension(col_w[1], rowHeight); dt.setPreferredSize(new Dimension(psize)); dt.setMinimumSize(new Dimension(psize)); dt.setMaximumSize(new Dimension(psize)); panel.add(dt); return panel; } } } panel.add(fl = new FListLabel((String) value, table, JLabel.LEFT)); if (((String) value).startsWith("<")) { fl.setFont(QuoteFont); } if ((((String) value).trim()).startsWith("(")) { fl.setFont(QuoteFont); } psize = new Dimension(col_w[1], rowHeight); fl.setPreferredSize(new Dimension(psize)); fl.setMinimumSize(new Dimension(psize)); fl.setMaximumSize(new Dimension(psize)); if (type == AnDisplay.DSP_MiniCallee || type == AnDisplay.DSP_MiniCaller || type == AnDisplay.DSP_MiniCallerCalleeSelf) { panel.setToolTipText((String) value); } // Set text color if (src_type == AT_COM) { fl.setForeground(AnVariable.CCOMP_COLOR); fl.setBackground(AnVariable.COMENTARY_COLOR); panel.setBackground(AnVariable.COMENTARY_COLOR); } else if ((type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2) && ((src_type == AT_SRC) || (src_type == AT_SRC_ONLY))) { fl.setForeground(AnVariable.DISRC_COLOR); } else if ((type == AnDisplay.DSP_DataLayout) && ((src_type == AT_SRC) || (src_type == AT_SRC_ONLY))) { fl.setFont(QuoteFont); } else if ((src_type == AT_QUOTE) || (src_type == AT_FUNC)) { fl.setForeground(AnVariable.QUOTE_COLOR); fl.setFont(QuoteFont); panel.setBackground(AnVariable.COMENTARY_COLOR); if (src_type == AT_FUNC) { if (srcRenderer != null) { if (srcRenderer.functionCallerCalleeAdded.get(row) == null) { srcRenderer.addFunctionByRow(row); } } else if (disRenderer != null) { if (disRenderer.functionCallerCalleeAdded.get(row) == null) { disRenderer.addFunctionByRow(row); } } } } if (column < tableModel.columnCount - 1) { Color borderColor; if (AnWindow.getInstance().getExperimentGroups().length == 1) { borderColor = AnEnvironment.TABLE_VERTICAL_GRID_METRIC_COLOR; } else { borderColor = AnEnvironment.TABLE_VERTICAL_GRID_METRIC_COMP_COLOR; } panel.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, borderColor)); } return panel; } // Check the source line type, return for empty metrics if ((src_type == AT_SRC_ONLY) || (src_type == AT_COM) || (src_type == AT_FUNC) || (src_type == AT_EMPTY) || (src_type == AT_DIS_ONLY)) { return panel; } // May contain multiple columns; value, time, and percent label = tableModel.getLabel(mcolumn); if (label == null) { return panel; } if (label.getClock() != -1.0) { panel.add( fl = new FListLabel( ((AnObject) value).toFormTime(label.getClock()), table, JLabel.RIGHT)); psize = new Dimension(col_w[1], rowHeight); fl.setPreferredSize(new Dimension(psize)); fl.setMinimumSize(new Dimension(psize)); fl.setMaximumSize(new Dimension(psize)); } if (label.getUnit() != null) { panel.add(fl = new FListLabel(((AnObject) value).toFormString(), table, JLabel.RIGHT)); psize = new Dimension(col_w[2], rowHeight); fl.setPreferredSize(new Dimension(psize)); fl.setMinimumSize(new Dimension(psize)); fl.setMaximumSize(new Dimension(psize)); } if (label.getTotal() != -1.0) { panel.add( fl = new FListLabel( ((AnObject) value).toPercent(label.getTotal()), table, JLabel.RIGHT)); psize = new Dimension(col_w[3], rowHeight); fl.setPreferredSize(new Dimension(psize)); fl.setMinimumSize(new Dimension(psize)); fl.setMaximumSize(new Dimension(psize)); } if (column < tableModel.columnCount - 1) { Color borderColor; if (AnWindow.getInstance().getExperimentGroups().length == 1) { if (tableModel .metricLabels[column] .getAnMetric() .getComd() .equals(tableModel.metricLabels[column + 1].getAnMetric().getComd())) { borderColor = AnEnvironment.TABLE_VERTICAL_GRID_COLOR; } else { borderColor = AnEnvironment.TABLE_VERTICAL_GRID_METRIC_COLOR; } } else { // Compare mode if (tableModel .metricLabels[column] .getAnMetric() .getComd() .equals(tableModel.metricLabels[column + 1].getAnMetric().getComd())) { if (tableModel.metricLabels[column].getAnMetric().getSubType() == tableModel.metricLabels[column + 1].getAnMetric().getSubType()) { borderColor = AnEnvironment.TABLE_VERTICAL_GRID_COLOR; } else { borderColor = AnEnvironment.TABLE_VERTICAL_GRID_ATTRIBUTE_COMP_COLOR; } } else { borderColor = AnEnvironment.TABLE_VERTICAL_GRID_METRIC_COMP_COLOR; } } panel.setBorder(BorderFactory.createMatteBorder(0, 0, 0, 1, borderColor)); } if (hasFocus) { // Override other border settings panel.setBorder(AnVariable.tableFocusBorder); } return panel; } } public void clearHistory() { if (navHistoryPool != null) { navHistoryPool.clearAll(); } } // Remove all rows & columns @Override public void removeAll() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { tableModel.removeAll(); } }); } // Remove all rows public void removeAllRows() { tableModel.removeAllRows(); } // Show message only public void showMessage(String msg) { showMessage(getErrorMessagePanel(msg)); } public void showMessage(Component component) { allHeaderPanel = null; setViewportView(component); } private JPanel getErrorMessagePanel(String text) { JPanel panel = new JPanel(new BorderLayout()); panel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); JLabel label = new JLabel(text); label.setHorizontalAlignment(JLabel.CENTER); label.getAccessibleContext().setAccessibleName(AnLocale.getString("Error message")); label.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Error message")); panel.add(label); return panel; } // Set table data public void setData( final MetricLabel[] label, final Object[][] data, final String[] names, final int[] src_type, final int org_row, final int name_col, final int sort_col) { this.names = names; this.orgRow = org_row; this.nameColumn = name_col; this.sortColumn = sort_col; switch (type) { case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_DisassemblyV2: if (disRenderer != null) { long sel_src = parent.window.getSelectedObject().getSelObj(AnDisplay.DSP_SourceSelectedObject, 0); long sel_instr = parent.window.getSelectedObject().getSelObj(AnDisplay.DSP_Disassembly, 0); int view_mode = parent.window.getSettings().getViewModeSetting().get().value(); disRenderer.maxSrcCachedNumber = 1; // XXXX don't cache disasm view data since there is no consistant row to content // map disRenderer.renderSrc(names, data, src_type, sel_src, view_mode); disRenderer.renderDis(data, src_type, sel_instr); // must be called after renderSrc } break; case AnDisplay.DSP_Source: case AnDisplay.DSP_SourceV2: if (srcRenderer != null) { long sel_src = parent.window.getSelectedObject().getSelObj(AnDisplay.DSP_SourceSelectedObject, 0); int view_mode = parent.window.getSettings().getViewModeSetting().get().value(); srcRenderer.renderSrc(names, data, src_type, sel_src, view_mode); } break; default: } AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { tableModel.setData(label, data, src_type, null, null); } }); } // Set table data public void setData( final MetricLabel[] metricLabels, final Object[][] data, final String[] names, final int[] src_type, final int org_row, final int name_col, final int sort_col, final int[][] marks, final int[][] marks_inc) { this.names = names; this.orgRow = org_row; this.nameColumn = name_col; this.sortColumn = sort_col; switch (type) { case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_DisassemblyV2: if (disRenderer != null) { long sel_src = parent.window.getSelectedObject().getSelObj(AnDisplay.DSP_SourceSelectedObject, 0); long sel_instr = parent.window.getSelectedObject().getSelObj(AnDisplay.DSP_Disassembly, 0); int view_mode = parent.window.getSettings().getViewModeSetting().get().value(); disRenderer.maxSrcCachedNumber = 1; // XXXX don't cache disasm view data since there is no consistant row to content // map disRenderer.renderSrc(names, data, src_type, sel_src, view_mode); disRenderer.renderDis(data, src_type, sel_instr); // must be called after renderSrc } break; case AnDisplay.DSP_Source: case AnDisplay.DSP_SourceV2: if (srcRenderer != null) { AnUtility.checkIPCOnWrongThread(false); long sel_src = parent.window.getSelectedObject().getSelObj(AnDisplay.DSP_SourceSelectedObject, 0); AnUtility.checkIPCOnWrongThread(true); int view_mode = parent.window.getSettings().getViewModeSetting().get().value(); srcRenderer.renderSrc(names, data, src_type, sel_src, view_mode); } break; default: } AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { // Set row selection if (org_row > 0 && org_row < table.getRowCount()) { table.changeSelection(org_row, 0, false, false); } tableModel.setData(metricLabels, data, src_type, marks, marks_inc); } }); } private Object[][] getTableData() { return tableModel.getTableData(); } // Set table column size public void setColumn(final int row_height) { this.rowHeight = row_height; tableModel.setColumn(); } // Set row visible; Place the actual update on the system event queue public void showSelectedRow() { AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { showSelectedRowNow(); } }); } /** Show selected row Note: use EventDispatchThread to call this method */ public void showSelectedRowNow() { final int vis_row; final Rectangle cellRect, visRect; vis_row = canSort ? tableModel.getSortRow(orgRow) : orgRow; cellRect = table.getCellRect(vis_row, 0, false); visRect = table.getVisibleRect(); cellRect.x = visRect.x; // if current view doesn't include selected row, scroll if (!visRect.contains(cellRect)) { // calculate middle based on selected row // being below or above current visible rows if (visRect.y < cellRect.y) { cellRect.y += visRect.height / 2; } else { cellRect.y -= visRect.height / 2; } table.scrollRectToVisible(cellRect); } // clear multiple selection if (table.getSelectedRowCount() > 1) { table.clearSelection(); } // Set row selection if (table.getSelectedRow() != vis_row) { table.changeSelection(vis_row, 0, false, false); } } // Get keyboard focus @Override public void requestFocus() { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { table.requestFocus(); } }); } public void clearSelection() { table.clearSelection(); } // Clear selected row public void clearSelectedRow() { table.clearSelection(); // Should reset the rows after clearSelection, otherwise repeated // recompute request event will be sent. orgRow = -1; } // Get scrolling value public int getScroll() { return getHorizontalScrollBar().getValue(); } // Set scrolling value; Place the actual update on the system event queue public void setScroll(final int scroll_pos) { SwingUtilities.invokeLater( new Runnable() { public void run() { getHorizontalScrollBar().setValue(scroll_pos); } }); } // Move columns public void moveColumn(final int from, final int to) { table.moveColumn(from, to); } // Set column width public void setColumnWidth(final int column, final int width) { final TableColumn col = table.getColumnModel().getColumn(column); if (col.getPreferredWidth() != width) { col.setPreferredWidth(columnWidth[column][0] = width); } } // Return column width info public int[][] getColumnWidth() { return columnWidth; } // Return raw height public int getRowHeight() { return rowHeight; } // Get string width public int stringWidth(final String str) { if (fontMetrics == null) { if (table.getGraphics() == null) { return 0; } fontMetrics = table.getGraphics().getFontMetrics(); } return fontMetrics.stringWidth(str); } public boolean canGoBack() { if (navHistoryPool == null) { return false; } SelObjInfo so = navHistoryPool.getHistory().getBack(); boolean can_go_back = navHistoryPool.getHistory().canGoBack(); boolean inError = anTable.getViewport().getView() != table; if (inError) { so = navHistoryPool.getHistory().getCurrent(); can_go_back = (so != null); } return can_go_back; } public boolean canGoForward() { if (navHistoryPool == null) { return false; } return navHistoryPool.getHistory().canGoForward(); } public void goBack() { String txt = STR_ACTION_BACK; SelObjInfo so = navHistoryPool.getHistory().getBack(); boolean can_go_back = navHistoryPool.getHistory().canGoBack(); boolean inError = anTable.getViewport().getView() != table; if (inError) { so = navHistoryPool.getHistory().getCurrent(); can_go_back = (so != null); } if (so != null && can_go_back) { NavigationHistoryUpdateAction nhua = new NavigationHistoryUpdateAction(txt, so.id, so.lineno, so.name); nhua.actionPerformed(null); } } public void goForward() { String txt = STR_ACTION_FORWARD; SelObjInfo so = navHistoryPool.getHistory().getForward(); if (so != null && navHistoryPool.getHistory().canGoForward()) { NavigationHistoryUpdateAction nhua = new NavigationHistoryUpdateAction(txt, so.id, so.lineno, so.name); nhua.actionPerformed(null); } } // Set current selected row and make it visible public void setSelectedRow(final int org_row) { this.orgRow = org_row; showSelectedRow(); // record history if (navHistoryPool != null && navHistoryPool.getHistory().enabled) { navHistoryPool.getHistory().goToSelected(org_row, false); } } // Experimental code // Set current selected row and make it visible public void setSelectedRowNow(final int org_row) { this.orgRow = org_row; AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { showSelectedRowNow(); } }); } // Return current selected row public int getSelectedRow() { return orgRow; } // Return current selected rows public int[] getSelectedRows() { return selected_indices; } // Find the part after the current row public int findAfter(final String str, final boolean next, boolean caseSensitive) { final int row, nr, last_line; row = tableModel.getSortRow(orgRow); nr = tableModel.getRowCount(); last_line = nr - 1; if (next) { if (row < last_line) { return tableModel.find(str, 1, row + 1, nr, caseSensitive); } } else { if (row > 0) { return tableModel.find(str, -1, row - 1, -1, caseSensitive); } } return -1; } // Find the part before the current row public int findBefore(final String str, final boolean next, boolean caseSensitive) { final int row, nr, last_line; row = tableModel.getSortRow(orgRow); if (row < 0) { return -1; } nr = tableModel.getRowCount(); last_line = nr - 1; if (next) { return tableModel.find(str, 1, 0, row + 1, caseSensitive); } else if (row <= last_line) { return tableModel.find(str, -1, last_line, row - 1, caseSensitive); } return -1; } // Sort table data public void sort(final int col) { if (canSort && (col >= 0)) { tableModel.sort(table.convertColumnIndexToModel(col)); } } // Listener to the event changed private final EventListenerList listenerList = new EventListenerList(); // Add a listener to the list public void addAnListener(final AnListener listener) { listenerList.add(AnListener.class, listener); } // Never used // // Remove a listener from the list // public void removeAnListener(final AnListener listener) { // listenerList.remove(AnListener.class, listener); // } // // Fire AnEvent to the listener public void fireAnEvent(final AnEvent event) { // System.out.println("AnTable fireAnEvent: " + event); AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { final Object[] listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == AnListener.class) { ((AnListener) listeners[i + 1]).valueChanged(event); } } } }); } // Events listener for row selecting, clicks on cell/row private final class CellHandler implements ListSelectionListener { public final void valueChanged(final ListSelectionEvent event) { final int first, last, new_row; final Rectangle cellRect, visRect; // for mini-c-c pane, only handle mouseclicked event if (type == AnDisplay.DSP_MiniCallee || type == AnDisplay.DSP_MiniCaller) { return; } if (event.getValueIsAdjusting()) { return; } // Which row is selected first = event.getFirstIndex(); if (first == -1) { return; } if (table.getSelectedRowCount() == 1) { // Single selection selectedRow = table.getSelectedRow(); } else { if (selectedRow == first) { last = event.getLastIndex(); // index of last row that may have changed // No change, happens when clicked on header (but now skipped for multi-sel) if ((selectedRow == last) && (type == AnDisplay.DSP_MiniCallee || type == AnDisplay.DSP_MiniCaller)) { return; } selectedRow = last; } else { selectedRow = first; } } // Update status with selected row(s) and total number of rows String selectedRows; if (table.getSelectedRowCount() == 1) { // Single selection selectedRows = "" + (table.getSelectedRow() + 1); } else { DefaultListSelectionModel dlsm = (DefaultListSelectionModel) event.getSource(); selectedRows = (dlsm.getMinSelectionIndex() + 1) + "-" + (dlsm.getMaxSelectionIndex() + 1); } AnWindow.getInstance() .getTableStatusHandle() .setText(selectedRows + "/" + table.getRowCount()); // Make it visible (setAutoscrolls has been turned off) cellRect = table.getCellRect(selectedRow, 0, false); visRect = table.getVisibleRect(); cellRect.x = visRect.x; if (!visRect.contains(cellRect)) { table.scrollRectToVisible(cellRect); } // Need to update summary display new_row = tableModel.getRow(selectedRow); // Get all selected indices ListSelectionModel listmodel = table.getSelectionModel(); if (listmodel.isSelectionEmpty() == false) { selected_indices = table.getSelectedRows(); } // Fire valueChanged event if (orgRow != new_row) { orgRow = new_row; // record history if (!(selectedRow != 0 && orgRow == 0)) { fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, orgRow, null)); if (navHistoryPool != null && navHistoryPool.getHistory().enabled) { navHistoryPool.getHistory().goToSelected(orgRow, true); } } } else { if ((type == AnDisplay.DSP_Lines) || (type == AnDisplay.DSP_PCs)) { fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, orgRow, null)); } } } } // -------------- Properties ---------------- // /** Implements menu item: Properties */ class SettingsAction extends AbstractAction { int index = 0; public SettingsAction(String what, int id) { super(what, AnUtility.gear_icon); index = id; } @Override public void actionPerformed(ActionEvent ev) { parent.window.getSettings().showDialog(index); } } // Events listener for selecting on already selected row for CallerCalleesDisp private final class CallHandler extends MouseAdapter implements ActionListener { @Override public void mouseClicked(final MouseEvent event) { if (event.getClickCount() == 2) { updateSelectedRow(table.rowAtPoint(event.getPoint())); } else { if (event.getButton() == MouseEvent.BUTTON3 && (type == AnDisplay.DSP_MiniCaller || type == AnDisplay.DSP_MiniCallee)) { return; } setSelectedRow(table.rowAtPoint(event.getPoint())); } } @Override public void actionPerformed(final ActionEvent event) { final String cmd = event.getActionCommand(); if (cmd.equals("SPACE")) { setSelectedRow(table.getSelectedRow()); } else if (cmd.equals("ENTER")) { // System.out.println("ENTER" + event.getSource()); int table_row = table.getSelectedRow(); if (table_row == -1) { return; } orgRow = tableModel.getRow(table_row); if (orgRow == -1) { return; } performDefaultAction(); } } public void setSelectedRow(final int table_row) { // CellHandler will handle this kind of event if (table_row == -1) { return; } orgRow = tableModel.getRow(table_row); if (orgRow < 0) { System.out.println("AnTable.CallHandler.setSelectedRow() org_row=" + orgRow); return; } fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, orgRow, null)); } } private void updateSelectedRow(final int table_row) { // CellHandler will handle this kind of event if (table_row == -1) { return; } orgRow = tableModel.getRow(table_row); if (orgRow < 0) { System.out.println("AnTable.CallHandler.updateSelectedRow() org_row=" + orgRow); return; } fireAnEvent( new AnEvent( anTable, AnEvent.EVT_COMPUTE, // AnEvent.EVT_UPDATE, orgRow, null)); } private final class TableAdapter extends MouseAdapter { @Override public void mouseClicked(final MouseEvent event) { final int table_row; // int src_type = model.getSrcType(table.getSelectedRow()); // never used if (event.getClickCount() == 2) { table_row = table.getSelectedRow(); if ((orgRow == -1) || (table_row == -1)) { return; } orgRow = tableModel.getRow(table_row); // Perform default action performDefaultAction(); // fireAnEvent(new AnEvent(anTable, AnEvent.EVT_NEWSRC, // orgRow, null)); } else { // Single click is already processed in CellHandler.valueChanged() when selection // changed // fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, // orgRow, null)); switch (type) { case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_DisassemblyV2: if (event.getClickCount() == 1 && event.getButton() == event.BUTTON1 && disRenderer != null) { int row = table.getSelectedRow(); // XXXX since source/disasm views are unsortable, we just // assume no need for model.getRow() disRenderer.updateSelectedRegs(row); boolean isJump = disRenderer.goToAddr(row); if (!isJump) { disRenderer.goToCallee(row, event); } disRenderer.goToSrcLine(row); disRenderer.caretLinePosition = -1; // reset caret position } case AnDisplay.DSP_Source: case AnDisplay.DSP_SourceV2: if (event.getClickCount() == 1 && event.getButton() == event.BUTTON1 && srcRenderer != null) { int row = table.getSelectedRow(); // XXXX since source/disasm views are unsortable, we just // assume no need for model.getRow() srcRenderer.goToCallee(row, event); srcRenderer.caretLinePosition = -1; // reset caret position } } } } } // Events listener for scrolling private final class ScrollHandler implements AdjustmentListener { @Override public void adjustmentValueChanged(final AdjustmentEvent event) { fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SCROLL, event.getValue(), null)); } } // Events listener for column switching private final class OldColumnHandler implements TableColumnModelListener { @Override public void columnMoved(final TableColumnModelEvent event) { final int from, to; from = event.getFromIndex(); to = event.getToIndex(); if (from == to) { return; } fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SWITCH, from, new Integer(to))); } @Override public void columnMarginChanged(final ChangeEvent event) { final TableColumn resizingColumn; final TableColumnModel cmodel; final int nc, width; int columnIndex; if (tableHeader == null) { return; } if ((resizingColumn = tableHeader.getResizingColumn()) == null) { return; } cmodel = table.getColumnModel(); nc = cmodel.getColumnCount(); for (columnIndex = 0; columnIndex < nc; columnIndex++) { if (cmodel.getColumn(columnIndex) == resizingColumn) { tableModel.fitColumnResize(columnIndex); if (type == AnDisplay.DSP_Callers) { width = resizingColumn.getWidth(); fireAnEvent(new AnEvent(anTable, AnEvent.EVT_RESIZE, columnIndex, new Integer(width))); } break; } } } @Override public void columnAdded(final TableColumnModelEvent event) {} @Override public void columnRemoved(final TableColumnModelEvent event) {} @Override public void columnSelectionChanged(final ListSelectionEvent event) {} } // Table Model for Function List public final class FListTableModel extends AbstractTableModel { // public for memobj/indexobj private MetricLabel[] metricLabels; private Object[][] data; private int[] src_type; private Row[] rows; private int rowCount; private int columnCount; public HashMap> hotMarks; public HashMap> hotMarks_inc; // Constructor public FListTableModel() { initData(); } public void updateTableHeaders() { boolean wrapMetricNames = AnTable.this.wrapMetricNames; if (AnTable.this.wrapMetricNames) { wrapMetricNames = AnWindow.getInstance().getSettings().getTableSettings().wrapMetricNames(); } allHeaderPanel = new AnTableHeaderPanel(AnTable.this, metricLabels, wrapMetricNames); setColumnHeaderView(allHeaderPanel); if (allHeaderPanel.getPreferredSize().height > 1 && hotGapPanel != null) { hotGapPanel.headerheightChanged(allHeaderPanel.getPreferredSize().height); } } public boolean isCellEditable(int row, int col) { int st = tableModel.getSrcType(row); if (st < 0) { st = -st; } // Just single string if (this.data[col][row] instanceof String) { if ((type != AnDisplay.DSP_DataLayout) && ((st == AT_SRC) || (st == AT_SRC_ONLY) || (st == AT_DIS) || (st == AT_DIS_ONLY))) { return (col == nameColumn); } } return false; } // Initialize data private void initData() { metricLabels = new MetricLabel[0]; data = new Object[1][0]; src_type = new int[0]; rows = new Row[0]; columnCount = 0; rowCount = 0; hotMarks = new HashMap>(); hotMarks_inc = new HashMap>(); } // Remove all rows & columns public final void removeAll() { initData(); fireTableChanged(null); } // Remove all rows public final void removeAllRows() { rowCount = 0; fireTableChanged(null); } // Set table data public final void setData( MetricLabel[] metricLabels, Object[][] data, int[] src_type, int[][] marks, int[][] marks_inc) { this.data = data; this.src_type = src_type; // Get numbers of rows/columns columnCount = metricLabels .length; // FIXUP: sometimes label == null if you quickly select/deselect metrics in // overview rowCount = data[0].length; // Initialize the rows elements rows = new Row[rowCount]; for (int i = 0; i < rowCount; i++) { rows[i] = new Row(i); } // for (int i=0; i< label.length; i ++) { // System.err.println("XXX Metric Label[" + i + "] = " + label[i].getText()); // } setLabel(metricLabels); if (marks != null && marks_inc != null) { for (int i = 0; i < marks[0].length; i++) { HashMap colMarks = hotMarks.get(marks[0][i]); if (colMarks == null) { colMarks = new HashMap(); hotMarks.put(marks[0][i], colMarks); } colMarks.put(marks[1][i], true); } for (int i = 0; i < marks_inc[0].length; i++) { HashMap colMarks = hotMarks_inc.get(marks_inc[0][i]); if (colMarks == null) { colMarks = new HashMap(); hotMarks_inc.put(marks_inc[0][i], colMarks); } colMarks.put(marks_inc[1][i], true); } } // New headers if (hasHeader) { updateTableHeaders(); } } private Object[][] getTableData() { // public for mem/idx objs return data; } // Returns line contents for selected row public String getSrcLine(final int row) { return (row != -1) ? (String) getValueAt(row, nameColumn) : null; } // Set table label only private void setLabel(final MetricLabel[] label) { this.metricLabels = label; // Use "AWT-EventQueue-0" thread to avoid race conditions AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { if (!columnsSaved) { columnWidth = new int[columnCount][4]; } if (columnCount != 0) { initWidth(); } // Update later for caller-callee display; need the maximum width if (hasSelect) { setColumn(); } } }); } // Set table columns for caller-callee display public final void setColumn() { if (columnCount != 0) { fitColumn(); table.setRowHeight(rowHeight); } fireTableChanged(null); } // Sizes the table columns to fit the available space. private void fitColumn() { int total_width, i; if (isSingle || (nameColumn < 0)) { return; } total_width = getViewportBorderBounds().width; for (i = 0; i < columnCount; i++) { if (i != nameColumn) { total_width -= columnWidth[i][0]; } } nameWidth = columnWidth[nameColumn][0]; if (columnWidth[nameColumn][0] < total_width) { columnWidth[nameColumn][0] = total_width; } } // Sizes the table columns to fit the available space. public final void fitColumnResize(final int index) { int ext_width; final TableColumnModel cm; final TableColumn column; if (isSingle || (index == nameColumn) || (nameColumn < 0)) { return; } ext_width = getViewportBorderBounds().width; cm = table.getColumnModel(); // Compute the extendable width of the name column for (int i = 0; i < columnCount; i++) { if (i != nameColumn) { ext_width -= cm.getColumn(i).getWidth(); } } // Extend the name column if (nameWidth < ext_width) { column = cm.getColumn(nameColumn); column.setPreferredWidth(ext_width); column.setWidth(ext_width); if (type == AnDisplay.DSP_Callers) { fireAnEvent(new AnEvent(anTable, AnEvent.EVT_RESIZE, nameColumn, new Integer(ext_width))); } } // if the user has manually adjusted the columns, note it & save the size if (index >= 0) { columnsSaved = true; final TableColumn col = cm.getColumn(index); columnWidth[index][0] = col.getWidth(); } } // Find the maximum column width for each field private void initWidth() { CellPanel cpanel = new CellPanel(table, true, FlowLayout.CENTER); cpanel.add(new FListLabel(AnVariable.all_chars, table, JLabel.LEFT)); rowHeight = cpanel.getPreferredSize().height; for (int i = 0; i < columnCount; i++) { int totalColumnWidth = 0; CellPanel cellPanel = new CellPanel(table, true, FlowLayout.CENTER); MetricLabel lb = metricLabels[i]; if (data[i] instanceof String[]) { FListLabel fListLabel = new FListLabel(lb.getMaxAnObject().toString(), table, JLabel.LEFT); int cellwidth = fListLabel.getPreferredSize().width; totalColumnWidth += cellwidth; cellPanel.add(fListLabel); columnWidth[i][1] = cellwidth; } else { if (lb.getClock() != -1.0) { FListLabel fListLabel = new FListLabel(lb.getMaxAnObject().toFormTime(lb.getClock()), table, JLabel.RIGHT); int cellwidth = fListLabel.getPreferredSize().width + 15; totalColumnWidth += cellwidth; columnWidth[i][1] = cellwidth; } if (lb.getUnit() != null) { FListLabel fListLabel = new FListLabel(lb.getMaxAnObject().toFormString(), table, JLabel.RIGHT); int cellwidth = fListLabel.getPreferredSize().width + 15; totalColumnWidth += cellwidth; columnWidth[i][2] = cellwidth; } if (lb.getTotal() != -1.0) { FListLabel fListLabel = new FListLabel(lb.getMaxAnObject().toPercent(lb.getTotal()), table, JLabel.RIGHT); int cellwidth = fListLabel.getPreferredSize().width + 15; totalColumnWidth += cellwidth; columnWidth[i][3] = cellwidth; } } columnWidth[i][0] = totalColumnWidth + 30; // Saves white space int minCellWidth; if (AnWindow.getInstance().getExperimentGroups().length == 1) { minCellWidth = getMinimumColumnWidth(); } else { minCellWidth = getMinimumColumnWidth() / 2; } if (columnWidth[i][0] < minCellWidth) { columnWidth[i][0] = minCellWidth; } } } @Override public final int getRowCount() { return rowCount; } @Override public final int getColumnCount() { return columnCount; } public final int getSrcType(final int r) { int res = AT_LIST; try { if ((src_type != null) && (r < rowCount)) { res = src_type[r]; } } catch (java.lang.ArrayIndexOutOfBoundsException e) { // CR 6999912 } return (res); } public final MetricLabel getLabel(final int c) { if (metricLabels != null) { if (metricLabels.length > c) { if (c >= 0) { return metricLabels[c]; } } } return null; } public final String getColumnName(final int c) { return ((c >= 0) && (c < columnCount)) ? metricLabels[c].getTitleLines()[0] + metricLabels[c].getTitleLines()[1] + metricLabels[c].getIcon() : ""; } // Needed for memobj/indexobj display public int getNameCol() { return nameColumn; } public final Object getValueAt(final int r, final int c) { int idx = 0; try { if (r < rowCount) { if (rows[r] == null) { return null; } idx = rows[r].index; } if ((c >= 0) && (c < columnCount) && (data[c] != null) && (idx < data[c].length)) { return data[c][idx]; } } catch (java.lang.ArrayIndexOutOfBoundsException e) { // CR 6999912 (desynchronization) return null; } return null; } // Find private final int find( String str, final int incr, int start, final int end, boolean caseSensitive) { String text; if (str == null) { // Search for High-Metric item while (start != end) { if (getSrcType(start) < 0) { return start; } start += incr; } } else if (nameColumn >= 0) { // Search string if (!caseSensitive) { str = str.toLowerCase(); } while ((start != -1) && (start != end)) { text = (String) getValueAt(start, nameColumn); if (text == null) { // see 23193063 return -1; } if (!caseSensitive) { text = text.toLowerCase(); } if ((text != null) && (text.indexOf(str) != -1)) { return getRow(start); } start += incr; } } return -1; } // Get the un-sorted row index public final int getRow(final int row) { if (row >= rows.length) { return 0; } return (rowCount == 0) ? row : rows[row].index; } // Get the sorted row index public final int getSortRow(final int row) { try { // For most case, non-sorted, it's just the original row index if ((rowCount == 0) || (row == -1) || (rows[row].index == row)) { return row; } for (int i = 0; i < rowCount; i++) { if (rows[i].index == row) { return i; } } } catch (java.lang.ArrayIndexOutOfBoundsException e) { // CR 6999912 (desynchronization) return row; } return row; } // Sort the table data public void sort(final int col) { // Sort by column sortColumn sortColumn = col; // if (type != AnDisplay.DSP_DLAYOUT) // Arrays.sort(rows); fireTableDataChanged(); // Repaint header, header's sort indicator changed if (hasHeader) { tableHeader.repaint(); } // Restore the selected row, should be after updating table data if (hasSelect) { showSelectedRow(); } } // Object which stores the un-sorted row index private final class Row implements Comparable { public final int index; public Row(final int index) { this.index = index; } public final int compareTo(final Object other) { final int col = (sortColumn >= 0) ? sortColumn : -sortColumn - 1; final int index_o = ((Row) other).index; final Object a = data[col][index]; final Object b = data[col][index_o]; return index - index_o; } } } // Table Column Model for Function List private final class FListColumnModel extends DefaultTableColumnModel { // Set column width here @Override public void moveColumn(int columnIndex, int newIndex) { if (columnIndex == newIndex) { return; } if (columnIndex < 0) { // HACK: why is columnIndex < 0? Sometimes it is if you quickly move a column. return; } super.moveColumn( columnIndex, newIndex); // To change body of generated methods, choose Tools | Templates. } public void addColumn(final TableColumn tc) { final int width; width = columnWidth[tc.getModelIndex()][0]; tc.setPreferredWidth(width); tc.setWidth(width); super.addColumn(tc); } // Workaround for (columnIndex>=tableColumns.size()), Swing sync problem public TableColumn getColumn(int columnIndex) { final int size = tableColumns.size(); TableColumn tc; if ((columnIndex < 0) || (columnIndex >= size)) { if (size > 0) { columnIndex = 0; } else { return new TableColumn(); } } if (size <= 0) { return new TableColumn(); } try { tc = (TableColumn) tableColumns.elementAt(columnIndex); } catch (java.lang.ArrayIndexOutOfBoundsException e) { tc = new TableColumn(); } return tc; } } public void sortTable(int colNum) { if (colNum >= tableModel.getColumnCount()) { return; } final int model_col = table.convertColumnIndexToModel(colNum); tableModel.sort(model_col); AnEvent ev = new AnEvent(anTable, AnEvent.EVT_SORT, model_col, type, new Integer(colNum)); fireAnEvent(ev); table.requestFocus(); } /* * Update tables in Callers-Callees tab * Possible actions: * Prepend - insert selected caller at the beginning of the stack fragment * Append - add selected callee to the end of the stack fragment * Recenter - replace the stack fragment with the selected function * Remove - remove selected function from the stack fragment * Reset - replace the stack fragment with the Selected Object * Set Head - remove all functions above the selected function from the stack fragment * Set Tail - remove all functions below the selected function from the stack fragment * Set Filter: Name in Stack - set the selected function name as filter * Set Filter: Call Path in Stack - set the call path to the selected function as filter * Set Filter: Function in Stack - set the selected function as filter * Set Filter: Function is Leaf - set the selected function as filter */ protected void updateAnTable(String actionName) { updateTable(null, null, actionName); if (!(parent instanceof IOView) && !(parent instanceof HeapView)) { parent.updateToolBar(); parent.syncSrcDisWin(); } } private void updateTable(String shortName, String longName, String actionName) { if ((parent != null) && ((parent instanceof CallerCalleesView) || (parent instanceof FuncListDisp))) { if (actionName.equals(STR_ACTION_REMOVE_ALL_FILTERS)) { parent.window.getFilters().addClause(FilterClause.getNoFiltersClause(), false); return; } if (actionName.equals(STR_ACTION_UNDOFILTER)) { parent.window.getFilters().undoLastFilteraction(); return; } if (actionName.equals(STR_ACTION_REDOFILTER)) { parent.window.getFilters().redoLastFilteraction(); return; } if (actionName.equals(STR_ACTION_SHOW_SELECTED_FUNCTION)) { if (orgRow >= 0) { fireAnEvent( new AnEvent( anTable, AnEvent.EVT_COMPUTE, // AnEvent.EVT_UPDATE, orgRow, null)); } return; } if (actionName.equals(STR_ACTION_SHOW_SOURCE)) { parent.window.setSelectedView(AnDisplay.DSP_Source); return; } if (actionName.equals(STR_ACTION_SHOW_CALLEE_SOURCE) || actionName.equals(STR_ACTION_SHOW_CALLER_SOURCE)) { if (parent.parent_type == AnDisplay.DSP_SourceDisassembly || parent.parent_type == AnDisplay.DSP_DualSource) { parent.window.setSelectedView(parent.parent_type); } else { parent.window.setSelectedView(AnDisplay.DSP_Source); } return; } if (actionName.equals(STR_ACTION_SHOW_CALLEE_DISASM) || actionName.equals(STR_ACTION_SHOW_CALLER_DISASM)) { if (parent.parent_type == AnDisplay.DSP_SourceDisassembly) { parent.window.setSelectedView(parent.parent_type); } else { parent.window.setSelectedView(AnDisplay.DSP_Disassembly); } return; } if (actionName.equals(STR_ACTION_SHOW_DISASM)) { parent.window.setSelectedView(AnDisplay.DSP_Disassembly); return; } if (actionName.equals(STR_ACTION_CUSTOM_FILTER)) { parent.window.getFilters().showCustomFilterDialog(); return; } boolean setFilter = false; long ID = parent.window.getSelectedObject().getSelObjV2("FUNCTION"); long[] cstack = null; String clause = "(" + ID + ")"; String stack = parent.window.getSettings().getViewModeSetting().getStackName(); if (parent instanceof CallerCalleesView) { cstack = ((CallerCalleesView) parent).getStack(); } if (actionName.equals(FILTER_SIMILARLY_NAMED_ACTION_NAME)) { setFilter = true; clause = parent.window.getObjNameV2(ID); clause = getFunctionName(clause); clause = "(FNAME(\".*" + clause + ".*\") SOME IN " + stack + ")"; } else if (actionName.equals(FILTER_WITH_SELECTED_JGROUP_ACTION_NAME)) { setFilter = true; int namecol = getTableModel().getNameCol(); for (int selrow : anTable.getSelectedRows()) { String name = (String) getTableModel().data[namecol][selrow]; if (name.contains("JThread")) { int indx0 = name.indexOf("Group"); int indx1 = name.indexOf("'", indx0); int indx2 = name.indexOf(",", indx1 + 1); if (indx2 == -1) { indx2 = name.lastIndexOf("'"); } else { indx2--; } clause = name.substring(indx1 + 1, indx2); break; } } clause = "(JGROUP(\"" + clause + "\") SOME IN JTHREAD)"; } else if (actionName.equals(FILTER_WITH_SELECTED_JPARENT_ACTION_NAME)) { setFilter = true; int namecol = getTableModel().getNameCol(); for (int selrow : anTable.getSelectedRows()) { String name = (String) getTableModel().data[namecol][selrow]; if (name.contains("JThread")) { int indx0 = name.indexOf("Parent"); int indx1 = name.indexOf("'", indx0); int indx2 = name.indexOf(",", indx1 + 1); if (indx2 == -1) { indx2 = name.lastIndexOf("'"); } else { indx2--; } clause = name.substring(indx1 + 1, indx2); break; } } clause = "(JPARENT(\"" + clause + "\") SOME IN JTHREAD)"; } else if (actionName.equals(FILTER_SELECTED_FUNCTION_ACTION_NAME) || actionName.equals(FILTER_SELECTED_FUNCTIONS_ACTION_NAME)) { setFilter = true; if ((type == AnDisplay.DSP_Callers) || (type == AnDisplay.DSP_CallerCalleeSelf) || (type == AnDisplay.DSP_Callees)) { // Special case for Callers-Callees view (CR 25631707) if (selected_indices.length > 1) { clause = "(" + clause + " SOME IN " + stack + ")"; } else { clause = "(" + clause + " IN " + stack + ")"; } } else { clause = getFilterForSelectedObjects(stack); } } else if (actionName.equals(FILTER_SELECTED_LINE_ACTION_NAME) || actionName.equals(FILTER_SELECTED_LINES_ACTION_NAME)) { setFilter = true; clause = getFilterForSelectedObjects(stack + "L"); } else if (actionName.equals(FILTER_SELECTED_PC_ACTION_NAME) || actionName.equals(FILTER_SELECTED_PCS_ACTION_NAME)) { setFilter = true; clause = getFilterForSelectedObjects(stack + "I"); } else if (actionName.equals(FILTER_NOT_SELECTED_FUNCTION_ACTION_NAME) || actionName.equals(FILTER_NOT_SELECTED_FUNCTIONS_ACTION_NAME)) { setFilter = true; clause = String.format("(!%s)", getFilterForSelectedObjects(stack)); } else if (actionName.equals(FILTER_NOT_SELECTED_LINE_ACTION_NAME) || actionName.equals(FILTER_NOT_SELECTED_LINES_ACTION_NAME)) { setFilter = true; clause = String.format("(!%s)", getFilterForSelectedObjects(stack + "L")); } else if (actionName.equals(FILTER_NOT_SELECTED_PC_ACTION_NAME) || actionName.equals(FILTER_NOT_SELECTED_PCS_ACTION_NAME)) { setFilter = true; clause = String.format("(!%s)", getFilterForSelectedObjects(stack + "I")); } else if (actionName.equals(FILTER_LEAF_FUNCTION_ACTION_NAME) || actionName.equals(FILTER_LEAF_FUNCTIONS_ACTION_NAME)) { setFilter = true; if ((type == AnDisplay.DSP_Callers) || (type == AnDisplay.DSP_CallerCalleeSelf) || (type == AnDisplay.DSP_Callees)) { // Special case for Callers-Callees view (CR 25644886) clause = "((" + stack + "+0) IN " + clause + ")"; } else { clause = String.format("((%s+0) IN %s)", stack, get_list_of_selected_objects()); } } else if (actionName.equals(FILTER_CALLSTACK_FRAGMENT_ACTION_NAME)) { setFilter = true; if ((cstack != null) && (cstack.length > 0)) { clause = "("; for (int i = 0; ; ) { clause = clause + cstack[i]; if (++i < cstack.length) { clause = clause + ","; } else { clause = clause + ")"; break; } } clause = "(" + clause + " ORDERED IN " + stack + ")"; } } else if (actionName.equals(FILTER_NOT_CALLSTACK_FRAGMENT_ACTION_NAME)) { setFilter = true; if ((cstack != null) && (cstack.length > 0)) { clause = "("; for (int i = 0; ; ) { clause = clause + cstack[i]; if (++i < cstack.length) { clause = clause + ","; } else { clause = clause + ")"; break; } } clause = "(!(" + clause + " ORDERED IN " + stack + "))"; } } else if (actionName.equals(FILTER_WITH_SELECTED_FILE_ACTION_NAME)) { long ids[] = AnWindow.getInstance().getIOView().getSelectedIds(selected_indices, AnDisplay.DSP_IO); if (ids != null && ids.length > 0) { long[] vfds = parent.window.getSelectedObject().getSelObjsIO(ids, AnDisplay.DSP_IO); if (vfds != null && vfds.length > 0) { StringBuffer strBuf = new StringBuffer(); strBuf.append("(IOVFD IN ("); for (int i = 0; i < vfds.length; i++) { strBuf.append(vfds[i]); if (i + 1 < vfds.length) { strBuf.append(","); } } strBuf.append("))"); clause = strBuf.toString(); setFilter = true; } } } else if (actionName.equals(FILTER_NOT_SELECTED_FILE_ACTION_NAME)) { long ids[] = AnWindow.getInstance().getIOView().getSelectedIds(selected_indices, AnDisplay.DSP_IO); if (ids != null && ids.length > 0) { long[] vfds = parent.window.getSelectedObject().getSelObjsIO(ids, AnDisplay.DSP_IO); if (vfds != null && vfds.length > 0) { StringBuffer strBuf = new StringBuffer(); strBuf.append("!(IOVFD IN ("); for (int i = 0; i < vfds.length; i++) { strBuf.append(vfds[i]); if (i + 1 < vfds.length) { strBuf.append(","); } } strBuf.append("))"); clause = strBuf.toString(); setFilter = true; } } } else if (actionName.equals(FILTER_WITH_SELECTED_IOVFD_ACTION_NAME)) { long ids[] = AnWindow.getInstance() .getIOView() .getSelectedIds(selected_indices, AnDisplay.DSP_IOFileDescriptors); if (ids != null && ids.length > 0) { long[] vfds = parent.window.getSelectedObject().getSelObjsIO(ids, AnDisplay.DSP_IOFileDescriptors); if (vfds != null && vfds.length > 0) { StringBuffer strBuf = new StringBuffer(); strBuf.append("(IOVFD IN ("); for (int i = 0; i < vfds.length; i++) { strBuf.append(vfds[i]); if (i + 1 < vfds.length) { strBuf.append(","); } } strBuf.append("))"); clause = strBuf.toString(); setFilter = true; } } } else if (actionName.equals(FILTER_NOT_SELECTED_IOVFD_ACTION_NAME)) { long ids[] = AnWindow.getInstance() .getIOView() .getSelectedIds(selected_indices, AnDisplay.DSP_IOFileDescriptors); if (ids != null && ids.length > 0) { long[] vfds = parent.window.getSelectedObject().getSelObjsIO(ids, AnDisplay.DSP_IOFileDescriptors); if (vfds != null && vfds.length > 0) { StringBuffer strBuf = new StringBuffer(); strBuf.append("!(IOVFD IN ("); for (int i = 0; i < vfds.length; i++) { strBuf.append(vfds[i]); if (i + 1 < vfds.length) { strBuf.append(","); } } strBuf.append("))"); clause = strBuf.toString(); setFilter = true; } } } else if (actionName.equals(FILTER_WITH_SELECTED_IOSTACK_ACTION_NAME)) { long stackIds[] = AnWindow.getInstance() .getIOView() .getSelectedIds(selected_indices, AnDisplay.DSP_IOCallStacks); if (stackIds != null && stackIds.length > 0) { StringBuffer strBuf1 = new StringBuffer(); strBuf1.append("("); for (int j = 0; j < stackIds.length; j++) { StringBuffer strBuf2 = new StringBuffer(); strBuf2.append("(("); strBuf2.append(stackIds[j]); strBuf2.append(")"); strBuf2.append(" == STACKID )"); setFilter = true; if (strBuf2.length() > 0) { strBuf1.append(strBuf2.toString()); } if ((j + 1 < stackIds.length) && (strBuf2.length() > 0)) { strBuf1.append(" || "); } } strBuf1.append(")"); clause = strBuf1.toString(); } } else if (actionName.equals(FILTER_NOT_SELECTED_IOSTACK_ACTION_NAME)) { long stackIds[] = AnWindow.getInstance() .getIOView() .getSelectedIds(selected_indices, AnDisplay.DSP_IOCallStacks); if (stackIds != null && stackIds.length > 0) { StringBuffer strBuf1 = new StringBuffer(); strBuf1.append("(!("); for (int j = 0; j < stackIds.length; j++) { StringBuffer strBuf2 = new StringBuffer(); strBuf2.append("(("); strBuf2.append(stackIds[j]); strBuf2.append(")"); strBuf2.append(" == STACKID )"); setFilter = true; if (strBuf2.length() > 0) { strBuf1.append(strBuf2.toString()); } if ((j + 1 < stackIds.length) && (strBuf2.length() > 0)) { strBuf1.append(" || "); } } strBuf1.append("))"); clause = strBuf1.toString(); } } else if (actionName.equals(FILTER_WITH_SELECTED_HEAPSTACK_ACTION_NAME)) { long stackIds[] = AnWindow.getInstance() .getHeapView() .getSelectedIds(selected_indices, AnDisplay.DSP_Heap); if (stackIds != null && stackIds.length > 0) { StringBuffer strBuf1 = new StringBuffer(); strBuf1.append("("); for (int j = 0; j < stackIds.length; j++) { StringBuffer strBuf2 = new StringBuffer(); strBuf2.append("(("); strBuf2.append(stackIds[j]); strBuf2.append(")"); strBuf2.append(" == STACKID )"); setFilter = true; if (strBuf2.length() > 0) { strBuf1.append(strBuf2.toString()); } if ((j + 1 < stackIds.length) && (strBuf2.length() > 0)) { strBuf1.append(" || "); } } strBuf1.append(")"); clause = strBuf1.toString(); } } else if (actionName.equals(FILTER_NOT_SELECTED_HEAPSTACK_ACTION_NAME)) { long stackIds[] = AnWindow.getInstance() .getHeapView() .getSelectedIds(selected_indices, AnDisplay.DSP_Heap); if (stackIds != null && stackIds.length > 0) { StringBuffer strBuf1 = new StringBuffer(); strBuf1.append("(!("); for (int j = 0; j < stackIds.length; j++) { StringBuffer strBuf2 = new StringBuffer(); strBuf2.append("(("); strBuf2.append(stackIds[j]); strBuf2.append(")"); strBuf2.append(" == STACKID )"); setFilter = true; if (strBuf2.length() > 0) { strBuf1.append(strBuf2.toString()); } if ((j + 1 < stackIds.length) && (strBuf2.length() > 0)) { strBuf1.append(" || "); } } strBuf1.append("))"); clause = strBuf1.toString(); } } else if (actionName.equals(FILTER_WITH_SELECTED_HEAPACTIVESTACK_ACTION_NAME)) { long stackId = 0; long stackIds[] = AnWindow.getInstance() .getHeapView() .getSelectedIds(selected_indices, AnDisplay.DSP_Heap); if (stackIds != null && stackIds.length > 0) { // Only one stack id can be selected. stackId = stackIds[0]; } long peakTimestamp = parent.window.getSelectedObject().getSelObjHeapTimestamp(stackId); // Get the user experiment id. Set the stackId to zero for Total Hist obj int userExpId = parent.window.getSelectedObject().getSelObjHeapUserExpId(0); StringBuffer strBuf1 = new StringBuffer(); if (peakTimestamp > 0) { strBuf1.append( "!((TSTAMP_HI < " + peakTimestamp + ") || (TSTAMP_LO > " + peakTimestamp + ")) && (( EXPID==" + userExpId + " ))"); setFilter = true; clause = strBuf1.toString(); } } else if (actionName.equals(FILTER_WITH_SELECTED_HEAPLEAKEDSTACK_ACTION_NAME)) { StringBuffer strBuf1 = new StringBuffer(); strBuf1.append("( HLEAKED > 0 )"); setFilter = true; clause = strBuf1.toString(); } else if (actionName.equals(FILTER_NOT_SELECTED_HEAPLEAKEDSTACK_ACTION_NAME)) { StringBuffer strBuf1 = new StringBuffer(); strBuf1.append("(( HSIZE > 0 ) && ( HLEAKED == 0))"); setFilter = true; clause = strBuf1.toString(); } if (setFilter) { // parent.window.filter.showDialog(); // parent.window.filter.setSelectedTab(1); // Select advanced filter tab parent .window .getFilters() .addClause( shortName, longName, clause, FilterClause.Kind.STANDARD); // Put the string in text field return; } } if (gap != null) { if (actionName.equals(gap.STR_ACTION_NEXT_HOT_LINE)) { gap.HG_Next_Hot_Line(); return; } if (actionName.equals(gap.STR_ACTION_NEXT_NZ_LINE)) { gap.HG_Next_NZ_Line(); return; } if (actionName.equals(gap.STR_ACTION_PREV_HOT_LINE)) { gap.HG_Prev_Hot_Line(); return; } if (actionName.equals(gap.STR_ACTION_PREV_NZ_LINE)) { gap.HG_Prev_NZ_Line(); return; } } if ((parent != null) && ((parent.type == AnDisplay.DSP_IndexObject || parent.type == AnDisplay.DSP_MemoryObject))) { // Threads, CPUs, Samples, Seconds tabs AnUtility.checkIPCOnWrongThread(false); setStandardFilter(shortName, longName, actionName); // IPC AnUtility.checkIPCOnWrongThread(true); } // XXX: AWT - Everything below can be done on AWT thread, // so this code should be moved up to the beginning of this method int disp_type = type; if (parent.parent_type == AnDisplay.DSP_SourceDisassembly || parent.parent_type == AnDisplay.DSP_DualSource) { disp_type = parent.parent_type; } if ((disp_type == AnDisplay.DSP_Source) || (disp_type == AnDisplay.DSP_SourceV2) || (disp_type == AnDisplay.DSP_Disassembly) || (disp_type == AnDisplay.DSP_DisassemblyV2) || (disp_type == AnDisplay.DSP_SourceDisassembly) || (disp_type == AnDisplay.DSP_DualSource)) { if (actionName.equals(STR_ACTION_BACK) || actionName.equals(STR_ACTION_FORWARD)) { parent.window.setSelectedView(disp_type); return; } } // Fire events AnEvent ev; if (actionName.equals(STR_ACTION_BACK)) { ev = new AnEvent(anTable, AnEvent.EVT_BACK, orgRow, null); } else if (actionName.equals(STR_ACTION_FORWARD)) { ev = new AnEvent(anTable, AnEvent.EVT_FORWARD, orgRow, null); } else if (actionName.equals(STR_ACTION_SETHEAD)) { ev = new AnEvent(anTable, AnEvent.EVT_SETHEAD, orgRow, null); } else if (actionName.equals(STR_ACTION_SETTAIL)) { ev = new AnEvent(anTable, AnEvent.EVT_SETTAIL, orgRow, null); } else if (actionName.equals(STR_ACTION_RECENTER)) { ev = new AnEvent(anTable, AnEvent.EVT_SET, orgRow, null); } else if (actionName.equals(STR_ACTION_RESET)) { ev = new AnEvent(anTable, AnEvent.EVT_RESET, orgRow, null); } else if (actionName.equals(STR_ACTION_COPY_ALL)) { ev = new AnEvent(anTable, AnEvent.EVT_COPY_ALL, orgRow, null); } else if (actionName.equals(STR_ACTION_COPY_SEL)) { ev = new AnEvent(anTable, AnEvent.EVT_COPY_SEL, orgRow, null); } else { ev = new AnEvent(anTable, AnEvent.EVT_UPDATE, orgRow, null); } fireAnEvent(ev); table.requestFocus(); } private String get_list_of_selected_objects() { AnUtility.checkIPCOnWrongThread(false); String sObjs = ((FuncListDisp) parent).composeFilterClause(parent.type, parent.subtype, selected_indices); AnUtility.checkIPCOnWrongThread(true); if (sObjs == null) { // Should never happen sObjs = "0"; } String pattern1 = "(LEAF IN ("; if (sObjs.startsWith(pattern1)) { String pattern2 = "))"; if (sObjs.endsWith(pattern2)) { int c1 = pattern1.length() - 1; int c2 = sObjs.length() - 1; sObjs = sObjs.substring(c1, c2); } } return sObjs; } private String getFilterForSelectedObjects(final String stackName) { String sObjs = get_list_of_selected_objects(); AnUtility.checkIPCOnWrongThread(false); String fltr = String.format("(%s SOME IN %s)", sObjs, stackName); return fltr; } /** * Get Function Name * * @param s - a function name with arguments * @return fs - function name */ private String getFunctionName(String s) { String fs = s; if (null != s) { int i = s.indexOf("("); if (i >= 0) { // Everything that is inside (...) is not a part of function name fs = s.substring(0, i); } } return fs; } /** * Sets Standard Filter for Index Object tabs: Threads, CPUs, Samples, Seconds * * @param actionName */ private void setStandardFilter(String shortName, String longName, String actionName) { boolean setFilter = false; String clause = null; if (selected_indices.length > 0) { clause = parent.window.composeFilterClause(parent.type, parent.subtype, selected_indices); if (actionName.equals(FILTER_WITH_SELECTED_ITEMS_ACTION_NAME)) { setFilter = true; } if (actionName.equals(FILTER_WITHOUT_SELECTED_ITEMS_ACTION_NAME)) { clause = "(!" + clause + ")"; setFilter = true; } } if (actionName.equals(STR_ACTION_REMOVE_ALL_FILTERS)) { clause = "1"; setFilter = true; } if (setFilter) { // parent.window.filter.showDialog(); // parent.window.filter.setSelectedTab(1); // Select advanced filter tab parent .window .getFilters() .addClause( shortName, longName, clause, FilterClause.Kind.STANDARD); // Put the string in text field return; } } private String getSelectedViewDisplayName() { String ret = "Table"; if (parent != null && parent.window != null) { ret = parent.window.getSelectedView().getDisplayName(); } return ret; } public JPopupMenu initPopup(boolean filterOnly) { JPopupMenu popup = new JPopupMenu(); boolean row_selected = false; int row = table.getSelectedRow(); if (row >= 0) { row_selected = true; } String viewName = getSelectedViewDisplayName(); if (filterOnly) { addFilterPopup(filterOnly, popup, type, viewName, row_selected); } else { addAllPopup(filterOnly, popup, type, viewName, row, row_selected); } return popup; } private void addAllPopup( boolean filterOnly, JPopupMenu popup, int type, String viewName, int row, boolean row_selected) { AccessibleContext ac; UpdateAction ua; JMenuItem mi; JMenu me; String txt; // Add default action if ((type == AnDisplay.DSP_Functions) || (type == AnDisplay.DSP_Lines)) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } // Add "Show Source" action txt = STR_ACTION_SHOW_SOURCE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); // popup.addSeparator(); // Add "Show Disassembly" action txt = STR_ACTION_SHOW_DISASM; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); } else if (type == AnDisplay.DSP_PCs) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } // Add "Show Disassembly" action txt = STR_ACTION_SHOW_DISASM; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); } else if ((type == AnDisplay.DSP_Source) || (type == AnDisplay.DSP_SourceV2) || (type == AnDisplay.DSP_Disassembly) || (type == AnDisplay.DSP_DisassemblyV2)) { SrcRenderer renderer = null; if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2) { renderer = srcRenderer; } else { renderer = disRenderer; } // show a list if lines in multiple functions that are chosen int num = table.getSelectedRows().length; HashMap funcMap = new HashMap(); int funcNum = 0; if (num > 0) { for (int i = 0; i < num; i++) { int r = table.getSelectedRows()[i]; if (renderer.functionId != null && r > 0 && r <= renderer.functionId.size()) { Long funcId = renderer.functionId.get(r); if (funcId != 0 && funcMap.get(funcId) == null) { funcMap.put(funcId, r); } } } for (Long idx : funcMap.keySet()) { int r = funcMap.get(idx).intValue(); String funcName = renderer.getFunction(r); if (funcName != null) { funcNum++; } } } if ((type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2) || (type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2)) { txt = STR_ACTION_BACK; SelObjInfo so = navHistoryPool.getHistory().getBack(); boolean can_go_back = navHistoryPool.getHistory().canGoBack(); boolean inError = anTable.getViewport().getView() != table; if (inError) { so = navHistoryPool.getHistory().getCurrent(); can_go_back = (so != null); } if (so != null) { NavigationHistoryUpdateAction nhua = new NavigationHistoryUpdateAction(txt, so.id, so.lineno, so.name); mi = new JMenuItem(nhua); } else { mi = new JMenuItem(txt); } ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(can_go_back); mi.setAccelerator(KeyboardShortcuts.backwardActionShortcut); popup.add(mi); txt = STR_ACTION_FORWARD; so = navHistoryPool.getHistory().getForward(); if (so != null) { NavigationHistoryUpdateAction nhua = new NavigationHistoryUpdateAction(txt, so.id, so.lineno, so.name); mi = new JMenuItem(nhua); } else { mi = new JMenuItem(txt); } ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(navHistoryPool.getHistory().canGoForward()); mi.setAccelerator(KeyboardShortcuts.forwardActionShortcut); popup.add(mi); if (popup.getComponentCount() > 0) { popup.addSeparator(); } // add "show callee source/disasm" int[] selectedRows = table.getSelectedRows(); ArrayList callsiteRows = new ArrayList(); for (int i = 0; i < selectedRows.length; i++) { int sr = selectedRows[i]; ArrayList calleeFuncs = renderer.calleeInfo.get(sr); if (calleeFuncs != null) { callsiteRows.add(sr); } } JMenuItem mi_dis = null; JMenu me_dis = null; if (callsiteRows.size() > 0) { txt = STR_ACTION_SHOW_CALLEE_SOURCE; // XXXX if the position is changed, please update the // offset in srcRenderer.goToCallee too String txt_dis = STR_ACTION_SHOW_CALLEE_DISASM; me = new JMenu(new UpdateAction(txt)); me_dis = new JMenu(new UpdateAction(txt_dis)); me.setEnabled( row_selected && (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2 || parent.parent_type != AnDisplay.DSP_SourceDisassembly)); JMenu cur_me = me; me_dis.setEnabled( row_selected && (type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2 || parent.parent_type != AnDisplay.DSP_SourceDisassembly)); JMenu cur_me_dis = me_dis; int num_items = 0; HashMap calleeSeen = new HashMap(); for (int i = 0; i < callsiteRows.size(); i++) { int sr = callsiteRows.get(i); ArrayList calleeFuncs = renderer.calleeInfo.get(sr); if (calleeFuncs == null) { continue; } Collections.sort(calleeFuncs); boolean seperaterAdded = false; for (int j = 0; j < calleeFuncs.size(); j++) { SelObjInfo fi = calleeFuncs.get(j); if (calleeSeen.get(fi.id) != null && calleeSeen.get(fi.id) == true) { continue; } if (i > 0 && !seperaterAdded) { cur_me.addSeparator(); cur_me_dis.addSeparator(); seperaterAdded = true; } calleeSeen.put(fi.id, true); NavigationUpdateAction nua = new NavigationUpdateAction(txt, fi.id, fi.lineno); NavigationUpdateAction nua_dis = new NavigationUpdateAction(txt_dis, fi.id, fi.lineno); mi = new JMenuItem(); mi.setAction(nua); mi.setText(fi.name); cur_me.add(mi); mi_dis = new JMenuItem(); mi_dis.setAction(nua_dis); mi_dis.setText(fi.name); cur_me_dis.add(mi_dis); num_items++; if (num_items > 0 && num_items % 20 == 0 && !(j == calleeFuncs.size() - 1 && i == callsiteRows.size() - 1)) { JMenu more_me = new JMenu(AnLocale.getString("more...")); cur_me.add(more_me); cur_me = more_me; JMenu more_me_dis = new JMenu(AnLocale.getString("more...")); cur_me_dis.add(more_me_dis); cur_me_dis = more_me_dis; } } } if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2) { popup.add(me); } else if (type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2) { popup.add(me_dis); } } else { if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2) { mi = new JMenuItem(STR_ACTION_SHOW_CALLEE_SOURCE); mi.setEnabled(false); popup.add(mi); } if (type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2) { mi = new JMenuItem(STR_ACTION_SHOW_CALLEE_DISASM); mi.setEnabled(false); popup.add(mi); } } if (popup.getComponentCount() > 0) { popup.addSeparator(); } // add "show caller source/disasm" txt = STR_ACTION_SHOW_CALLER_SOURCE; String txt_dis = STR_ACTION_SHOW_CALLER_DISASM; HashMap callerSeen = new HashMap(); me = new JMenu(new UpdateAction(txt)); me.setEnabled( row_selected && (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2 || parent.parent_type != AnDisplay.DSP_SourceDisassembly)); JMenu cur_me = me; me_dis = new JMenu(new UpdateAction(txt_dis)); me_dis.setEnabled( row_selected && (type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2 || parent.parent_type != AnDisplay.DSP_SourceDisassembly)); JMenu cur_me_dis = me_dis; int num_items = 0; int num_funcs = 0; for (Long idx : funcMap.keySet()) { ArrayList callerFuncs = renderer.callerInfo.get(idx.longValue()); if (callerFuncs == null) { continue; } Collections.sort(callerFuncs); boolean seperaterAdded = false; for (int j = 0; j < callerFuncs.size(); j++) { SelObjInfo fi = callerFuncs.get(j); if (callerSeen.get(fi.name) != null && callerSeen.get(fi.name) == true) { continue; } if (num_funcs > 0 && !seperaterAdded) { cur_me.addSeparator(); cur_me_dis.addSeparator(); seperaterAdded = true; } callerSeen.put(fi.name, true); NavigationUpdateAction nua = new NavigationUpdateAction(txt, fi.id, fi.lineno); mi = new JMenuItem(); mi.setAction(nua); mi.setText(fi.name); cur_me.add(mi); NavigationUpdateAction nua_dis = new NavigationUpdateAction(txt_dis, fi.id, fi.lineno); mi_dis = new JMenuItem(); mi_dis.setAction(nua_dis); mi_dis.setText(fi.name); cur_me_dis.add(mi_dis); num_items++; if (num_items > 0 && num_items % 20 == 0 && !(j == callerFuncs.size() - 1 && num_funcs == funcMap.size() - 1)) { JMenu more_me = new JMenu(AnLocale.getString("more...")); cur_me.add(more_me); cur_me = more_me; JMenu more_me_dis = new JMenu(AnLocale.getString("more...")); cur_me_dis.add(more_me_dis); cur_me_dis = more_me_dis; } } num_funcs++; } if (num_items > 0) { if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2) { popup.add(me); } else if (type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2) { popup.add(me_dis); } } else { if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2) { mi = new JMenuItem(STR_ACTION_SHOW_CALLER_SOURCE); mi.setEnabled(false); popup.add(mi); } if (type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2) { mi = new JMenuItem(STR_ACTION_SHOW_CALLER_DISASM); mi.setEnabled(false); popup.add(mi); } } } if ((type == AnDisplay.DSP_Source) || (type == AnDisplay.DSP_SourceV2)) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } // Add "Show Disassembly" action txt = STR_ACTION_SHOW_DISASM; if (funcNum > 1 && funcMap != null) { me = new JMenu(new UpdateAction(txt)); me.setEnabled(row_selected); for (Long idx : funcMap.keySet()) { int r = funcMap.get(idx).intValue(); String funcName = renderer.getFunction(r); if (funcName != null) { SrcLineUpdateAction sua = new SrcLineUpdateAction(txt, r); mi = new JMenuItem(); mi.setAction(sua); mi.setText(funcName); me.add(mi); } } popup.add(me); } else { mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); } } } if ((type == AnDisplay.DSP_Callers)) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } // Add "Prepend" action txt = STR_ACTION_PREPEND; UpdateAction ppa = new UpdateAction(txt); mi = new JMenuItem(ppa); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); } if ((type == AnDisplay.DSP_Callees)) { // Add "Append" action txt = STR_ACTION_APPEND; UpdateAction apa = new UpdateAction(txt); mi = new JMenuItem(apa); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); } if ((type == AnDisplay.DSP_CallerCalleeSelf)) { // Add "Remove" action txt = STR_ACTION_REMOVE; UpdateAction rma = new UpdateAction(txt); mi = new JMenuItem(rma); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(false); if (row == 0) { mi.setEnabled(true); } if (table.getRowCount() - 1 == row) { mi.setEnabled(row_selected); } if (table.getRowCount() <= 1) { mi.setEnabled(false); } popup.add(mi); // Add "Set Head" action txt = STR_ACTION_SETHEAD; ua = new UpdateAction(txt); mi = new JMenuItem(ua); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (row <= 0) { mi.setEnabled(false); } else { mi.setEnabled(true); } popup.add(mi); } if ((type == AnDisplay.DSP_Callers) || (type == AnDisplay.DSP_CallerCalleeSelf) || (type == AnDisplay.DSP_Callees)) { // Add "Set Center" action txt = STR_ACTION_RECENTER; UpdateAction rca = new UpdateAction(txt); mi = new JMenuItem(rca); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); if ((type == AnDisplay.DSP_CallerCalleeSelf)) { if (table.getRowCount() <= 1) { mi.setEnabled(false); } } popup.add(mi); } if ((type == AnDisplay.DSP_CallerCalleeSelf)) { // Add "Set Tail" action txt = STR_ACTION_SETTAIL; ua = new UpdateAction(txt); mi = new JMenuItem(ua); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(false); if (row >= 0) { if (row < table.getRowCount() - 1) { mi.setEnabled(true); } } popup.add(mi); } if ((type == AnDisplay.DSP_Callers) || (type == AnDisplay.DSP_CallerCalleeSelf) || (type == AnDisplay.DSP_Callees)) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } // NM // Add "Reset" action // NM txt = STR_ACTION_RESET; // NM UpdateAction rsa = new UpdateAction(txt); // NM mi = new JMenuItem(rsa); // NM ac = mi.getAccessibleContext(); // NM ac.setAccessibleDescription(txt); // NM mi.setEnabled(true); // NM popup.add(mi); // NM // NM // Add separator // NM popup.addSeparator(); // Add "Back" action txt = STR_ACTION_BACK; UpdateAction bka = new UpdateAction(txt); mi = new JMenuItem(bka); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (parent != null) { mi.setEnabled(parent.isBackActionAvailable()); popup.add(mi); } // Add "Forward" action txt = STR_ACTION_FORWARD; UpdateAction fwa = new UpdateAction(txt); mi = new JMenuItem(fwa); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (parent != null) { mi.setEnabled(parent.isForwardActionAvailable()); popup.add(mi); } // Add separator popup.addSeparator(); } if ((type == AnDisplay.DSP_MiniCaller || type == AnDisplay.DSP_MiniCallee)) { txt = STR_ACTION_SHOW_SELECTED_FUNCTION; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); } addFilterPopup(filterOnly, popup, type, viewName, row_selected); popup.addSeparator(); JMenu tableColumnsSubMenu; tableColumnsSubMenu = new JMenu(AnLocale.getString("Table Columns")); for (Component component : AnWindow.getInstance().getSettings().getMetricsSetting().createTableColumnMenuItems(this)) { tableColumnsSubMenu.add(component); } tableColumnsSubMenu.addSeparator(); for (Component component : AnWindow.getInstance().getSettings().getMetricsSetting().getOtherMetricItems(this)) { tableColumnsSubMenu.add(component); } popup.add(tableColumnsSubMenu); if (canSort && !(type == AnDisplay.DSP_MiniCallee || type == AnDisplay.DSP_MiniCaller || type == AnDisplay.DSP_MiniCallerCalleeSelf)) { // Add Select Next submenu JMenu sortSubMenu; sortSubMenu = new JMenu(AnLocale.getString("Sort Table By ")); // Add sorting menu items for (int i = 0; i < tableModel.getColumnCount(); i++) { txt = tableModel.getLabel(i).getText(); // FIXUP SortMenu sm = new SortMenu(i, txt); mi = new JMenuItem(sm); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(canSort); sortSubMenu.add(mi); } popup.add(sortSubMenu); } switch (type) { case AnDisplay.DSP_Functions: case AnDisplay.DSP_Lines: case AnDisplay.DSP_SourceDisassembly: case AnDisplay.DSP_Source: case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_SourceV2: case AnDisplay.DSP_DisassemblyV2: // case AnDisplay.DSP_LEAKLIST: case AnDisplay.DSP_InstructionFrequency: { if (gap != null) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } // Add "Previous Hot Line" action txt = gap.STR_ACTION_PREV_HOT_LINE; mi = new JMenuItem(new UpdateAction(txt)); mi.setAccelerator(KeyboardShortcuts.sourcePreviousHotLineActionShortcut); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(gap.HG_Is_Prev_Hot_Line()); popup.add(mi); // Add "Next Hot Line" action txt = gap.STR_ACTION_NEXT_HOT_LINE; mi = new JMenuItem(new UpdateAction(txt)); mi.setAccelerator(KeyboardShortcuts.sourceNextHotLineActionShortcut); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(gap.HG_Is_Next_Hot_Line()); popup.add(mi); // Add separator popup.addSeparator(); // Add "Previous Non-zero Metric Line" action txt = gap.STR_ACTION_PREV_NZ_LINE; mi = new JMenuItem(new UpdateAction(txt)); mi.setAccelerator(KeyboardShortcuts.sourcePreviousNonZeroLineActionShortcut); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(gap.HG_Is_Prev_NZ_Line()); popup.add(mi); // Add "Next Non-zero Metric Line" action txt = gap.STR_ACTION_NEXT_NZ_LINE; mi = new JMenuItem(new UpdateAction(txt)); mi.setAccelerator(KeyboardShortcuts.sourceNextNonZeroLineActionShortcut); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(gap.HG_Is_Next_NZ_Line()); popup.add(mi); } break; } } // popup.addSeparator(); // // Format // JMenu formatByMenuItem = new JMenu(AnLocale.getString("Format")); // JRadioButtonMenuItem jRadioButtonMenuItem; // formatByMenuItem.add(jRadioButtonMenuItem = new // JRadioButtonMenuItem(AnLocale.getString("Text"))); // jRadioButtonMenuItem.setSelected(true); // formatByMenuItem.add(jRadioButtonMenuItem = new // JRadioButtonMenuItem(AnLocale.getString("Bar"))); // jRadioButtonMenuItem.setEnabled(false); // formatByMenuItem.add(jRadioButtonMenuItem = new // JRadioButtonMenuItem(AnLocale.getString("Pie"))); // jRadioButtonMenuItem.setEnabled(false); // popup.add(formatByMenuItem); // Table format // JMenu formatMenuItem = new JMenu(AnLocale.getString("Format")); // final JCheckBoxMenuItem wrapCheckBoxMenuItem = new // JCheckBoxMenuItem(AnLocale.getString("Wrap Long Metric Names in Table Headers")); // // wrapCheckBoxMenuItem.setSelected(AnWindow.getInstance().getSettings().getTableSettings().wrapMetricNames()); // wrapCheckBoxMenuItem.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // // AnWindow.getInstance().getSettings().getTableSettings().setWrapMetricNames(AnTable.this, // wrapCheckBoxMenuItem.isSelected()); // } // // }); // formatMenuItem.add(wrapCheckBoxMenuItem); // popup.add(formatMenuItem); // Compare // CompareModeSetting.CompareMode mode = // AnWindow.getInstance().getSettings().getCompareModeSetting().get(); // JMenu compareMenuItem = new JMenu(AnLocale.getString("Compare Mode")); // if (mode != CompareModeSetting.CompareMode.CMP_DISABLE) { // JRadioButtonMenuItem absoluteRadioButtonMenuItem = new // JRadioButtonMenuItem(AnLocale.getString("Absolute")); // JRadioButtonMenuItem deltaRadioButtonMenuItem = new // JRadioButtonMenuItem(AnLocale.getString("Delta")); // JRadioButtonMenuItem ratioRadioButtonMenuItem = new // JRadioButtonMenuItem(AnLocale.getString("Ratio")); // absoluteRadioButtonMenuItem.setSelected(mode == // CompareModeSetting.CompareMode.CMP_ENABLE); // deltaRadioButtonMenuItem.setSelected(mode == // CompareModeSetting.CompareMode.CMP_DELTA); // ratioRadioButtonMenuItem.setSelected(mode == // CompareModeSetting.CompareMode.CMP_RATIO); // absoluteRadioButtonMenuItem.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // AnWindow.getInstance().getSettings().getCompareModeSetting().set(this, // CompareModeSetting.CompareMode.CMP_ENABLE); // } // }); // deltaRadioButtonMenuItem.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // AnWindow.getInstance().getSettings().getCompareModeSetting().set(this, // CompareModeSetting.CompareMode.CMP_DELTA); // } // }); // ratioRadioButtonMenuItem.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // AnWindow.getInstance().getSettings().getCompareModeSetting().set(this, // CompareModeSetting.CompareMode.CMP_RATIO); // } // }); // compareMenuItem.add(absoluteRadioButtonMenuItem); // compareMenuItem.add(deltaRadioButtonMenuItem); // compareMenuItem.add(ratioRadioButtonMenuItem); // formatMenuItem.add(compareMenuItem); // } if ((type == AnDisplay.DSP_Callers) || (type == AnDisplay.DSP_CallerCalleeSelf) || (type == AnDisplay.DSP_Callees)) { // Add menu item "Copy All" txt = STR_ACTION_COPY_ALL; UpdateAction ca = new UpdateAction(txt); mi = new JMenuItem(ca); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); popup.addSeparator(); popup.add(mi); } switch (type) { case AnDisplay.DSP_Callees: case AnDisplay.DSP_Callers: case AnDisplay.DSP_CallerCalleeSelf: case AnDisplay.DSP_MPIChart: case AnDisplay.DSP_MPITimeline: case AnDisplay.DSP_Null: case AnDisplay.DSP_Overview: case AnDisplay.DSP_Statistics: case AnDisplay.DSP_Timeline: case AnDisplay.DSP_Welcome: break; default: popup.addSeparator(); // Add menu item "Copy Selected" txt = STR_ACTION_COPY_SEL; UpdateAction cs = new UpdateAction(txt); mi = new JMenuItem(cs); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); popup.add(mi); // Add menu item "Copy All" txt = STR_ACTION_COPY_ALL; UpdateAction ca = new UpdateAction(txt); mi = new JMenuItem(ca); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); popup.add(mi); break; } switch (type) { case AnDisplay.DSP_Functions: case AnDisplay.DSP_MiniFunctions: case AnDisplay.DSP_IO: case AnDisplay.DSP_Heap: case AnDisplay.DSP_IOFileDescriptors: case AnDisplay.DSP_Lines: case AnDisplay.DSP_PCs: case AnDisplay.DSP_IndexObject: case AnDisplay.DSP_Callers: case AnDisplay.DSP_CallerCalleeSelf: case AnDisplay.DSP_Callees: popup.addSeparator(); // Add menu item Properties mi = new JMenuItem( new SettingsAction( AnLocale.getString("Metric Settings"), parent.window.getSettings().settingsMetricsIndex)); mi.setAccelerator(KeyboardShortcuts.metricsSettingsShortcut); popup.add(mi); break; case AnDisplay.DSP_SourceDisassembly: case AnDisplay.DSP_Source: case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_SourceV2: case AnDisplay.DSP_DisassemblyV2: popup.addSeparator(); // Add menu item Properties mi = new JMenuItem( new SettingsAction( AnLocale.getString("Source/Disassembly Settings"), parent.window.getSettings().settingsSourceDisassemblyIndex)); mi.setAccelerator(KeyboardShortcuts.settingsActionShortcut); popup.add(mi); break; } } private void addFilterPopup( boolean filterOnly, JPopupMenu popup, int type, String viewName, boolean row_selected) { AccessibleContext ac; JMenuItem mi; String txt; if ((type == AnDisplay.DSP_Callers) || (type == AnDisplay.DSP_CallerCalleeSelf) || (type == AnDisplay.DSP_Callees)) { // Add "Set Filter: Stack Fragment in Stack ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_CALLSTACK_FRAGMENT_SHORT_NAME, FILTER_CALLSTACK_FRAGMENT_LONG_NAME, FILTER_CALLSTACK_FRAGMENT_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_CALLSTACK_FRAGMENT_LONG_NAME); mi.setEnabled(true); popup.add(mi); // Add "Set Filter: Not Stack Fragment in Stack ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_CALLSTACK_FRAGMENT_SHORT_NAME, FILTER_NOT_CALLSTACK_FRAGMENT_LONG_NAME, FILTER_NOT_CALLSTACK_FRAGMENT_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_CALLSTACK_FRAGMENT_LONG_NAME); mi.setEnabled(true); popup.add(mi); // Add "Set Filter: Function in Stack ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_SELECTED_FUNCTION_SHORT_NAME, FILTER_SELECTED_FUNCTION_LONG_NAME, FILTER_SELECTED_FUNCTION_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_SELECTED_FUNCTION_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Function is Leaf ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_LEAF_FUNCTION_SHORT_NAME, FILTER_LEAF_FUNCTION_LONG_NAME, FILTER_LEAF_FUNCTION_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_LEAF_FUNCTION_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); if (filterOnly) { popup.addSeparator(); } // Add Manage Filters txt = STR_ACTION_CUSTOM_FILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); popup.add(mi); // Add "Undo Last Filter ..." action txt = STR_ACTION_UNDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canUndoLastFilter()); popup.add(mi); // Add "Redo Last Filter ..." action txt = STR_ACTION_REDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRedoLastFilter()); popup.add(mi); // Add "Reset Default Filter ..." action txt = STR_ACTION_REMOVE_ALL_FILTERS; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRemoveAllFilters()); popup.add(mi); // Add "Remove Filter" action if (parent.window.getFilters().anyFilters()) { popup.add(parent.window.getFilters().removeFilterMenuItem()); } // if (filterOnly) { // popup.addSeparator(); // } } if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_Lines) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_SELECTED_LINES_SHORT_NAME, FILTER_SELECTED_LINES_LONG_NAME, FILTER_SELECTED_LINES_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_SELECTED_LINES_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_SELECTED_LINES_SHORT_NAME, FILTER_NOT_SELECTED_LINES_LONG_NAME, FILTER_NOT_SELECTED_LINES_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_SELECTED_LINES_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); } if (type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_PCs) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_SELECTED_PCS_SHORT_NAME, FILTER_SELECTED_PCS_LONG_NAME, FILTER_SELECTED_PCS_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_SELECTED_PCS_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_SELECTED_PCS_SHORT_NAME, FILTER_NOT_SELECTED_PCS_LONG_NAME, FILTER_NOT_SELECTED_PCS_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_SELECTED_PCS_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); } if (type == AnDisplay.DSP_Functions) { if (popup.getComponentCount() > 0) { popup.addSeparator(); } // Add "Set Filter: Function in Stack ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_SELECTED_FUNCTIONS_SHORT_NAME, FILTER_SELECTED_FUNCTIONS_LONG_NAME, FILTER_SELECTED_FUNCTIONS_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_SELECTED_FUNCTIONS_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Function in Stack ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_SELECTED_FUNCTIONS_SHORT_NAME, FILTER_NOT_SELECTED_FUNCTIONS_LONG_NAME, FILTER_NOT_SELECTED_FUNCTIONS_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_SELECTED_FUNCTIONS_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Function is Leaf ..." mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_LEAF_FUNCTIONS_SHORT_NAME, FILTER_LEAF_FUNCTIONS_LONG_NAME, FILTER_LEAF_FUNCTIONS_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_LEAF_FUNCTIONS_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Name in Stack ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_SIMILARLY_NAMED_SHORT_NAME, FILTER_SIMILARLY_NAMED_LONG_NAME, FILTER_SIMILARLY_NAMED_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_SIMILARLY_NAMED_LONG_NAME); mi.setEnabled(row_selected); if (table.getSelectedRowCount() > 1) { mi.setEnabled(false); } popup.add(mi); } if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_Lines || type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_PCs || type == AnDisplay.DSP_Functions || type == AnDisplay.DSP_MiniFunctions) { // Add "Manage Filters..." action txt = STR_ACTION_CUSTOM_FILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); popup.add(mi); if (filterOnly) { popup.addSeparator(); } // Add "Undo Last Filter ..." action txt = STR_ACTION_UNDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canUndoLastFilter()); popup.add(mi); // Add "Redo Last Filter ..." action txt = STR_ACTION_REDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRedoLastFilter()); popup.add(mi); // Add "Set Filter: Reset Default Filter ..." action txt = STR_ACTION_REMOVE_ALL_FILTERS; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRemoveAllFilters()); popup.add(mi); // Add "Remove Filter" action if (parent.window.getFilters().anyFilters()) { popup.add(parent.window.getFilters().removeFilterMenuItem()); } // if (filterOnly) { // popup.addSeparator(); // } } if ((type == AnDisplay.DSP_IO) || (type == AnDisplay.DSP_IOFileDescriptors) || (type == AnDisplay.DSP_IOCallStacks)) { if (AnWindow.getInstance().getIOView().getDisplayMode() == AnDisplay.DSP_IO) { // Add "Set Filter: Selected File Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_FILE_SHORT_NAME, FILTER_WITH_SELECTED_FILE_LONG_NAME, FILTER_WITH_SELECTED_FILE_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_FILE_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Exclude Selected File Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_SELECTED_FILE_SHORT_NAME, FILTER_NOT_SELECTED_FILE_LONG_NAME, FILTER_NOT_SELECTED_FILE_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_SELECTED_FILE_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); } else if (AnWindow.getInstance().getIOView().getDisplayMode() == AnDisplay.DSP_IOFileDescriptors) { // Add "Set Filter: Selected IOVFD Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_IOVFD_SHORT_NAME, FILTER_WITH_SELECTED_IOVFD_LONG_NAME, FILTER_WITH_SELECTED_IOVFD_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_IOVFD_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Exclude Selected IOVFD Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_SELECTED_IOVFD_SHORT_NAME, FILTER_NOT_SELECTED_IOVFD_LONG_NAME, FILTER_NOT_SELECTED_IOVFD_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_SELECTED_IOVFD_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); } else if (AnWindow.getInstance().getIOView().getDisplayMode() == AnDisplay.DSP_IOCallStacks) { // Add "Set Filter: Selected Stack Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_IOSTACK_SHORT_NAME, FILTER_WITH_SELECTED_IOSTACK_LONG_NAME, FILTER_WITH_SELECTED_IOSTACK_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_IOSTACK_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Exclude Selected Stack Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_SELECTED_IOSTACK_SHORT_NAME, FILTER_NOT_SELECTED_IOSTACK_LONG_NAME, FILTER_NOT_SELECTED_IOSTACK_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_SELECTED_IOSTACK_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); } // Add "Manage Filters..." action txt = STR_ACTION_CUSTOM_FILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); popup.add(mi); if (filterOnly) { popup.addSeparator(); } // Add "Undo Last Filter ..." action txt = STR_ACTION_UNDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canUndoLastFilter()); popup.add(mi); // Add "Redo Last Filter ..." action txt = STR_ACTION_REDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRedoLastFilter()); popup.add(mi); // Add "Set Filter: Reset Default Filter ..." action txt = STR_ACTION_REMOVE_ALL_FILTERS; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRemoveAllFilters()); popup.add(mi); // Add "Remove Filter" action if (parent.window.getFilters().anyFilters()) { popup.add(parent.window.getFilters().removeFilterMenuItem()); } } if (type == AnDisplay.DSP_Heap) { if (AnWindow.getInstance().getHeapView().getDisplayMode() == AnDisplay.DSP_Heap) { // Add "Set Filter: Active Allocation Stacks Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_HEAPACTIVESTACK_SHORT_NAME, FILTER_WITH_SELECTED_HEAPACTIVESTACK_LONG_NAME, FILTER_WITH_SELECTED_HEAPACTIVESTACK_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_HEAPACTIVESTACK_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Allocations That Leaked ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_HEAPLEAKEDSTACK_SHORT_NAME, FILTER_WITH_SELECTED_HEAPLEAKEDSTACK_LONG_NAME, FILTER_WITH_SELECTED_HEAPLEAKEDSTACK_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_HEAPLEAKEDSTACK_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Allocations That Not Leaked ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_SELECTED_HEAPLEAKEDSTACK_SHORT_NAME, FILTER_NOT_SELECTED_HEAPLEAKEDSTACK_LONG_NAME, FILTER_NOT_SELECTED_HEAPLEAKEDSTACK_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_SELECTED_HEAPLEAKEDSTACK_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Selected Stack Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_HEAPSTACK_SHORT_NAME, FILTER_WITH_SELECTED_HEAPSTACK_LONG_NAME, FILTER_WITH_SELECTED_HEAPSTACK_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_HEAPSTACK_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Exclude Selected Stack Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_NOT_SELECTED_HEAPSTACK_SHORT_NAME, FILTER_NOT_SELECTED_HEAPSTACK_LONG_NAME, FILTER_NOT_SELECTED_HEAPSTACK_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_NOT_SELECTED_HEAPSTACK_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); } // Add "Manage Filters..." action txt = STR_ACTION_CUSTOM_FILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); popup.add(mi); if (filterOnly) { popup.addSeparator(); } // Add "Undo Last Filter ..." action txt = STR_ACTION_UNDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canUndoLastFilter()); popup.add(mi); // Add "Redo Last Filter ..." action txt = STR_ACTION_REDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRedoLastFilter()); popup.add(mi); // Add "Set Filter: Reset Default Filter ..." action txt = STR_ACTION_REMOVE_ALL_FILTERS; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRemoveAllFilters()); popup.add(mi); // Add "Remove Filter" action if (parent.window.getFilters().anyFilters()) { popup.add(parent.window.getFilters().removeFilterMenuItem()); } } if ((type == AnDisplay.DSP_IndexObject) || (type == AnDisplay.DSP_MemoryObject)) { // Threads, CPUs, Samples, Seconds tabs if (popup.getComponentCount() > 0) { popup.addSeparator(); } // Add "Set Filter: Selected Objects Only ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_ITEMS_SHORT_NAME, FILTER_WITH_SELECTED_ITEMS_LONG_NAME, FILTER_WITH_SELECTED_ITEMS_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_ITEMS_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Exclude Selected Objects ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITHOUT_SELECTED_ITEMS_SHORT_NAME, FILTER_WITHOUT_SELECTED_ITEMS_LONG_NAME, FILTER_WITHOUT_SELECTED_ITEMS_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITHOUT_SELECTED_ITEMS_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); if (viewName.equals("Threads")) { boolean jthread_selected = false; int namecol = getTableModel().getNameCol(); for (int selrow : anTable.getSelectedRows()) { String name = (String) getTableModel().data[namecol][selrow]; if (name.contains("JThread")) { jthread_selected = true; break; } } if (jthread_selected) { // Add "Set Filter: Include only JThreads in selected group ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_JGROUP_SHORT_NAME, FILTER_WITH_SELECTED_JGROUP_LONG_NAME, FILTER_WITH_SELECTED_JGROUP_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_JGROUP_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Include only JThreads in selected parent ..." action mi = new JMenuItem( new FilterUpdateAction( viewName, FILTER_WITH_SELECTED_JPARENT_SHORT_NAME, FILTER_WITH_SELECTED_JPARENT_LONG_NAME, FILTER_WITH_SELECTED_JPARENT_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(FILTER_WITH_SELECTED_JPARENT_LONG_NAME); mi.setEnabled(row_selected); popup.add(mi); } } // Add "Manage Filters..." action txt = STR_ACTION_CUSTOM_FILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); popup.add(mi); if (filterOnly) { popup.addSeparator(); } // Add "Undo Last Filter ..." action txt = STR_ACTION_UNDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canUndoLastFilter()); popup.add(mi); // Add "Redo Last Filter ..." action txt = STR_ACTION_REDOFILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRedoLastFilter()); popup.add(mi); // Add "Set Filter: Reset Default Filter ..." action txt = STR_ACTION_REMOVE_ALL_FILTERS; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(parent.window.getFilters().canRemoveAllFilters()); popup.add(mi); // Add "Remove Filter" action if (parent.window.getFilters().anyFilters()) { popup.add(parent.window.getFilters().removeFilterMenuItem()); } // if (filterOnly) { // popup.addSeparator(); // } } } // ------- Private classes to implement popup menu items ------- // protected class AnMenuListener extends MouseAdapter { private boolean debug; private AnTable anTable; AnMenuListener(AnTable _anTable) { anTable = _anTable; debug = false; } // Experimental code, mostly "quick and dirty hack" public JPopupMenu initPopup(MouseEvent event) { // Experimental code if (parent != null) { if (parent instanceof CallerCalleesView) { try { parent.changeSelection(anTable, table.rowAtPoint(event.getPoint())); } catch (Exception exc) { System.out.println("AnTable.init_popup() exception: " + exc); exc.printStackTrace(); } setSelectedRowNow(table.rowAtPoint(event.getPoint())); } } return anTable.initPopup(false); } /* private JMenuItem menuItem(String txt, boolean enbl) { UpdateAction act = new UpdateAction(txt); JMenuItem mi = new JMenuItem(act); AccessibleContext ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(enbl); return mi; } */ @Override public void mousePressed(MouseEvent e) { maybeShowPopup(e); } @Override public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { showPopup(e); } } public void showPopup(MouseEvent e) { if (!Analyzer.getInstance().normalSelection) { int row = table.rowAtPoint(e.getPoint()); if (row != -1 && !table.isRowSelected(row)) { setSelectedRow(row); fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, row, null)); } } JPopupMenu popup = initPopup(e); if (popup != null) { popup.show(e.getComponent(), e.getX(), e.getY()); } } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeInvisible(" + e + ")"); } } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeVisible(" + e + ")"); } } public void popupMenuCanceled(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuCanceled(" + e + ")"); } } } class SortMenu extends AbstractAction { private int colNum; public SortMenu(int colNum, String txt) { super(txt); this.colNum = colNum; } public SortMenu(int colNum) { this.colNum = colNum; } public void actionPerformed(ActionEvent ev) { if (colNum < tableModel.getColumnCount()) { sortTable(colNum); } } } /* * Generic action for context menu items. * Action name is passed as String. */ class UpdateAction extends AbstractAction { String actionName = null; public UpdateAction(String txt) { super(txt); actionName = txt; } @Override public void actionPerformed(ActionEvent ev) { Object progressBarHandle = parent .window .getSystemProgressPanel() .progressBarStart(AnLocale.getString("Table Update")); updateAnTable(actionName); parent.window.getSystemProgressPanel().progressBarStop(progressBarHandle); } public void tailFunction() {} } class FilterUpdateAction extends AbstractAction { String viewName; String shortName; String longName; String actionName; public FilterUpdateAction( String viewName, String shortName, String longName, String actionName) { super(ADD_FILTER + ": " + longName); this.viewName = viewName; this.shortName = shortName; this.longName = longName; this.actionName = actionName; } public void actionPerformed(ActionEvent ev) { // parent.window.setBusyCursor(true); AnUtility.checkIPCOnWrongThread(false); updateTable(viewName + ": " + shortName, longName, actionName); AnUtility.checkIPCOnWrongThread(true); // parent.window.setBusyCursor(false); } } /* * Action for context menu items of source line navigation. * Action name is passed as String. */ class SrcLineUpdateAction extends UpdateAction { String actionName = null; int row = -1; public SrcLineUpdateAction(String txt, int r) { super(txt); actionName = txt; row = r; } @Override public void actionPerformed(ActionEvent ev) { Object progressBarHandle = parent .window .getSystemProgressPanel() .progressBarStart(AnLocale.getString("Source Line")); // change selected object parent.window.getSelectedObject().setSelObj(row, parent.type, parent.subtype); updateAnTable(actionName); parent.window.getSystemProgressPanel().progressBarStop(progressBarHandle); } } /* * Action for context menu items of function navigation. * Action name is passed as String. */ class NavigationUpdateAction extends UpdateAction { protected String actionName = null; protected long functionId = -1; protected int lineNo = -1; public NavigationUpdateAction(String txt, long id, int no) { super(txt); actionName = txt; functionId = id; lineNo = no; } public void actionPerformed(ActionEvent ev) { navHistoryPool.getHistory().enabled = true; // change selected object parent.window.getSelectedObject().setSelObjV2(functionId); parent.setNavigationAction(this); parent.setComputed(false); parent.computeOnAWorkerThread(); } public void tailFunction() { if ((type == AnDisplay.DSP_Source) || (type == AnDisplay.DSP_SourceV2)) { if (lineNo != -1) { // -1 is for callee, but here is for caller int base_row = table.getSelectedRow(); int row = srcRenderer.getRowByLineNo(lineNo); if (row != -1) { navHistoryPool.getHistory().enabled = false; anTable.setSelectedRow(row); navHistoryPool.getHistory().enabled = true; anTable.fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, row, null)); // adjust history SelObjInfo back_obj = navHistoryPool.getHistory().goBack(); if (back_obj != null && back_obj.id == functionId && back_obj.lineno == lineNo) { navHistoryPool.getHistory().goBack(); SelObjInfo new_obj = new SelObjInfo(back_obj.id, back_obj.lineno, back_obj.name); navHistoryPool.getHistory().goToNew(new_obj); } else { navHistoryPool.getHistory().goForward(); SrcRenderer.SrcTextMarker sm = srcRenderer.srcRendered.get(srcRenderer.mapRow(base_row)); int base_lineNo = sm == null ? -1 : sm.lineNo; SelObjInfo cur_obj = navHistoryPool.getHistory().getCurrent(); if (navHistoryPool.getHistory().newAdded == false && cur_obj != null && cur_obj.id == functionId && cur_obj.lineno == base_lineNo) { SelObjInfo new_obj = new SelObjInfo(cur_obj.id, lineNo, cur_obj.name); navHistoryPool.getHistory().goToNew(new_obj); } else { cur_obj.lineno = lineNo; } } } } } else if ((type == AnDisplay.DSP_Disassembly) || (type == AnDisplay.DSP_DisassemblyV2)) { if (lineNo != -1) { // -1 is for callee, but here is for caller int base_row = table.getSelectedRow(); String baseAddrStr = disRenderer.getRowToAddr(base_row, base_row); if (baseAddrStr != null) { Long callsiteAddr = Long.parseLong(baseAddrStr, 16); callsiteAddr += lineNo; // lineNo is actually offset inside function for disasm view Integer callsite = disRenderer.getAddrToRow(Long.toHexString(callsiteAddr), base_row); if (callsite != null) { navHistoryPool.getHistory().enabled = false; anTable.setSelectedRow(callsite); navHistoryPool.getHistory().enabled = true; anTable.fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, callsite, null)); // adjust history SelObjInfo back_obj = navHistoryPool.getHistory().goBack(); if (back_obj != null && back_obj.id == functionId && back_obj.lineno == callsite) { navHistoryPool.getHistory().goBack(); SelObjInfo new_obj = new SelObjInfo(back_obj.id, back_obj.lineno, back_obj.name); navHistoryPool.getHistory().goToNew(new_obj); } else { navHistoryPool.getHistory().goForward(); SelObjInfo cur_obj = navHistoryPool.getHistory().getCurrent(); if (navHistoryPool.getHistory().newAdded == false && cur_obj != null && cur_obj.id == functionId && cur_obj.lineno == base_row) { SelObjInfo new_obj = new SelObjInfo(cur_obj.id, callsite, Long.toHexString(callsiteAddr)); navHistoryPool.getHistory().goToNew(new_obj); } else { cur_obj.lineno = callsite; cur_obj.name = Long.toHexString(callsiteAddr); } } } } } } updateAnTable(actionName); } } class NavigationHistoryUpdateAction extends NavigationUpdateAction { private String addr; public NavigationHistoryUpdateAction(String txt, long id, int no, String a) { super(txt, id, no); addr = a; } public void actionPerformed(ActionEvent ev) { boolean inError = anTable.getViewport().getView() != table; if (actionName.equalsIgnoreCase(STR_ACTION_BACK)) { if (navHistoryPool.getHistory().canGoBack() && !inError) { navHistoryPool.getHistory().goBack(); } } if (actionName.equalsIgnoreCase(STR_ACTION_FORWARD)) { if (navHistoryPool.getHistory().canGoForward()) { navHistoryPool.getHistory().goForward(); } } boolean done = false; navHistoryPool.getHistory().enabled = false; if (!inError && ((type == AnDisplay.DSP_Disassembly) || (type == AnDisplay.DSP_DisassemblyV2))) { int sel_row = anTable.getSelectedRow(); long fun_id = -1; if (sel_row >= 0 && sel_row < disRenderer.functionId.size()) { fun_id = disRenderer.functionId.get(sel_row); } if (fun_id == functionId) { Integer targetRowObj = disRenderer.getAddrToRow(addr, sel_row); if (targetRowObj != null) { int targetRow = targetRowObj.intValue(); setSelectedRow(targetRow); fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, targetRow, null)); done = true; } } } if (!inError && !done) { if ((type == AnDisplay.DSP_Disassembly) || (type == AnDisplay.DSP_DisassemblyV2)) { Integer targetRowObj = disRenderer.getAddrToRow(addr, selectedRow); if (targetRowObj != null) { int targetRow = targetRowObj.intValue(); long fun_id = -1; if (targetRow >= 0 && targetRow < disRenderer.functionId.size()) { fun_id = disRenderer.functionId.get(targetRow); } if (fun_id == functionId) { setSelectedRow(targetRow); fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, targetRow, null)); done = true; } } } } if (done) { parent.updateToolBar(); // only for dis view navHistoryPool.getHistory().enabled = true; } if (!done) { // change selected object if (type == AnDisplay.DSP_Functions) { parent.window.getSelectedObject().setSelObj(lineNo, parent.type, parent.subtype); } else { parent.window.getSelectedObject().setSelObjV2(functionId); } parent.setNavigationAction(this); parent.setComputed(false); parent.computeOnAWorkerThread(); } } @Override public void tailFunction() { if ((type == AnDisplay.DSP_Source) || (type == AnDisplay.DSP_SourceV2)) { if (lineNo != -1) { int row = srcRenderer.getRowByLineNo(lineNo); if (row != -1) { anTable.setSelectedRow(row); anTable.fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, row, null)); } } } else if ((type == AnDisplay.DSP_Disassembly) || (type == AnDisplay.DSP_DisassemblyV2)) { int row = table.getSelectedRow(); for (int i = row; i < anTable.getRowCount(); i++) { String baseAddrStr = disRenderer.getRowToAddr(i, i); if ((baseAddrStr != null && baseAddrStr.equalsIgnoreCase(addr)) || lineNo == i) { anTable.setSelectedRow(i); anTable.fireAnEvent(new AnEvent(anTable, AnEvent.EVT_SELECT, i, null)); break; } } } updateAnTable(actionName); navHistoryPool.getHistory().enabled = true; } } static class SelObjInfo implements Comparable { long id; // function id int lineno; // for callsite dis, lineno is instr offset in one function // for history dis, lineno is row number String name; // for history dis data, name is address if lineno is -1 public SelObjInfo(long idp, int no, String namep) { id = idp; lineno = no; name = namep; } public int compareTo(SelObjInfo o) { return this.name.compareTo(o.name); } } class NavigationHistoryPool { private ArrayList> historyPool = null; public NavigationHistoryPool() { historyPool = new ArrayList>(); for (int i = 0; i < 3; i++) { historyPool.add(new HashMap()); } for (int i = 0; i < 3; i++) { historyPool.get(i).put("", new NavigationHistory()); } } public NavigationHistory getHistory() { int viewMode = parent.window.getSettings().getViewModeSetting().get().value(); if (viewMode < 0 || viewMode > 2) { System.err.println("Error: wrong view mode!"); return null; } String filterExp = parent.window.getFilters().getFilterStr(0); if (filterExp == null) { filterExp = ""; } NavigationHistory ret = historyPool.get(viewMode).get(filterExp); if (ret == null) { historyPool.get(viewMode).put(filterExp, new NavigationHistory()); ret = historyPool.get(viewMode).get(filterExp); } return ret; } public void clearAll() { for (int i = 0; i < 3; i++) { if (historyPool.get(i) != null) { historyPool.get(i).clear(); } } for (int i = 0; i < 3; i++) { if (historyPool.get(i) != null) { historyPool.get(i).put("", new NavigationHistory()); } } } } class NavigationHistory { private ArrayList history; private int curPos; public boolean enabled; public boolean newAdded; public NavigationHistory() { curPos = -1; history = new ArrayList(); enabled = true; newAdded = false; } public void goToNew(SelObjInfo obj) { newAdded = true; curPos++; history.add(curPos, obj); int size = history.size(); for (int i = size - 1; i > curPos; i--) { history.remove(i); } shrinkDuplicated(); } public SelObjInfo goBack() { curPos--; if (curPos >= 0) { return history.get(curPos); } curPos = -1; return null; } public SelObjInfo goForward() { curPos++; if (curPos < history.size()) { return history.get(curPos); } curPos = history.size(); return null; } public SelObjInfo getBack() { if (curPos > 0) { return history.get(curPos - 1); } return null; } public SelObjInfo getForward() { if (curPos < history.size() - 1) { return history.get(curPos + 1); } return null; } public boolean canGoBack() { return (curPos > 0); } public boolean canGoForward() { return (curPos < history.size() - 1); } public SelObjInfo getCurrent() { if (curPos >= 0 && curPos < history.size()) { return history.get(curPos); } return null; } public void goToFuncNew(int row) { SelObjInfo cur_so = navHistoryPool.getHistory().getCurrent(); if (cur_so == null || cur_so.lineno != row) { SelObjInfo new_so = new SelObjInfo(0, row, ""); navHistoryPool.getHistory().goToNew(new_so); } } public void goToSrcNew(int row) { if (srcRenderer == null) { return; } long fun_id = -1; if (row >= 0 && row < srcRenderer.functionId.size()) { fun_id = srcRenderer.functionId.get(row); } if (fun_id == 0) { fun_id = parent.window.getSelectedObject().getSelObjV2("FUNCTION"); } SrcRenderer.SrcTextMarker marker = srcRenderer.srcRendered.get(srcRenderer.mapRow(row)); int lineNo = marker == null ? -1 : marker.lineNo; SelObjInfo cur_so = navHistoryPool.getHistory().getCurrent(); if (cur_so == null || cur_so.id != fun_id || cur_so.lineno != lineNo) { SelObjInfo new_so = new SelObjInfo(fun_id, lineNo, ""); navHistoryPool.getHistory().goToNew(new_so); } } public void goToDisNew(int row) { if (disRenderer == null) { return; } long fun_id = -1; if (row >= 0 && row < disRenderer.functionId.size()) { fun_id = disRenderer.functionId.get(row); } if (fun_id == 0) { fun_id = parent.window.getSelectedObject().getSelObjV2("FUNCTION"); } SelObjInfo cur_so = navHistoryPool.getHistory().getCurrent(); if (cur_so == null || cur_so.id != fun_id || cur_so.lineno != row) { String addr = disRenderer.getRowToAddr(row, row); addr = (addr == null) ? "" : addr; SelObjInfo new_so = new SelObjInfo(fun_id, row, addr); navHistoryPool.getHistory().goToNew(new_so); } } public void shrinkDuplicated() { SelObjInfo cur_so = getCurrent(); if (canGoBack()) { SelObjInfo back_so = getBack(); if (back_so.id == cur_so.id && back_so.lineno == cur_so.lineno) { int i = curPos; while (i < history.size() - 1) { history.set(i, history.get(i + 1)); i++; } history.remove(i); curPos--; } } if (canGoForward()) { SelObjInfo next_so = getForward(); if (next_so.id == cur_so.id && next_so.lineno == cur_so.lineno) { int i = curPos; while (i < history.size() - 1) { history.set(i, history.get(i + 1)); i++; } history.remove(i); } } } public void goToSelected(int org_row, boolean isNew) { if ((type == AnDisplay.DSP_Source) || (type == AnDisplay.DSP_SourceV2)) { if (isNew) { goToSrcNew(org_row); parent.updateToolBar(); } else { SelObjInfo sel_obj = navHistoryPool.getHistory().getCurrent(); Long funcId = null; if ((org_row >= 0) && (srcRenderer.functionId != null) && (org_row < srcRenderer.functionId.size())) { funcId = srcRenderer.functionId.get(org_row); } if (funcId == null) { funcId = parent.window.getSelectedObject().getSelObjV2("FUNCTION"); } SrcRenderer.SrcTextMarker sm = srcRenderer.srcRendered.get(srcRenderer.mapRow(org_row)); int lineNo = -1; if (sel_obj != null && funcId != null && funcId.longValue() != 0 && sm != null) { // XXXX ugly assumption that 0 function id is invalid lineNo = sm.lineNo; sel_obj.id = funcId; sel_obj.lineno = lineNo; sel_obj.name = ""; shrinkDuplicated(); } } } else if ((type == AnDisplay.DSP_Disassembly) || (type == AnDisplay.DSP_DisassemblyV2)) { if (isNew) { goToDisNew(org_row); parent.updateToolBar(); } else { SelObjInfo sel_obj = navHistoryPool.getHistory().getCurrent(); if (sel_obj != null) { Long funcId = null; if (org_row >= 0 && org_row < disRenderer.functionId.size()) { funcId = disRenderer.functionId.get(org_row); } if (funcId == null) { funcId = parent.window.getSelectedObject().getSelObjV2("FUNCTION"); } String addr = disRenderer.getRowToAddr(org_row, org_row); if (funcId != null && funcId.longValue() != 0) { // XXXX ugly assumption that 0 function id is invalid sel_obj.id = funcId; sel_obj.lineno = org_row; sel_obj.name = addr; shrinkDuplicated(); } } } } else if (type == AnDisplay.DSP_Functions) { if (isNew) { goToFuncNew(org_row); parent.updateToolBar(); } else { SelObjInfo sel_obj = navHistoryPool.getHistory().getCurrent(); if (sel_obj != null) { sel_obj.id = 0; sel_obj.lineno = org_row; sel_obj.name = ""; shrinkDuplicated(); } } } } public void clear() { history.clear(); curPos = -1; } } public void setGroupId(int id) { groupId = id; } public int getGroupId() { return groupId; } } gprofng-gui-1.0/org/gprofng/mpmt/collect/0000755000175000017500000000000014517775727015460 500000000000000gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectPanel2.java0000644000175000017500000012167514517772113020670 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.collect; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.PsParser; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import javax.accessibility.AccessibleContext; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.PopupMenuEvent; import javax.swing.table.DefaultTableModel; /** Creates first page for Collector GUI to profile a running application */ public class CollectPanel2 extends JPanel { private final String STR_ACTION_UPDATE = AnLocale.getString("Refresh"); private final String STR_ACTION_SORTBY = AnLocale.getString("Sort by"); private final String STR_ACTION_COPY_ALL = AnLocale.getString("Copy All"); private JPanel workPanel; private AnWindow anWindow; private AnMenuListener menuListener; private String processID; private String[] tableColumns = new String[6]; /* * Creates new form CollectPanel2 */ public CollectPanel2(final AnWindow aWindow) { workPanel = this; this.anWindow = aWindow; initComponents(); postInitComponents(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; jPanel2 = new javax.swing.JPanel(); jLabel2 = new javax.swing.JLabel(); jLabel1 = new javax.swing.JLabel(); jComboBox1 = new javax.swing.JComboBox(); jButton1 = new javax.swing.JButton(); jScrollPane2 = new javax.swing.JScrollPane(); processesTable = new javax.swing.JTable(); jPanel3 = new javax.swing.JPanel(); jTextField1 = new javax.swing.JTextField(); jLabel3 = new javax.swing.JLabel(); jComboBox2 = new javax.swing.JComboBox(); jLabel4 = new javax.swing.JLabel(); jComboBox3 = new javax.swing.JComboBox(); jLabel5 = new javax.swing.JLabel(); jComboBox4 = new javax.swing.JComboBox(); jLabel6 = new javax.swing.JLabel(); jTextField2 = new javax.swing.JTextField(); jLabel7 = new javax.swing.JLabel(); jButton2 = new javax.swing.JButton(); jButton6 = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); jPanel2.setLayout(new java.awt.GridBagLayout()); jLabel2.setLabelFor(processesTable); jLabel2.setText("Select the Process to profile."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; jPanel2.add(jLabel2, gridBagConstraints); jLabel1.setLabelFor(jComboBox1); jLabel1.setText("Filter:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); jPanel2.add(jLabel1, gridBagConstraints); jComboBox1.setEditable(true); jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { " " })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); jPanel2.add(jComboBox1, gridBagConstraints); jButton1.setText("Refresh"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); jPanel2.add(jButton1, gridBagConstraints); processesTable.setAutoCreateRowSorter(true); processesTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null} }, new String [] { "User Name", "PID", "PPID", "Start Time", "CPU time", "Command" } ) { Class[] types = new Class [] { java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class }; boolean[] canEdit = new boolean [] { false, false, false, false, false, false }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit [columnIndex]; } }); processesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane2.setViewportView(processesTable); processesTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); jPanel2.add(jScrollPane2, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 12); add(jPanel2, gridBagConstraints); jPanel3.setLayout(new java.awt.GridBagLayout()); jTextField1.setColumns(12); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); jPanel3.add(jTextField1, gridBagConstraints); jLabel3.setLabelFor(jTextField1); jLabel3.setText("Target PID:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; jPanel3.add(jLabel3, gridBagConstraints); jComboBox2.setEditable(true); jComboBox2.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "test.1.er" })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jComboBox2, gridBagConstraints); jLabel4.setLabelFor(jComboBox2); jLabel4.setText("Experiment Name:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); jPanel3.add(jLabel4, gridBagConstraints); jComboBox3.setEditable(true); jComboBox3.setModel(new javax.swing.DefaultComboBoxModel(new String[] { " " })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jComboBox3, gridBagConstraints); jLabel5.setLabelFor(jComboBox3); jLabel5.setText("Experiment Directory:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); jPanel3.add(jLabel5, gridBagConstraints); jComboBox4.setEditable(true); jComboBox4.setModel(new javax.swing.DefaultComboBoxModel(new String[] { " " })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jComboBox4, gridBagConstraints); jLabel6.setLabelFor(jComboBox4); jLabel6.setText("Experiment Group:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); jPanel3.add(jLabel6, gridBagConstraints); jTextField2.setEditable(false); jTextField2.setText("gp-display-text"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); jPanel3.add(jTextField2, gridBagConstraints); jLabel7.setLabelFor(jTextField2); jLabel7.setText("Target Name:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 8, 0, 0); jPanel3.add(jLabel7, gridBagConstraints); jButton2.setText("..."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jButton2, gridBagConstraints); jButton6.setText("..."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jButton6, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 12, 12, 12); add(jPanel3, gridBagConstraints); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JButton jButton6; private javax.swing.JComboBox jComboBox1; private javax.swing.JComboBox jComboBox2; private javax.swing.JComboBox jComboBox3; private javax.swing.JComboBox jComboBox4; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JLabel jLabel5; private javax.swing.JLabel jLabel6; private javax.swing.JLabel jLabel7; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JTextField jTextField1; private javax.swing.JTextField jTextField2; private javax.swing.JTable processesTable; // End of variables declaration//GEN-END:variables /** Initialize combo boxes with default values */ public void postInitComponents() { AnUtility.setTextAndAccessibleContext( jLabel2, AnLocale.getString("Select the Process to profile.")); AnUtility.setTextAndAccessibleContext(jLabel1, AnLocale.getString("Filter:")); jLabel1.setDisplayedMnemonic(AnLocale.getString('F', "MN_PROFILE_RUNNING_PROCESS_Filter")); jLabel1.setLabelFor(jComboBox1); AnUtility.setTextAndAccessibleContext(jLabel3, AnLocale.getString("Target PID:")); AnUtility.setTextAndAccessibleContext(jLabel4, AnLocale.getString("Experiment Name:")); AnUtility.setTextAndAccessibleContext(jLabel5, AnLocale.getString("Experiment Directory:")); AnUtility.setTextAndAccessibleContext(jLabel6, AnLocale.getString("Experiment Group:")); AnUtility.setTextAndAccessibleContext(jLabel7, AnLocale.getString("Target Name:")); AnUtility.setTextAndAccessibleContext(jButton1, AnLocale.getString("Refresh")); jButton1.setMnemonic(AnLocale.getString('R', "MN_PROFILE_RUNNING_PROCESS_Refresh")); AnUtility.setAccessibleContext(jButton2.getAccessibleContext(), AnLocale.getString("Browse")); AnUtility.setAccessibleContext(jButton6.getAccessibleContext(), AnLocale.getString("Browse")); AnUtility.setAccessibleContext( processesTable.getTableHeader().getAccessibleContext(), AnLocale.getString("Process Table")); processesTable.getSelectionModel().addListSelectionListener(new SelectionHandler()); jComboBox1.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); jComboBox1.setSelectedItem(""); // Filter String user = System.getProperty("user.name"); jComboBox1.addItem(user); // Filter jComboBox2.setSelectedItem("test.1.er"); // Experiment name // jComboBox2.addItem(empty_str); // Experiment name jComboBox3.setSelectedItem(""); // Experiment directory // jComboBox3.addItem(empty_str); // Experiment directory jComboBox4.setSelectedItem(""); // Experiment group // jComboBox4.addItem(empty_str); // Experiment group jButton1.addActionListener(new RefreshActionHandler()); // Refresh jButton2.addActionListener(new ExpDirActionHandler()); // Experiment directory browser jButton6.addActionListener(new ExpGroupActionHandler()); // Experiment group browser // Init column names tableColumns[0] = AnLocale.getString("User Name") + " (UID)"; tableColumns[1] = AnLocale.getString("Process ID") + " (PID)"; tableColumns[2] = AnLocale.getString("Parent Process ID") + " (PPID)"; tableColumns[3] = AnLocale.getString("Start Time") + " (START TIME)"; tableColumns[4] = AnLocale.getString("CPU Time") + " (CPU TIME)"; tableColumns[5] = AnLocale.getString("Process name") + " (COMMAND)"; // Popup menu menuListener = new AnMenuListener(this, processesTable); processesTable.addMouseListener(menuListener); KeyStroke ks = KeyboardShortcuts.contextMenuActionShortcut; processesTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, ks); processesTable .getActionMap() .put( ks, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { JPopupMenu popup = initPopup(processesTable); if (popup != null) { JTable src = (JTable) ev.getSource(); Rectangle cellRect, visRect; visRect = src.getVisibleRect(); cellRect = visRect; if (cellRect.width > 0) { // calculate a good place to show the menu cellRect.x += cellRect.width / 4; } if (cellRect.height > 0) { cellRect.y += cellRect.height / 4; } popup.show(src, cellRect.x, cellRect.y); } } }); jTextField2.setColumns(50); } /** Copy all lines to the system clipboard */ protected void copyAll() { String text = ""; int rows = processesTable.getRowCount(); int columns = processesTable.getColumnCount(); int collen[] = new int[columns]; // Print table header for (int j = 0; j < columns; j++) { if (tableColumns.length > j) { String s = tableColumns[j]; text += s; collen[j] = s.length(); } if (columns - 1 == j) { break; } text += " | "; } text += "\n"; // Print table rows for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { String s = processesTable.getValueAt(i, j).toString(); text += s; // Try to format the string if (columns - 1 == j) { break; } int k = collen[j] - s.length(); while (k > 0) { text += " "; k--; } text += " | "; } text += "\n"; } // copyToClipboard(text); StringSelection data = new StringSelection(text); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(data, data); } public void update() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { updateTable(); updateSelection(); updateTextFields(); } }); } private void updateTable() { AnUtility.checkIfOnAWTThread(true); final String f = "/bin/ps -ef"; AnUtility.checkIPCOnWrongThread(false); String p = Collector.getRunningProcesses(f); // IPC call String o = Collector.getOSFamily(); // IPC call AnUtility.checkIPCOnWrongThread(true); PsParser psParser = PsParser.getDefault(o); psParser.setPsOutput(p); List th = psParser.getData(true).header(); // Headers // Customize column names for (int i = 0; i < th.size(); i++) { String s = th.get(i); if ("STIME".equals(s)) { th.set(i, "START TIME"); } if ("TIME".equals(s)) { th.set(i, "CPU TIME"); } if ("CMD".equals(s)) { th.set(i, "COMMAND"); } } java.util.regex.Pattern re = java.util.regex.Pattern.compile("."); String filter = getFilter(); if (!"".equals(filter)) { re = java.util.regex.Pattern.compile(".*" + filter + ".*"); } List> tp = psParser.getData(true).processes(re); // Processes // Convert List> to Object[][].... List tpList = new ArrayList(); for (List object : tp) { tpList.add(object.toArray()); } Object[][] tpArray = new Object[tpList.size()][]; int index = 0; for (Object[] x : tpList) { tpArray[index++] = x; } ((DefaultTableModel) processesTable.getModel()).setDataVector(tpArray, th.toArray()); // Set coulumn widths (available space goes to last column) for (int i = 0; i < processesTable.getColumnCount() - 1; i++) { processesTable.getColumnModel().getColumn(i).setPreferredWidth(80); processesTable.getColumnModel().getColumn(i).setMaxWidth(300); } } /** * Get Filter * * @return String filter */ private String getFilter() { String filter = ""; if (null != jComboBox1.getSelectedItem()) { filter = jComboBox1.getSelectedItem().toString(); } return filter; } /** * Get Process ID * * @return String PID */ public String getProcessID() { String PID = ""; processID = jTextField1.getText(); if (null != processID) { PID = processID; } return PID; } /** * Get Experiment Directory * * @return String directory */ public String getExperimentDirectory() { String expdir = ""; if (null != jComboBox3.getSelectedItem()) { expdir = jComboBox3.getSelectedItem().toString(); } if (expdir.length() < 1) { // XXX should it be here? expdir = CGetCurDir(); // IPC call } return expdir; } /** * Set Experiment Directory * * @param expdir */ public void setExperimentDirectory(String expdir) { jComboBox3.setSelectedItem(expdir); } /** * Get Experiment Name * * @return String directory */ public String getExperimentName() { String expdir = ""; if (null != jComboBox2.getSelectedItem()) { expdir = jComboBox2.getSelectedItem().toString(); } return expdir; } /** * Get Experiment Group * * @return String group */ public String getExperimentGroup() { String group = ""; if (null != jComboBox4.getSelectedItem()) { group = jComboBox4.getSelectedItem().toString(); } return group; } /** * Set Experiment Group * * @param expdir */ public void setExperimentGroup(String group) { jComboBox4.setSelectedItem(group); } /** * Get Current Directory * * @return */ private String CGetCurDir() { return Analyzer.getInstance().getWorkingDirectory(); } /** * Get Preview Command * * @return String command */ public String getPreviewCommand() { String col_cmd = "collect"; col_cmd += " -P " + getProcessID(); // jTextField1.getText(); col_cmd += " -d " + getExperimentDirectory(); // jComboBox3.getItemAt(0); col_cmd += " -o " + getExperimentName(); // jComboBox2.getItemAt(0); col_cmd += " -g " + getExperimentGroup(); // jComboBox4.getItemAt(0); System.out.println(col_cmd); // DEBUG return col_cmd; } private void actionPerformed2(final ActionEvent event) { int i; final String cmd = event.getActionCommand(); final String empty = ""; final String slash = "/"; if (cmd.equals(empty)) { int theState = event.getID(); // state change event if (theState == Collector.COLLECTING_RUNNING) { // if (buttons[0].isEnabled()) { // the collection has just started // writeln(AnLocale.getString("Running: ") + new File(target.getText()).getName(), // getOutLog()); // set_runtime_buttons(); // } else { // the collection has been resumed // writeln(AnLocale.getString("Data collection resumed"), getOutLog()); // writeln("(" + AnLocale.getString("process id ") + m_collector.getProcessPID() + ")", // getOutLog()); // buttons[2].setText(AnLocale.getString("Pause")); // buttons[2].setActionCommand(AnLocale.getString("Pause")); // } } else if (theState == Collector.COLLECTING_PAUSED) { // writeln(AnLocale.getString("Data collection paused"), getOutLog()); // writeln("(" + AnLocale.getString("process id ") + m_collector.getProcessPID() + ")", // getOutLog()); // buttons[2].setText(AnLocale.getString("Resume")); // buttons[2].setActionCommand(AnLocale.getString("Resume")); } else if (theState == Collector.COLLECTING_TERMINATING) { // writeln(AnLocale.getString("Data collection terminating"), getOutLog()); } else if ((theState == Collector.COLLECTING_TERMINATED) || (theState == Collector.COLLECTING_COMPLETED)) { if (theState == Collector.COLLECTING_TERMINATED) { // writeln(AnLocale.getString("Data collection terminated"), getOutLog()); } // NM if (output_thread != null) { // NM Thread stopped = output_thread; // NM output_thread=null; // NM stopped.interrupt(); // NM } // writeln(AnLocale.getString("Process ID: ") + m_collector.getProcessPID(), getOutLog()); // writeln(AnLocale.getString("Elapsed Time: ") + m_collector.getElapsedTime() + " ms", // getOutLog()); // writeln(AnLocale.getString("Execution completed, exit status is ") + // m_collector.getProcessExitValue(), getOutLog()); // final String actual_expname = m_collector.getActualExpName(); // getBtClear().setEnabled(true); // resetButtons(); // exp_name.setValue(m_collector.getNextExpName()); } } else if (cmd.equals(AnLocale.getString("Refresh"))) { if (anWindow != null) { update(); } else { // TEST refreshPS(processesTable); updateSelection(); updateTextFields(); } } else if (cmd.equals(AnLocale.getString("Pause"))) { // if (m_collector.pause(AnUtility.getSignalValue(pause_sig.getValue()))) { // } // tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Resume"))) { // if (m_collector.resume(AnUtility.getSignalValue(pause_sig.getValue()))) { // } // tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Sample"))) { // if (m_collector.sample(AnUtility.getSignalValue(sample_sig.getValue()))) { // writeln(AnLocale.getString("Manual sample"), getOutLog()); // } // tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Terminate"))) { } else if (cmd.equals(AnLocale.getString("Preview Command:"))) { System.out.println(getPreviewCommand()); } else if (cmd.equals(AnLocale.getString("Cancel"))) { } else { // showChooser(cmd); } } private void updateSelection() { AnUtility.checkIfOnAWTThread(true); String last_pid = processID; // jTextField1.getText(); if ((last_pid != null) && (last_pid.length() > 0)) { // Check if selection is still correct int row = processesTable.getSelectedRow(); int count = processesTable.getRowCount(); if (count < row) { row = -1; } if (row >= 0) { String s = processesTable.getModel().getValueAt(row, 1).toString(); if (!last_pid.equals(s)) { row = -1; } } if (row < 0) { // Find last_pid in the table for (row = 0; row < count; row++) { String s = processesTable.getModel().getValueAt(row, 1).toString(); if (last_pid.equals(s)) { if (row != processesTable.getSelectedRow()) { processesTable.setRowSelectionInterval(row, row); } return; } } // Not found - select first row row = 0; } // New selection if (row < count) { processesTable.setRowSelectionInterval(row, row); return; } } if (null == processID) { // first time processesTable.clearSelection(); } else { int count = processesTable.getRowCount(); if (count > 0) { // select first row int row = 0; processesTable.setRowSelectionInterval(row, row); } } } private void updateTextFields() { AnUtility.checkIfOnAWTThread(true); int rows = processesTable.getRowCount(); if (rows <= 0) { return; } int row = processesTable.getSelectedRow(); if (row < 0) { row = 0; } if (rows < row) { row = 0; } int lastCol = processesTable.getColumnCount() - 1; if (lastCol > 0) { // Get process ID String p = processesTable.getValueAt(row, 1).toString(); jTextField1.setText(p); // Process ID processID = p; // Get process name String s = processesTable.getValueAt(row, lastCol).toString(); int spaceind = s.indexOf(' '); if (spaceind > 0) { s = s.substring(0, spaceind); } jTextField2.setText(s); // Process name } } private final class SelectionHandler implements ListSelectionListener { @Override public void valueChanged(ListSelectionEvent evt) { updateTextFields(); } } /** Refresh Action handler */ private final class RefreshActionHandler implements ActionListener { @Override public void actionPerformed(final ActionEvent event) { processID = jTextField1.getText(); update(); } } /** * "Choose Experiment Directory" action handler Call file chooser and update Experiment Directory */ private final class ExpDirActionHandler implements ActionListener { AnChooser ac = null; String dir = null; @Override public void actionPerformed(final ActionEvent event) { String title = AnLocale.getString("Experiment Directory"); if (null == ac) { ac = anWindow.getAnChooser(title, AnChooser.DIR_CHOOSER, dir); } if ((ac.showOpenDialog(workPanel) == AnChooser.APPROVE_OPTION) && ((ac.getSelectedFile()) != null)) { dir = ac.getSelectedFile().getAbsolutePath(); setExperimentDirectory(dir); } } } /** "Choose Experiment Group" action handler Call file chooser and update Experiment Group */ private final class ExpGroupActionHandler implements ActionListener { AnChooser ac = null; String dir = null; @Override public void actionPerformed(final ActionEvent event) { String title = AnLocale.getString("Experiment Group"); if (null == ac) { ac = anWindow.getAnChooser(title, AnChooser.EXP_GROUP_CHOOSER, dir); } if ((ac.showOpenDialog(workPanel) == AnChooser.APPROVE_OPTION) && ((ac.getSelectedFile()) != null)) { dir = ac.getSelectedFile().getParent(); String group = ac.getSelectedFile().getName(); setExperimentGroup(group); } } } // ================================= UNIT TESTING ===================================== // // For unit testing public static void main(final String[] args) { final int size; String str_args; if (args != null) { size = args.length; if (size > 0) { str_args = ""; for (int i = 1; i < size; i++) { if (i != 1) { str_args += " "; } str_args += args[i]; } } } CollectPanel2 cp = new CollectPanel2(null); cp.Test(cp); } public void Test(CollectPanel2 cp) { final JFrame mframe = new JFrame(); // CollectPanel2 cp = new CollectPanel2(); cp.jButton1.addActionListener(new ActionHandler()); // cp.jButton5.addActionListener(new ActionHandler()); // Preview JScrollPane work_pane = new JScrollPane(cp); work_pane.setMinimumSize(new Dimension(AnVariable.WIN_SIZE)); mframe.add(work_pane); processesTable.setColumnSelectionAllowed(false); processesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); processesTable.getSelectionModel().addListSelectionListener(new SelectionHandler()); jTextField1.setText("25457"); refreshPS(processesTable); updateSelection(); processesTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); // jTable1.setAutoResizeMode(Table.AUTO_RESIZE_LAST_COLUMN); processesTable.doLayout(); mframe.pack(); mframe.setVisible(true); } // Action handler private final class ActionHandler implements ActionListener { @Override public void actionPerformed(final ActionEvent event) { if (anWindow == null) { // TEST refreshPS(processesTable); } actionPerformed2(event); } } private static String[] ps = { "tester 883 882 Nov_09 35:55 /usr/lib/ssh/sshd", "tester 1022 1012 Nov_09 0:00 -csh", "tester 327 23523 16:18:05 0:00 ps -aef", "tester 27385 27384 Dec_04 0:05 /usr/lib/ssh/sshd", "tester 11582 893 Nov_20 0:00 /bin/sh /bin/firefox", "tester 4664 2140 Nov_28 0:00 vertool" }; static boolean resized = false; // Window handler private void refreshPS(JTable t) { int ps_index = 0; String empty_str = ""; String filter = empty_str; if (null != jComboBox1.getSelectedItem()) { filter = jComboBox1.getSelectedItem().toString(); } for (int i = 0; i < t.getRowCount(); i++) { char space = ' '; String s1, s2, s3, s4, s5, s6; String s = empty_str; if ((i < ps.length) && (ps_index < ps.length)) { for (; ps_index < ps.length; ps_index++) { s1 = ps[ps_index]; if (filter.length() > 0) { // Apply filter if (s1.indexOf(filter) < 0) { continue; } } s = s1; ps_index++; break; } } if (s.length() <= 0) { t.setValueAt(s, i, 0); t.setValueAt(s, i, 1); t.setValueAt(s, i, 2); t.setValueAt(s, i, 3); t.setValueAt(s, i, 4); t.setValueAt(s, i, 5); continue; } int p1 = 0; int p2 = s.indexOf(space); // user name s1 = s.substring(p1, p2); t.setValueAt(s1, i, 0); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.indexOf(space, p1); // PID s2 = s.substring(p1, p2); t.setValueAt(s2, i, 1); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.indexOf(space, p1); // PPID s3 = s.substring(p1, p2); t.setValueAt(s3, i, 2); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.indexOf(space, p1); // Start time s4 = s.substring(p1, p2); t.setValueAt(s4, i, 3); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.indexOf(space, p1); // CPU time s5 = s.substring(p1, p2); t.setValueAt(s5, i, 4); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.length(); // Command s6 = s.substring(p1, p2); t.setValueAt(s6, i, 5); } // if (!resized) { // resized = true; // // Resize jTable1 // TableColumnModel tcm = t.getColumnModel(); // TableColumn tc = tcm.getColumn(0); // int w = tc.getWidth(); // tc.setPreferredWidth((w * 2) / 3); // tc.setWidth((w * 2) / 3); // tc = tcm.getColumn(1); // w = tc.getWidth(); // tc.setPreferredWidth(w / 2); // tc.setWidth(w / 2); // tc = tcm.getColumn(2); // w = tc.getWidth(); // tc.setPreferredWidth(w / 2); // tc.setWidth(w / 2); // tc = tcm.getColumn(3); // w = tc.getWidth(); // tc.setPreferredWidth(w / 2); // tc.setWidth(w / 2); // tc = tcm.getColumn(4); // w = tc.getWidth(); // tc.setPreferredWidth(w / 2); // tc.setWidth(w / 2); // tc = tcm.getColumn(5); // w = tc.getWidth(); // tc.setPreferredWidth(w * 4); // tc.setWidth(w * 4); // } } /* * Generic action for context menu items. * Action name is passed as String. */ class UpdateAction extends AbstractAction { String actionName = null; public UpdateAction(String name) { super(name); this.actionName = name; } public UpdateAction(String name, String actionName) { super(name); this.actionName = actionName; } @Override public void actionPerformed(ActionEvent ev) { // Use AWT thread to perform some actions if (actionName.equals(STR_ACTION_UPDATE)) { update(); return; } if (actionName.equals(STR_ACTION_COPY_ALL)) { copyAll(); return; } // if (actionName.startsWith(STR_ACTION_SORTBY)) { for (int i = 0; i < tableColumns.length; i++) { if (actionName.contains(tableColumns[i])) { processesTable.getRowSorter().toggleSortOrder(i); return; } } // } } } private JPopupMenu initPopup(JTable table) { AccessibleContext ac; JMenuItem mi; JPopupMenu popup = new JPopupMenu(); String txt; boolean row_selected = false; int row = table.getSelectedRow(); if (row >= 0) { row_selected = true; } // Add "Update List of Processes" action txt = STR_ACTION_UPDATE; mi = new JMenuItem(new UpdateAction(txt)); mi.setMnemonic(AnLocale.getString('R', "MN_PROFILE_PROCESS_Refresh_MENU_ITEM")); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); // String hotkey = "CTRL_U"; // KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_U, InputEvent.CTRL_DOWN_MASK, // false); // table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, hotkey); // UpdateAction act = new UpdateAction(txt); // table.getActionMap().put(hotkey, act); // mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_U, ActionEvent.CTRL_MASK)); mi.setEnabled(true); popup.add(mi); // Add "Set Metric" action txt = STR_ACTION_SORTBY; UpdateAction sm = new UpdateAction(txt); mi = new JMenuItem(sm); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (tableColumns.length <= 1) { mi.setEnabled(false); popup.add(mi); } else { JMenu submenu1; submenu1 = new JMenu(txt); for (int i = 0; i < tableColumns.length; i++) { txt = tableColumns[i]; sm = new UpdateAction(txt); mi = new JMenuItem(sm); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(STR_ACTION_SORTBY + ":" + txt); mi.setEnabled(true); submenu1.add(mi); } popup.add(submenu1); } // Add separator popup.addSeparator(); // Add menu item "Copy All" txt = STR_ACTION_COPY_ALL; UpdateAction cs = new UpdateAction(txt); mi = new JMenuItem(cs); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); popup.add(mi); return popup; } // ------- Private classes to implement popup menu items ------- // private class AnMenuListener extends MouseAdapter { private boolean debug; CollectPanel2 cp; JTable ptable; AnMenuListener(CollectPanel2 collectPanel, JTable table) { this.cp = collectPanel; this.ptable = table; debug = false; } // Experimental code, mostly "quick and dirty hack" public JPopupMenu initPopup(MouseEvent event) { return cp.initPopup(ptable); } /** Check for double click to performs default action */ @Override public void mouseClicked(final MouseEvent e) {} @Override public void mousePressed(MouseEvent e) { maybeShowPopup(e); } @Override public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { JPopupMenu popup = initPopup(e); if (popup != null) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeInvisible(" + e + ")"); } } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeVisible(" + e + ")"); } } public void popupMenuCanceled(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuCanceled(" + e + ")"); } } } } gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectDialog.java0000644000175000017500000001057014517772113020735 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.collect; import org.gprofng.mpmt.AnDialog; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.event.ActionEvent; import javax.swing.JButton; import javax.swing.JFrame; public final class CollectDialog extends AnDialog implements CollectPanel.Provider { private final CollectPanel collectPanel; private final Collector collector; private int prof_type = Collector.PROFILE_APPLICATION; // Constructor public CollectDialog( final AnWindow awindow, final JFrame frame, int profiling_type, String title) { super( awindow, frame, /*CollectPanel.title*/ title, false, CollectPanel.aux, CollectPanel.mnemonic, getHelpID(profiling_type), false /* not modal */); final JButton buttons[] = new JButton[] {ok, apply, aux_actions[0], aux_actions[1], close}; close_on_enter = false; try { if (Analyzer.getInstance().IPC_started == false) { Analyzer.getInstance().startIPC(); } } catch (Exception e) { // Should never come here System.err.println("analyzer: Exception in CollectDialog"); e.printStackTrace(); System.exit(1); } collector = new Collector(window); prof_type = profiling_type; collector.setProfilingType(prof_type); AnUtility.checkIPCOnWrongThread(false); if (prof_type == Collector.SYSTEM_PROFILING) { // profile kernel JButton buttons2[] = new JButton[] {ok, apply, aux_actions[0], aux_actions[1], close}; collectPanel = new CollectPanel(collector, this, this, window, buttons2); } else if (prof_type == Collector.PROFILE_RUNNING_APPLICATION) { // profile running application JButton buttons1[] = new JButton[] {ok, apply, aux_actions[0], aux_actions[1], close}; collectPanel = new CollectPanel(collector, this, this, window, buttons1); } else { // profile new application collectPanel = new CollectPanel(collector, this, this, window, buttons); } AnUtility.checkIPCOnWrongThread(true); setAccessory(collectPanel.work_panel); } private static String getHelpID(int profiling_type) { if (profiling_type == Collector.PROFILE_APPLICATION) { return AnVariable.HELP_CollectDialog; } else if (profiling_type == Collector.PROFILE_RUNNING_APPLICATION) { return AnVariable.HELP_CollectRunningDialog; } else if (profiling_type == Collector.SYSTEM_PROFILING) { return AnVariable.HELP_CollectKernelDialog; } else { return AnVariable.HELP_CollectDialog; } } // Constructor public CollectDialog(final AnWindow awindow, final JFrame frame) { this(awindow, frame, 0, CollectPanel.title); } public void doDialog() { collectPanel.loadExpDefaults(); setVisible(true); } public void doDialog(String[] arguments) { collectPanel.loadExpDefaults(); if ((arguments != null) && (arguments.length > 0)) { collectPanel.target.setValue(arguments[0]); String args = ""; for (int i = 1; i < arguments.length; i++) { if (i > 1) { args += " "; } args += arguments[i]; } collectPanel.args.setValue(args); } setVisible(true); } @Override public void setTitleStr(final String title) { setTitle(title); } public void loadExpDefaults() { collectPanel.loadExpDefaults(); } // Action performed; run collect @Override public void actionPerformed(final ActionEvent event) { collectPanel.actionPerformed(event); } @Override public void setVisible(boolean aFlag) { if (collectPanel != null) { collectPanel.closeHWCDialogs(); } super.setVisible(aFlag); } } gprofng-gui-1.0/org/gprofng/mpmt/collect/HWCSelectDialog.java0000644000175000017500000000560214517772113021131 00000000000000/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ package org.gprofng.mpmt.collect; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.util.gui.AnDialog2; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dialog; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; import java.util.Map; import javax.swing.JButton; public class HWCSelectDialog extends AnDialog2 { private CollectPanel collectPanel; private HWCSelectPanel hwcSelectPanel; public HWCSelectDialog( Dialog dialog, CollectPanel collectPanel, List hwcFlatList, Map hwcNameMap) { super(dialog, collectPanel, AnLocale.getString("Select Hardware Counters")); this.collectPanel = collectPanel; hwcSelectPanel = new HWCSelectPanel(this, hwcFlatList, hwcNameMap); setHelpTag(AnVariable.HELP_CollectDialog); setCustomPanel(hwcSelectPanel); getHelpButton().setVisible(true); getOKButton().setText(AnLocale.getString("Add")); getOKButton().setMnemonic((AnLocale.getString('A', "HWCSelectDialog.Add"))); setModal(false); JButton HWCHelpButton = new JButton(AnLocale.getString("Hardware Counter Descriptions")); AnUtility.setAccessibleContext( HWCHelpButton.getAccessibleContext(), AnLocale.getString("Hardware Counter Help")); HWCHelpButton.setMnemonic((AnLocale.getString('C', "HWCSelectDialog.availableCountersButton"))); HWCHelpButton.setToolTipText(AnLocale.getString("Hardware Counter Help")); HWCHelpButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { HWCSelectDialog.this.collectPanel.showAvailableCountersDialog(); } }); addAuxButton(HWCHelpButton); } @Override public void setVisible(boolean b) { if (b) { hwcSelectPanel.resetGUI(); } super.setVisible(b); } protected List getSelectedEntries() { return hwcSelectPanel.getSelectedEntries(); } @Override protected void setStatus(Status status) { super.setStatus(status); if (getStatus() == AnDialog2.Status.OK) { List selectedList = getSelectedEntries(); collectPanel.addHWCEntry(selectedList); } } } gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectPanel2.form0000644000175000017500000005124114517772113020701 00000000000000

<Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> </TableColumnModel> </Property> <Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor"> <JTableSelectionModel selectionMode="0"/> </Property> <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> <TableHeader reorderingAllowed="true" resizingAllowed="true"/> </Property> </Properties> </Component> </SubComponents> </Container> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="jPanel3"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="12" insetsBottom="12" insetsRight="12" anchor="15" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JTextField" name="jTextField1"> <Properties> <Property name="columns" type="int" value="12"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel3"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jTextField1"/> </Property> <Property name="text" type="java.lang.String" value="Target PID:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="jComboBox2"> <Properties> <Property name="editable" type="boolean" value="true"/> <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> <StringArray count="1"> <StringItem index="0" value="test.1.er"/> </StringArray> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="1" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel4"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jComboBox2"/> </Property> <Property name="text" type="java.lang.String" value="Experiment Name:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="jComboBox3"> <Properties> <Property name="editable" type="boolean" value="true"/> <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> <StringArray count="1"> <StringItem index="0" value=" "/> </StringArray> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="2" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel5"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jComboBox3"/> </Property> <Property name="text" type="java.lang.String" value="Experiment Directory:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="jComboBox4"> <Properties> <Property name="editable" type="boolean" value="true"/> <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> <StringArray count="1"> <StringItem index="0" value=" "/> </StringArray> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="3" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel6"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jComboBox4"/> </Property> <Property name="text" type="java.lang.String" value="Experiment Group:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="jTextField2"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="text" type="java.lang.String" value="gp-display-text"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="3" gridY="0" gridWidth="4" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel7"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jTextField2"/> </Property> <Property name="text" type="java.lang.String" value="Target Name:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="8" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="jButton2"> <Properties> <Property name="text" type="java.lang.String" value="..."/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="5" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="jButton6"> <Properties> <Property name="text" type="java.lang.String" value="..."/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="5" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> </SubComponents> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectorOpenPanel.form������������������������������������0000644�0001750�0001750�00000011712�14517772113�022001� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="label1"> <Properties> <Property name="text" type="java.lang.String" value="jLabel1"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="experimentLabel"> <Properties> <Property name="text" type="java.lang.String" value="jLabel3"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="pathTextField"> <Properties> <Property name="editable" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="configurationOuterPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="12" insetsRight="0" anchor="23" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout> <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="0" max="32767" attributes="0"/> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="0" max="32767" attributes="0"/> </Group> </DimensionLayout> </Layout> </Container> </SubComponents> </Form> ������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/HWCSelectPanel.java����������������������������������������0000644�0001750�0001750�00000100652�14517772113�020772� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.collect; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.picklist.StringPickList; import org.gprofng.mpmt.picklist.StringPickListElement; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; public class HWCSelectPanel extends JPanel { private HWCSelectDialog dialog; private List<HWCEntry> hwcFlatList; // All counters private List<HWCEntry> hwcFilteredList; // Filtered counters only private final Map<String, HWCEntry> hwcNameMap; private TableModel tableModel; private JTable table; private static StringPickList includePicklist = new StringPickList(); private static StringPickList excludePicklist = new StringPickList(); private ItemListener includeItemListener = null; private ItemListener excludeItemListener = null; private JMenuItem copySelectedItems; private JMenuItem copyAllItems; public HWCSelectPanel( HWCSelectDialog dialog, List<HWCEntry> hwcFlatList, Map<String, HWCEntry> hwcNameMap) { AnUtility.checkIfOnAWTThread(true); this.dialog = dialog; this.hwcFlatList = hwcFlatList; this.hwcNameMap = hwcNameMap; initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); AnUtility.setTextAndAccessibleContext( infoLabel, AnLocale.getString( "Select one or more HW counters from the list of available counters below.")); // Filter panel filterPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); AnUtility.setTextAndAccessibleContext(filterLabel, " " + AnLocale.getString("Filters")); filterLabel.setLabelFor(includeComboBox); filterLabel.setOpaque(true); checkBoxPanel.setOpaque(false); recommendedIconLabel.setIcon(AnUtility.circleGreenIcon); recommendedCheckBox.setOpaque(false); recommendedCheckBox.setSelected(false); AnUtility.setTextAndAccessibleContext( recommendedCheckBox, AnLocale.getString("Recommended (R)")); recommendedCheckBox.setToolTipText(AnLocale.getString("Recommended hardware counters")); recommendedCheckBox.setMnemonic(AnLocale.getString('R', "HWCSelectPanel.recommendedCheckBox")); timeIconLabel.setIcon(AnUtility.circleRedIcon); timeCheckBox.setOpaque(false); timeCheckBox.setSelected(false); AnUtility.setTextAndAccessibleContext(timeCheckBox, AnLocale.getString("Time (T)")); timeCheckBox.setToolTipText(AnLocale.getString("Hardware counters supporting time profiling")); timeCheckBox.setMnemonic(AnLocale.getString('T', "HWCSelectPanel.timeCheckBox")); memoryIconLabel.setIcon(AnUtility.circleBlueIcon); memoryCheckBox.setOpaque(false); memoryCheckBox.setSelected(false); AnUtility.setTextAndAccessibleContext(memoryCheckBox, AnLocale.getString("Memoryspace (M)")); memoryCheckBox.setToolTipText( AnLocale.getString("Hardware counters supporting memory profiling")); memoryCheckBox.setMnemonic(AnLocale.getString('M', "HWCSelectPanel.memoryCheckBox")); String includeTT = AnLocale.getString("Include entries that contain any of these text strings"); includeLabel.setText(AnLocale.getString("Include:")); includeLabel.setToolTipText(includeTT); includeLabel.setDisplayedMnemonic( AnLocale.getString('I', "HWCSelectPanel.IncludeLabelMnemonic")); includeLabel.setLabelFor(includeComboBox); includeComboBox.setToolTipText(includeTT); String excludeTT = AnLocale.getString("Exclude entries that contain any of these text strings"); excludeLabel.setToolTipText(excludeTT); excludeLabel.setText(AnLocale.getString("Exclude:")); excludeLabel.setDisplayedMnemonic( AnLocale.getString('X', "HWCSelectPanel.ExcludeLabelMnemonic")); excludeLabel.setLabelFor(excludeComboBox); excludeComboBox.setToolTipText(excludeTT); refreshButton.setText(AnLocale.getString("Refresh")); refreshButton.setMnemonic(AnLocale.getString('f', "HWCSelectPanel.RefreshButton")); refreshButton.setToolTipText(AnLocale.getString("Apply filters")); includeComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); excludeComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); // Label panel listLabelPanel.setOpaque(false); AnUtility.setTextAndAccessibleContext(listLabel, AnLocale.getString("Available Counters")); listLabel.setDisplayedMnemonic(AnLocale.getString('V', "HWCSelectPanel.listLabel")); // Table tablePanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); tablePanel.setLayout(new BorderLayout()); table = new JTable(tableModel = new TableModel()); table.setDefaultRenderer(String.class, new TableCellRenderer()); table.setBorder(null); table.setBackground(Color.WHITE); table.getTableHeader().setReorderingAllowed(false); table.setFillsViewportHeight(true); table.setAutoCreateRowSorter(true); AnUtility.setAccessibleContext( table.getTableHeader().getAccessibleContext(), AnLocale.getString("Table Header")); // Handle Enter key table.addKeyListener( new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyChar() == KeyEvent.VK_ENTER) { if (HWCSelectPanel.this.dialog.getOKButton().isEnabled()) { HWCSelectPanel.this.dialog.getOKButton().doClick(); e.consume(); } } } }); // Handle double-click table.addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { if (HWCSelectPanel.this.dialog.getOKButton().isEnabled()) { HWCSelectPanel.this.dialog.getOKButton().doClick(); e.consume(); } } } }); JPopupMenu popupMenu = new JPopupMenu(); copySelectedItems = new JMenuItem(AnLocale.getString("Copy Selected")); copySelectedItems.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { int selectedRows[] = table.getSelectedRows(); copyToClipboard(selectedRows); } }); copyAllItems = new JMenuItem(AnLocale.getString("Copy All")); copyAllItems.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { copyToClipboard(0, table.getRowCount()); } }); popupMenu.add(copySelectedItems); popupMenu.add(copyAllItems); table.setComponentPopupMenu(popupMenu); listLabel.setLabelFor(table); JScrollPane scrollPane = new JScrollPane(table); scrollPane.setBorder(null); scrollPane.setBackground(Color.WHITE); tablePanel.add(scrollPane, BorderLayout.CENTER); includeComboBox.addItemListener( includeItemListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { applyFiltersAndUpdateGUI(); } } }); excludeComboBox.addItemListener( excludeItemListener = new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (e.getStateChange() == ItemEvent.SELECTED) { applyFiltersAndUpdateGUI(); } } }); dialog.getOKButton().setEnabled(false); table .getSelectionModel() .addListSelectionListener( new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { HWCSelectPanel.this .dialog .getOKButton() .setEnabled(table.getSelectedRowCount() > 0); } }); // Set coulumn widths (available space goes to last column) table.getColumnModel().getColumn(0).setPreferredWidth(35); table.getColumnModel().getColumn(0).setMaxWidth(35); table.getColumnModel().getColumn(1).setPreferredWidth(20); table.getColumnModel().getColumn(1).setMaxWidth(20); table.getColumnModel().getColumn(2).setPreferredWidth(300); table.getColumnModel().getColumn(2).setMaxWidth(800); table.getColumnModel().getColumn(3).setPreferredWidth(100); table.getColumnModel().getColumn(3).setMaxWidth(800); for (int i = 4; i < 6; i++) { table.getColumnModel().getColumn(i).setPreferredWidth(20); table.getColumnModel().getColumn(i).setMaxWidth(20); } setPreferredSize(new Dimension(1250, 800)); applyFiltersAndUpdateGUI(); } private void copyToClipboard(int first, int last) { int selectedRows[] = new int[last - first]; for (int i = 0; i < selectedRows.length; i++) { selectedRows[i] = i + first; } copyToClipboard(selectedRows); } private void copyToClipboard(int selectedRows[]) { int[] columnWidths = getColumnWidths(selectedRows); StringBuilder buf = new StringBuilder(); // Header for (int column = 0; column < table.getColumnCount(); column++) { String headerText = (String) table.getTableHeader().getColumnModel().getColumn(column).getHeaderValue(); String format = '%' + String.format("-%ds", columnWidths[column]); buf.append(String.format(format, headerText)); } buf.append("\n"); buf.append("\n"); // Table rows for (int i : selectedRows) { buf.append(formatRowAsText(columnWidths, i)); buf.append("\n"); } copyToClipboard(buf.toString()); System.out.println(buf.toString()); } private String formatRowAsText(int[] columnWidths, int row) { StringBuilder buf = new StringBuilder(); for (int column = 0; column < table.getColumnCount(); column++) { Object object = table.getModel().getValueAt(row, column); if (object instanceof String) { String format = '%' + String.format("-%ds", columnWidths[column]); buf.append(String.format(format, object)); } } return buf.toString(); } private void copyToClipboard(String text) { StringSelection data = new StringSelection(text); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(data, data); } private int[] getColumnWidths(int selectedRows[]) { int[] columnWidths = getFixedColumnWidths(); for (int row : selectedRows) { String text; int len; text = (String) table.getModel().getValueAt(row, 2); len = text.length() + 3; if (len > columnWidths[2]) { columnWidths[2] = len; } text = (String) table.getModel().getValueAt(row, 3); len = text.length() + 3; if (len > columnWidths[3]) { columnWidths[3] = len; } text = (String) table.getModel().getValueAt(row, 6); len = text.length() + 3; if (len > columnWidths[6]) { columnWidths[6] = len; } } return columnWidths; } private int[] getFixedColumnWidths() { int[] columnWidths = new int[table.getColumnCount()]; columnWidths[0] = 4; columnWidths[1] = 2; columnWidths[2] = 0; // variable width columnWidths[3] = 0; // variable width columnWidths[4] = 2; columnWidths[5] = 2; columnWidths[6] = 0; // variable width return columnWidths; } protected void resetGUI() { // includeComboBox.setSelectedItem(""); // excludeComboBox.setSelectedItem(""); } private void updateFilterComboBoxes(String includeFilterString, String excludeFilterString) { includePicklist.addElement(includeFilterString); excludePicklist.addElement(excludeFilterString); updateFilterComboBoxes( includePicklist, includeFilterString, excludePicklist, excludeFilterString); } private boolean containsIgnoreCase(String string, String clause) { return string != null && string.toLowerCase().contains(clause.toLowerCase()); } private List<HWCEntry> filterEntries( List<HWCEntry> origList, String rawIncludeFilterString, boolean exclude) { String[] substrings = rawIncludeFilterString.split(" "); // multiword match //FIXUP bypass escaped spaces? // String[] substrings = {raw_includeFilterString}; // exact text match List<String> clauses = new ArrayList(); for (int ii = 0; ii < substrings.length; ii++) { if (substrings[ii].isEmpty()) { continue; // strip out empty clauses caused by consecutive spaces } clauses.add(substrings[ii]); } final List<HWCEntry> newList; if (clauses.isEmpty()) { newList = new ArrayList(origList); } else { newList = new ArrayList(); for (HWCEntry entry : origList) { boolean pass = false; for (String clause : clauses) { if (containsIgnoreCase(entry.getMetricText(), clause) || containsIgnoreCase(entry.getCounterText(), clause) || containsIgnoreCase(entry.getDescriptionText(hwcNameMap), clause)) { pass = true; break; } } if (exclude) { if (!pass) { newList.add(entry); } } else if (pass) { newList.add(entry); } } } return newList; } private void updateFilterComboBoxes( StringPickList includePicklist, String currentIncludeFilter, StringPickList excludePicklist, String currentExcludeFilter) { AnUtility.checkIfOnAWTThread(true); includeComboBox.removeAllItems(); includeComboBox.addItem(""); for (StringPickListElement elem : includePicklist.getStringElements()) { if (elem.getString().length() > 0) { includeComboBox.addItem(elem.getString()); } } if (currentIncludeFilter != null) { includeComboBox.setSelectedItem(currentIncludeFilter); } excludeComboBox.removeAllItems(); excludeComboBox.addItem(""); for (StringPickListElement elem : excludePicklist.getStringElements()) { if (elem.getString().length() > 0) { excludeComboBox.addItem(elem.getString()); } } if (currentExcludeFilter != null) { excludeComboBox.setSelectedItem(currentExcludeFilter); } } private void applyFiltersAndUpdateGUI() { AnUtility.checkIfOnAWTThread(true); // System.out.println("applyFiltersAndUpdateGUI"); includeComboBox.removeItemListener(includeItemListener); excludeComboBox.removeItemListener(excludeItemListener); hwcFilteredList = new ArrayList<HWCEntry>(); // Check boxes for (HWCEntry hwcEntry : hwcFlatList) { if (recommendedCheckBox.isSelected() && !hwcEntry.isRecommended()) { continue; } if (timeCheckBox.isSelected() && !hwcEntry.supportsTime(hwcNameMap)) { continue; } if (memoryCheckBox.isSelected() && !hwcEntry.supportsMemspace(hwcNameMap)) { continue; } hwcFilteredList.add(hwcEntry); } // Text filters String includeFilterString = (String) includeComboBox.getSelectedItem(); String excludeFilterString = (String) excludeComboBox.getSelectedItem(); if (includeFilterString == null) { includeFilterString = ""; } if (excludeFilterString == null) { excludeFilterString = ""; } hwcFilteredList = filterEntries(hwcFilteredList, includeFilterString, false); hwcFilteredList = filterEntries(hwcFilteredList, excludeFilterString, true); includeComboBox.addItem(includeFilterString); excludeComboBox.addItem(excludeFilterString); // Update table tableModel.fireTableDataChanged(); // Update labels String format0 = AnLocale.getString(" (%d/%d shown)"); maxListLabel.setText(String.format(format0, hwcFilteredList.size(), hwcFlatList.size())); String format1 = AnLocale.getString("Available HW counters, showing %s out of %s available counters"); String tooltip = String.format(format1, hwcFilteredList.size(), hwcFlatList.size()); maxListLabel.setToolTipText(tooltip); listLabel.setToolTipText(tooltip); // Update comboboxes updateFilterComboBoxes(includeFilterString, excludeFilterString); includeComboBox.addItemListener(includeItemListener); excludeComboBox.addItemListener(excludeItemListener); copySelectedItems.setEnabled(table.getRowCount() > 0); copyAllItems.setEnabled(table.getRowCount() > 0); requestTableFocus(); } private void requestTableFocus() { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { if (table.getModel().getRowCount() > 0) { table.getSelectionModel().setSelectionInterval(0, 0); table.requestFocus(); } } }); } class TableCellRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JLabel label = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); HWCEntry hwcEntry = hwcFilteredList.get(table.convertRowIndexToModel(row)); if (column == 0 || column == 1 || column == 4 || column == 5) { label.setHorizontalAlignment(JLabel.CENTER); } else { label.setHorizontalAlignment(JLabel.LEFT); } if (column == 1 && hwcEntry.isRecommended()) { label.setIcon(AnUtility.circleGreenIcon); label.setText(""); } else if (column == 4 && hwcEntry.supportsTime(hwcNameMap)) { label.setIcon(AnUtility.circleRedIcon); label.setText(""); } else if (column == 5 && hwcEntry.supportsMemspace(hwcNameMap)) { label.setIcon(AnUtility.circleBlueIcon); label.setText(""); } else { label.setIcon(null); } String ttText = hwcEntry.getDescriptionText(hwcNameMap); if (ttText == null || ttText.length() == 0) { ttText = hwcEntry.getMetricText(); } label.setToolTipText(ttText); return label; } } class TableModel extends AbstractTableModel { private String[] columnNames = { "#", AnLocale.getString("R"), AnLocale.getString("Metric"), AnLocale.getString("Counter"), AnLocale.getString("T"), AnLocale.getString("M"), AnLocale.getString("Description") }; @Override public int getColumnCount() { return columnNames.length; } @Override public int getRowCount() { int rowCount; if (hwcFilteredList == null) { rowCount = 0; } else { rowCount = hwcFilteredList.size(); } return rowCount; } @Override public String getColumnName(int col) { return columnNames[col]; } @Override public Object getValueAt(int row, int col) { if (row >= hwcFilteredList.size()) { return null; // FIXUP: why is this necessary? } HWCEntry hwcEntry = hwcFilteredList.get(row); switch (col) { case 0: { return String.format("%03d", hwcEntry.getNo()); } case 1: { return hwcEntry.isRecommended() ? "R" : ""; } case 2: { // Metric return hwcEntry.getMetricText(); } case 3: { // Counter return hwcEntry.getCounterText(); } case 4: { return hwcEntry.supportsTime(hwcNameMap) ? "T" : ""; } case 5: { return hwcEntry.supportsMemspace(hwcNameMap) ? "M" : ""; } case 6: { // Description return hwcEntry.getDescriptionText(hwcNameMap); } default: { return "???"; } } } @Override public Class getColumnClass(int c) { Object o = getValueAt(0, c); if (o != null) { return getValueAt(0, c).getClass(); } else { return super.getColumnClass(c); } } } protected List<HWCEntry> getSelectedEntries() { List<HWCEntry> list = new ArrayList<HWCEntry>(); int selected[] = table.getSelectedRows(); for (int i : selected) { list.add(hwcFilteredList.get(table.convertRowIndexToModel(i)).copy()); } return list; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; infoLabel = new javax.swing.JLabel(); filterPanel = new javax.swing.JPanel(); filterLabel = new javax.swing.JLabel(); checkBoxPanel = new javax.swing.JPanel(); recommendedIconLabel = new javax.swing.JLabel(); recommendedCheckBox = new javax.swing.JCheckBox(); timeIconLabel = new javax.swing.JLabel(); timeCheckBox = new javax.swing.JCheckBox(); memoryIconLabel = new javax.swing.JLabel(); memoryCheckBox = new javax.swing.JCheckBox(); includeLabel = new javax.swing.JLabel(); includeComboBox = new javax.swing.JComboBox(); excludeLabel = new javax.swing.JLabel(); excludeComboBox = new javax.swing.JComboBox(); refreshButton = new javax.swing.JButton(); listLabelPanel = new javax.swing.JPanel(); listLabel = new javax.swing.JLabel(); maxListLabel = new javax.swing.JLabel(); tablePanel = new javax.swing.JPanel(); setLayout(new java.awt.GridBagLayout()); infoLabel.setText("info..."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(infoLabel, gridBagConstraints); filterPanel.setLayout(new java.awt.GridBagLayout()); filterLabel.setText("Filter"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.ipady = 6; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; filterPanel.add(filterLabel, gridBagConstraints); checkBoxPanel.setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); checkBoxPanel.add(recommendedIconLabel, gridBagConstraints); recommendedCheckBox.setText("Recommended"); recommendedCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { recommendedCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); checkBoxPanel.add(recommendedCheckBox, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; checkBoxPanel.add(timeIconLabel, gridBagConstraints); timeCheckBox.setText("Time"); timeCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { timeCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; checkBoxPanel.add(timeCheckBox, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; checkBoxPanel.add(memoryIconLabel, gridBagConstraints); memoryCheckBox.setText("Memory"); memoryCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { memoryCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; checkBoxPanel.add(memoryCheckBox, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; filterPanel.add(checkBoxPanel, gridBagConstraints); includeLabel.setText("Include"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 0); filterPanel.add(includeLabel, gridBagConstraints); includeComboBox.setEditable(true); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 0); filterPanel.add(includeComboBox, gridBagConstraints); excludeLabel.setText("and exclude"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 8, 4, 0); filterPanel.add(excludeLabel, gridBagConstraints); excludeComboBox.setEditable(true); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 0); filterPanel.add(excludeComboBox, gridBagConstraints); refreshButton.setText("Refresh"); refreshButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { refreshButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 8, 4, 0); filterPanel.add(refreshButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(filterPanel, gridBagConstraints); listLabelPanel.setLayout(new java.awt.GridBagLayout()); listLabel.setText("Available Counters:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; listLabelPanel.add(listLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; listLabelPanel.add(maxListLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(listLabelPanel, gridBagConstraints); tablePanel.setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(tablePanel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void refreshButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_refreshButtonActionPerformed applyFiltersAndUpdateGUI(); } // GEN-LAST:event_refreshButtonActionPerformed private void recommendedCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_recommendedCheckBoxActionPerformed applyFiltersAndUpdateGUI(); } // GEN-LAST:event_recommendedCheckBoxActionPerformed private void timeCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_timeCheckBoxActionPerformed applyFiltersAndUpdateGUI(); } // GEN-LAST:event_timeCheckBoxActionPerformed private void memoryCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_memoryCheckBoxActionPerformed applyFiltersAndUpdateGUI(); } // GEN-LAST:event_memoryCheckBoxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel checkBoxPanel; private javax.swing.JComboBox excludeComboBox; private javax.swing.JLabel excludeLabel; private javax.swing.JLabel filterLabel; private javax.swing.JPanel filterPanel; private javax.swing.JComboBox includeComboBox; private javax.swing.JLabel includeLabel; private javax.swing.JLabel infoLabel; private javax.swing.JLabel listLabel; private javax.swing.JPanel listLabelPanel; private javax.swing.JLabel maxListLabel; private javax.swing.JCheckBox memoryCheckBox; private javax.swing.JLabel memoryIconLabel; private javax.swing.JCheckBox recommendedCheckBox; private javax.swing.JLabel recommendedIconLabel; private javax.swing.JButton refreshButton; private javax.swing.JPanel tablePanel; private javax.swing.JCheckBox timeCheckBox; private javax.swing.JLabel timeIconLabel; // End of variables declaration//GEN-END:variables } ��������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectPanel.java������������������������������������������0000644�0001750�0001750�00000526436�14517772113�020612� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.collect; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnDialog; import org.gprofng.mpmt.AnFile; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.util.gui.AnDialog2; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.io.BufferedReader; import java.io.File; import java.io.InputStream; import java.io.InputStreamReader; import java.io.PipedInputStream; import java.io.PipedOutputStream; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.border.EtchedBorder; import javax.swing.border.LineBorder; import javax.swing.border.SoftBevelBorder; import javax.swing.border.TitledBorder; public final class CollectPanel extends JPanel implements ActionListener { private static final int CEXP_NA = 0; private static final int CEXP_TARGET = 1; private static final int CEXP_NAME = 2; private static final int CEXP_DIR = 3; private static final int CEXP_GROUP = 4; private static final int CEXP_WORK = 5; private static final int CEXP_LNCH = 6; private static final int CEXP_ENV = 7; protected final String CSTR_TARGET, CSTR_DIR, CSTR_GROUP, CSTR_WORK, CSTR_TARGET_JDK; private TargetJDK target_jdk = null; public CollectExp target, args, exp_name, exp_dir, exp_group, work_dir, env_vars, launcher, vm_args; public CollectData descendant, pause_sig, sample_sig, exp_limit, time_limit, arch_exp, clock_prof, sync_trace, hwc1_prof, hwc1_val, dspace_hwc1, hwc2_prof, hwc2_val, dspace_hwc2, io_trace, heap_trace, data_race, count_data, mpi_trace, jvm_prof, sample, dbxsample, ctr_attr, reg_alloc, deadlock_trace, prof_idle; private CollectPanel2 collectPanel2; // "Profile Running Process" private CollectPanel3 collectPanel3; // "System Profiling" public JTextField preview_cmd; // public JTextArea preview_cmd; // public JScrollPane work_panel; public JPanel work_panel; public JTabbedPane tab_pane; public JRadioButton startPaused, startResumed; public JLabel start_state; public JRadioButton input_output_btn1, input_output_btn2; public JLabel input_output_lbl; public List<HWCEntry> selectedHWCList; public JList hwcList; private JScrollPane hwcListScrollPane; private HWCSelectDialog hwcSelectDialog = null; private AnDialog2 availableCountersDialog = null; public List<String> sel_attr; public JList attrList; private JScrollPane attrScrollPane; public JButton updateButton, cancelButton; public JPanel buttonPanel; public boolean attr_warn; private JButton propertyButton; private JButton addHWCButton; private JButton removeButton; // private JButton showButton; private JButton remAttr; private JButton addAttr; private JButton modAttr; private JLabel counterLabel; private JLabel selectedAttrLabel; private JPanel hwcPanel; // Data to collect private final String[][] arch_data = { { AnLocale.getString("On"), AnLocale.getString("Used Sources"), AnLocale.getString("All Sources"), AnLocale.getString("Off") }, {ipc_str_on, "usedsrc", "src", ipc_str_off} }; private final String[][] desc_data = { {AnLocale.getString("On"), AnLocale.getString("Off"), AnLocale.getString("Custom")}, {ipc_str_on, ipc_str_off, "=.*"} }; private final String[][] sig_data = { {AnLocale.getString("Off"), "USR1", "USR2", "PROF", AnLocale.getString("Custom")}, {ipc_str_off, "USR1", "USR2", "PROF", "USR1"} }; private final String[][] clock_data = { { AnLocale.getString("Normal (100 Hz)"), AnLocale.getString("High (1000 Hz)"), AnLocale.getString("Low (10 Hz)"), AnLocale.getString("Custom (msec)") }, {ipc_str_on, "high", "low", "10.0"} }; private final String[][] hwc_data = { { AnLocale.getString("Auto"), AnLocale.getString("Low"), AnLocale.getString("Mid"), AnLocale.getString("High"), AnLocale.getString("Custom") }, {"", "low", ipc_str_on, "high", "9999991"} }; private final String[][] sync_data = { {AnLocale.getString("Calibrate"), AnLocale.getString("All"), AnLocale.getString("Custom")}, {"calibrate", "all", "0"} }; private final String[][] samp_data = { {AnLocale.getString("Normal"), AnLocale.getString("Custom")}, {ipc_str_on, "1"} }; private final String[][] count_types = { {AnLocale.getString("On"), AnLocale.getString("Static")}, {ipc_str_on, "static"} }; private final String[][] limit_data = { {AnLocale.getString("Unlimited"), AnLocale.getString("Custom")}, {ipc_str_empty, ipc_str_empty} }; private final String[][] limit_time = { {AnLocale.getString("Unlimited"), AnLocale.getString("Custom")}, {ipc_str_empty, ipc_str_empty} }; private final String[][] mpi_data = { { AnLocale.getString("OMPT"), AnLocale.getString("CT"), AnLocale.getString("OPENMPI"), AnLocale.getString("MPICH2"), AnLocale.getString("MVAPICH2"), AnLocale.getString("off") }, {"OMPT", "CT", "OPENMPI", "MPICH2", "MVAPICH2", ipc_str_off} }; private final String[][] hwc_dsp_data = { {AnLocale.getString("Off"), AnLocale.getString("On")}, {ipc_str_off, ipc_str_on} }; private final String[][] prof_idle_data = { {AnLocale.getString("On"), AnLocale.getString("Off")}, {ipc_str_on, ipc_str_off} }; private final String external_terminal = "/usr/bin/gnome-terminal"; // backend info about system's hwcs private final int maxHWC; private final String[][] hwcSets; private final List<List<HWCEntry>> hwcLists; private final String[] hwc_attr_list; // hwc attribute list private final String[] hwc_help; // hwc help text private final Map<String, HWCEntry> hwcI18NMap; // Will be faced out private final Map<String, HWCEntry> hwcNameMap; private final List<HWCEntry> hwcFlatList; private JLabel errorLabel; // backend info saved into format needed for combo boxes private final String[][] hwc_name_data; private final String[][] hwc_att_data; private String[][] hwc_reg_data; private final ArrayList data_list, left_list; private final boolean profile_running_process; private final boolean system_profiling; private int target_type; private boolean toAdd; public JDialog hwcPropertyDialog; private CollectChooser dir_chooser; private CollectChooser target_chooser; private CollectChooser exp_group_chooser; private Collector collector; private JTextArea out_log; private JTextArea pioTextArea; private JButton bt_clear; private JPanel pioPanel; private AnWindow anWindow; private static Boolean mpi_support() { return false; } public JTextArea getOutLog() { return out_log; } public void setOutLog(JTextArea area) { out_log = area; } public JButton getBtClear() { return bt_clear; } private final JButton[] buttons; private JButton RunButton = null; private final AnDialog m_dialog; private final Provider m_prov; private Thread output_thread; private int autoUpdaterState = 0; // Interface constants /* Interface strings GUI <-> CLI */ static final String ipc_str_clkprof = "clkprof"; static final String ipc_str_hwcprof = "hwcprof"; static final String ipc_str_javaprof = "javaprof"; static final String ipc_str_sample = "sample"; static final String ipc_str_synctrace = "synctrace"; static final String ipc_str_heaptrace = "heaptrace"; static final String ipc_str_iotrace = "iotrace"; static final String ipc_str_thatrace = "thatrace"; static final String ipc_str_count = "count"; static final String ipc_str_MPIexpt = "MPIexpt"; // -M option static final String ipc_str_MPItrace = "MPItrace"; // -m option static final String ipc_str_dbxsample = "dbxsample"; // not implemented yet static final String ipc_str_sample_sig = "sample_sig"; // not implemented yet static final String ipc_str_pause_resume_sig = "pause_resume_sig"; // not implemented yet static final String ipc_str_descendant = "descendant"; // not implemented yet static final String ipc_str_arch_exp = "arch_exp"; // not implemented yet static final String ipc_str_time_limit = "time_limit"; // not implemented yet static final String ipc_str_exp_limit = "exp_limit"; // not implemented yet static final String ipc_str_hwc2_prof = "hwc2_prof"; static final String ipc_str_hwc_default = "default"; static final String ipc_str_hwc1_val = "hwc1_val"; // not implemented yet static final String ipc_str_dspace_hwc1 = "dspace_hwc1"; // not implemented yet static final String ipc_str_hwc_reg_alloc = "hwc_reg_alloc"; // not implemented yet static final String ipc_str_hwc_ctr_attr = "hwc_ctr_attr"; // not implemented yet // Standard answers static final String ipc_str_empty = ""; static final String ipc_str_comma = ","; static final String ipc_str_auto = "auto"; static final String ipc_str_on = "on"; static final String ipc_str_off = "off"; static final String ipc_str_space = " "; static final String ipc_str_unknown_control = "Unknown control"; static final String ipc_str_internal_error = "Internal error"; static final String ipc_str_zero = "0"; static final String ipc_str_all = "all"; static final String ipc_str_None = "None"; static final String ipc_str_race = "race"; static final String ipc_str_deadlock = "deadlock"; static final String ipc_str_prof_idle = "prof_idle"; // Semaphores private final Object globalSem = new Object(); // private Boolean inItemStateChanged = false; private Boolean clkprof_on_by_default = true; private Boolean javaprof_on_by_default = true; private Boolean hwcprof_on_by_default = false; private Boolean sample_on_by_default = true; private Boolean clkprof_not_changed_by_user = true; private Boolean javaprof_not_changed_by_user = true; private Boolean hwcprof_not_changed_by_user = true; private Boolean sample_not_changed_by_user = true; private String collect_output_file = null; // Temporary file for collect's output private String temp_file_name = null; // Temporary file for generated profiling script public CollectPanel( Collector collector, AnDialog anDialog, Provider cprov, AnWindow anWindow, JButton[] buttons) { this.collector = collector; this.anWindow = anWindow; this.m_dialog = anDialog; this.m_prov = cprov; CSTR_TARGET = AnLocale.getString("Target Program"); CSTR_DIR = AnLocale.getString("Experiment Directory"); CSTR_GROUP = AnLocale.getString("Experiment Group"); CSTR_WORK = AnLocale.getString("Working Directory"); CSTR_TARGET_JDK = AnLocale.getString("Target JDK"); data_list = new ArrayList(); left_list = new ArrayList(); this.buttons = buttons; // int h = CollectUtility.text_font.getSize(); // float hf = h; // titlefont = CollectUtility.text_font.deriveFont(1, hf); if (collector.getProfilingType() == Collector.PROFILE_RUNNING_APPLICATION) { profile_running_process = true; } else { profile_running_process = false; } if (collector.getProfilingType() == Collector.SYSTEM_PROFILING) { system_profiling = true; } else { system_profiling = false; } // HW Counters IPC // Note: could be done in parallel to reduce latency hwcSets = getHwcSets(system_profiling); maxHWC = getHwcMaxConcurrent(system_profiling); hwc_attr_list = getHwcAttrList(system_profiling); hwcLists = getHWCsAllProcess(getHwcsAll(system_profiling)); hwc_help = getHwcHelp(system_profiling); // populate hwc_map and hwcFlatList hwcI18NMap = new HashMap(); hwcNameMap = new HashMap(); hwcFlatList = new ArrayList(); // prepend default counters at top of list for (int ii = 0; hwcSets[0] != null && ii < hwcSets[0].length; ii++) { HWCEntry hwcEntry = new HWCEntry( true, hwcSets[1][ii], hwcSets[1][ii], hwcSets[0][ii], null, 0, 0, 0, null, null, false, false, true); hwcI18NMap.put(hwcEntry.getI18n(), hwcEntry); hwcNameMap.put(hwcEntry.getName(), hwcEntry); hwcEntry.setNo(hwcFlatList.size()); hwcFlatList.add(hwcEntry); } for (List<HWCEntry> list : hwcLists) { for (HWCEntry hwcEntry : list) { hwcI18NMap.put(hwcEntry.getI18n(), hwcEntry); hwcNameMap.put(hwcEntry.getName(), hwcEntry); hwcEntry.setNo(hwcFlatList.size()); hwcFlatList.add(hwcEntry); } } // populate *_data fields used in dropdowns if (hwcFlatList.isEmpty()) { hwc_name_data = new String[2][0]; // THOMAS: should probably disable HWCs in this case } else { hwc_name_data = new String[2][hwcFlatList.size()]; int ii = 0; for (HWCEntry hwcentry : hwcFlatList) { hwc_name_data[0][ii] = hwcentry.getI18n(); hwc_name_data[1][ii] = hwcentry.getName(); ii++; } hwc_reg_data = setRegData(hwcFlatList.get(0).getI18n()); } // populate hwc_att_data final String[] alist = hwc_attr_list; if ((alist == null) || (alist.length == 0)) { hwc_att_data = new String[2][1]; hwc_att_data[0][0] = AnLocale.getString("None"); hwc_att_data[1][0] = "0"; } else { hwc_att_data = new String[2][alist.length]; hwc_att_data[0] = alist; for (int i = 0; i < hwc_att_data[0].length; i++) { hwc_att_data[1][i] = "0"; } } // dumpHWCounters(); initComponents(); initButtons(); if (profile_running_process) { collectPanel2.update(); } if (system_profiling) { collectPanel3.update(); } autoUpdate(); collector.addCollectingStatusListener(this); } private void dumpHWCEntry(int no, HWCEntry hwcentry) { System.out.println("=============================== " + no); System.out.println("recommended: " + hwcentry.isRecommended()); System.out.println("name : " + hwcentry.getName()); System.out.println("collector : " + hwcentry.getCollectorString()); System.out.println("i18n : " + hwcentry.getI18n()); System.out.println("int_name : " + hwcentry.getIntName()); System.out.println("short_desc : " + hwcentry.getShortDesc()); System.out.println("metric : " + hwcentry.getMetric()); System.out.println( "val: " + hwcentry.getVal() + ", timecvt: " + hwcentry.getTimecvt() + ", supportsAttrs: " + hwcentry.supportsAttrs() + ", supportsMemspace: " + hwcentry.supportsMemspace(hwcNameMap) + ", memop: " + hwcentry.getMemop()); System.out.print("regs: "); if (hwcentry.getRegList() != null) { for (int i = 0; i < hwcentry.getRegList().length; i++) { System.out.print(" " + hwcentry.getRegList()[i]); } } System.out.println(""); } private void dumpHWCounters() { int no = 0; System.out.println("************************************************* hwc_max_reg"); System.out.println(maxHWC); System.out.println("************************************************* hwc_sets"); System.out.println("hwc_sets"); for (int i = 0; i < hwcSets[0].length; i++) { System.out.println(i + ": " + hwcSets[0][i] + ", " + hwcSets[1][i]); } System.out.println("************************************************* hwcs (std)"); no = 0; for (HWCEntry hwcentry : hwcLists.get(0)) { dumpHWCEntry(no++, hwcentry); } System.out.println("************************************************* hwcs (raw)"); no = 0; for (HWCEntry hwcentry : hwcLists.get(1)) { dumpHWCEntry(no++, hwcentry); } System.out.println("************************************************* hwcFlatList"); no = 0; for (HWCEntry hwcentry : hwcFlatList) { dumpHWCEntry(no++, hwcentry); } System.out.println("************************************************* hwc_attr_list"); for (int i = 0; i < hwc_attr_list.length; i++) { System.out.println(i + ": " + hwc_attr_list[i]); } } /** Check fields and update buttons */ private void autoUpdate() { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { String err = null; RunButton = buttons[0]; while (null != target) { try { Thread.sleep(200); // wait 200 milliseconds if (!m_dialog.isVisible()) { continue; // to sleep } synchronized (globalSem) { if (autoUpdaterState == 1) { String target_name = target.getText(); if (profile_running_process) { if (null != target_name) { target_name = collectPanel2.getProcessID(); } } if (system_profiling) { if (null == target_name) { target_name = collectPanel3.getProcessID(); } } if ((null != target_name) && (target_name.length() > 0)) { RunButton.setEnabled(true); // XXX should use AWT thread RunButton.setToolTipText(AnLocale.getString("Start Profiling")); } else if (system_profiling) { RunButton.setEnabled(true); // XXX should use AWT thread RunButton.setToolTipText(AnLocale.getString("Start Kernel Profiling")); } else { RunButton.setEnabled(false); // XXX should use AWT thread RunButton.setToolTipText(AnLocale.getString("Target must be specified")); } if (getErrorText().length() > 0) { RunButton.setEnabled(false); // XXX should use AWT thread RunButton.setToolTipText(getErrorText()); } if (!profile_running_process && !system_profiling) { // Dependency between data_race, deadlock_trace, and descendant if ((data_race.check.isEnabled()) || (deadlock_trace.check.isEnabled())) { if ((data_race.isChecked()) || (deadlock_trace.isChecked())) { // disable descendant.combo TEMPORARY (DEBUG) descendant.combo.setEnabled(false); // descendant.combo.setSelectedIndex(1); // off } else { descendant.combo.setEnabled(true); // descendant.combo.setSelectedIndex(0); // on } } if ((descendant.field != null) && (ipc_str_on.equals(descendant.field.getText()))) { // do not disable data_race - on is a default // data_race.check.setEnabled(false); // deadlock_trace.check.setEnabled(false); } else { // Update descendant mode if ((descendant.field != null) && (ipc_str_off.equals(descendant.field.getText()))) { Collector.setCollectorControlValue( descendant.name, ipc_str_off); // IPC call } else { Collector.unsetCollectorControlValue(descendant.name); // IPC call } if ((!data_race.check.isEnabled())) { // try to enable data_race err = Collector.setCollectorControlValue( data_race.name, ipc_str_on); // IPC call if (null == err) { data_race.check.setEnabled(true); // Only if other controls allow if (!data_race.isChecked()) { Collector.unsetCollectorControlValue(data_race.name); // IPC call } } else { data_race.check.setEnabled(false); data_race.check.setSelected(false); // err = m_window.setCollectorControlValue(data_race.name, ipc_str_off); // // IPC call } } if ((!deadlock_trace.check.isEnabled())) { // try to enable deadlock_trace err = Collector.setCollectorControlValue( deadlock_trace.name, ipc_str_on); // IPC call if (null == err) { deadlock_trace.check.setEnabled(true); if (!deadlock_trace.isChecked()) { Collector.unsetCollectorControlValue(deadlock_trace.name); // IPC call } } else { deadlock_trace.check.setEnabled(false); deadlock_trace.check.setSelected(false); // err = m_window.setCollectorControlValue(deadlock_trace.name, // ipc_str_off); // IPC call } } } // End of Dependency between data_race, deadlock_trace, and descendant } // !in_dbx } if (autoUpdaterState == 2) { break; // Done } } // end of critical section } catch (Exception e) { // break; } } } }, "autoUpdateCollectDialog"); } /** * Set AutoUpdater State * * @param state */ private void setAutoUpdaterState(int state) { autoUpdaterState = state; try { Thread.sleep(300); // wait 200 milliseconds } catch (Exception e) { // break; } } /** * Read lines from specified InputStream and print them to the Process Output (JTextArea * pioTextArea) * * @param from */ private void output(InputStream from, List fromVector) { String line; Thread thisThread = Thread.currentThread(); BufferedReader br = null; if (null == fromVector) { br = new BufferedReader(new InputStreamReader(from)); } boolean closed = false; JTextArea to = pioTextArea; int line_number = 0; while ((output_thread == thisThread) && !closed) { try { line = null; if (null == br) { if (fromVector.size() > 0) { line = (String) fromVector.get(0); fromVector.remove(0); } else if (output_thread != thisThread) { closed = true; break; } } else { line = br.readLine(); } if (line != null) { if (line.length() > 0) { line_number++; if (line_number < 100) { // XXX: TEMPORARY HACK!!! String pattern = "Creating experiment database "; int idx = line.indexOf(pattern); if (idx >= 0) { write /*ln*/(line, getOutLog()); idx += pattern.length(); String substr = line.substring(idx); idx = substr.indexOf(ipc_str_space); if (idx > 1) { String expname = substr.substring(0, idx); // test.*.er collector.setActualExpName(expname); } // XXX: ANOTHER TEMPORARY HACK!!! pattern = "(Process ID: "; int n = line.indexOf(pattern); if (n >= 0) { n += pattern.length(); long p = 0; int d = 0; while ((d >= 0) && (d <= 9)) { p = p * 10 + d; d = line.charAt(n) - '0'; n++; } if (p > 0) { collector.setProcessPID(p); } } } } write /*ln*/(line, to); // We need a short delay to make sure the responsiveness // is good - otherwise AWT thread can be overloaded with // output requests and buttons Pause, Resume, Terminate // work with long delays. 10 milliseconds should be enough. // Thread.sleep(10); if (line_number % 100 == 0) { Thread.sleep(10); } continue; } } Thread.sleep(10); // empty line } catch (Exception e) { // don't print anything, this exception is expected // printException(e, AnLocale.getString("I/O exception 0")); if (output_thread != thisThread) { // closed = true; break; } } finally { // closed = true; } // NM if (output_thread == thisThread) { // NM closed = false; // TEMPORARY // NM } } } /** * Read lines from specified InputStream and print them to the Process Output (JTextArea * pioTextArea) * * @param from */ private void output(InputStream from, JTextArea out) { BufferedReader br = new BufferedReader(new InputStreamReader(from)); boolean closed = false; JTextArea to = pioTextArea; if (out != null) { to = out; } int line_number = 0; while (!closed) { String line; try { line = br.readLine(); if (line != null) { if (line.length() > 0) { line_number++; if (line_number < 100) { // XXX: TEMPORARY HACK!!! String pattern = "Creating experiment database "; int idx = line.indexOf(pattern); if (idx >= 0) { write /*ln*/(line, getOutLog()); idx += pattern.length(); String substr = line.substring(idx); idx = substr.indexOf(ipc_str_space); if (idx > 1) { String expname = substr.substring(0, idx); // test.*.er collector.setActualExpName(expname); } // XXX: ANOTHER TEMPORARY HACK!!! pattern = "(Process ID: "; int n = line.indexOf(pattern); if (n >= 0) { n += pattern.length(); long p = 0; int d = 0; while ((d >= 0) && (d <= 9)) { p = p * 10 + d; d = line.charAt(n) - '0'; n++; } if (p > 0) { collector.setProcessPID(p); } } } } // write/*ln*/(line, to); writeln(line, to); // We need a short delay to make sure the responsiveness // is good - otherwise AWT thread can be overloaded with // output requests and buttons Pause, Resume, Terminate // work with long delays. 10 milliseconds should be enough. if (line_number % 100 == 0) { Thread.sleep(10); } continue; } } Thread.sleep(10); // empty line } catch (Exception e) { // don't print anything, this exception is expected // printException(e, AnLocale.getString("I/O exception 0")); closed = true; break; } } } private static void printException(Exception e, String annot_msg) { if (annot_msg != null) { System.err.println(annot_msg + ": " + e.getMessage()); // DEBUG } else { System.err.println(e.getMessage()); // DEBUG } } private void write(final String line, final JTextArea to) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { to.append(line); to.setCaretPosition(to.getDocument().getLength()); } }); } // Output with new line private void writeln(final String line, final JTextArea to) { write(line + "\n", to); } // Add one collect argument private static void addOne(final ArrayList cmd_list, final String flag, final String str) { if ((str != null) && (str.length() > 0)) { if (flag != null) { cmd_list.add(flag); } cmd_list.add(str); } } private ArrayList getCmdList() { final ArrayList cmd_list; final String hwc1, hwc2; cmd_list = new ArrayList(); String cmd = Analyzer.getInstance().getPathToCollect(); // experiment name/dir/group if (profile_running_process) { cmd_list.add(cmd); addOne(cmd_list, "-P", collectPanel2.getProcessID()); addOne(cmd_list, "-o", collectPanel2.getExperimentName()); addOne(cmd_list, "-d", collectPanel2.getExperimentDirectory()); addOne(cmd_list, "-g", collectPanel2.getExperimentGroup()); } else if (system_profiling) { cmd = Analyzer.getInstance().getPathToCollectKernel(); cmd_list.add(cmd); String pid = collectPanel3.getProcessID(); if ((null != pid) && (pid.length() > 0)) { addOne(cmd_list, "-F", "=" + pid); } else { // er_kernel supports only one -F option String proc = collectPanel3.getProcessName(); if ((null != proc) && (proc.length() > 0)) { addOne(cmd_list, "-F", "=" + proc); } else { addOne(cmd_list, "-F", descendant.getValue()); } } addOne(cmd_list, "-o", collectPanel3.getExperimentName()); addOne(cmd_list, "-d", collectPanel3.getExperimentDirectory()); addOne(cmd_list, "-g", collectPanel3.getExperimentGroup()); addOne(cmd_list, "-x", prof_idle.getValue()); } else { // profile application cmd_list.add(cmd); addOne(cmd_list, "-o", exp_name.getText()); addOne(cmd_list, "-d", exp_dir.getText()); addOne(cmd_list, "-g", exp_group.getText()); } // don't add default limit value (now it's 2000 MB) addOne(cmd_list, "-L", exp_limit.getValue()); addOne(cmd_list, "-t", time_limit.getValue()); if (!profile_running_process && !system_profiling) { if (!descendant.getValue().equals(ipc_str_on)) { // Now "on" is the default value addOne(cmd_list, "-F", descendant.getValue()); } } else { // dbx cannot profile descendants // already done for er_kernel } // Archiving if (!arch_exp.getValue().equals(ipc_str_on)) { // Now "on" is the default value addOne(cmd_list, "-A", arch_exp.getValue()); } // set signals if (pause_sig.getValue() != null) { if (!pause_sig.getValue().equals(ipc_str_off)) { if (startResumed.isSelected()) { addOne(cmd_list, "-y", pause_sig.getValue() + ",r"); } else { addOne(cmd_list, "-y", pause_sig.getValue()); } } } addOne(cmd_list, "-l", sample_sig.getValue()); // data to collect addOne(cmd_list, "-p", clock_prof.getValue()); addOne(cmd_list, "-S", sample.getValue()); if (((hwc1 = hwc1_prof.getValue()) != null) && (selectedHWCList.size() > 0)) { String ctrlist = ipc_str_empty; String separator = ipc_str_empty; for (int i = 0; i < selectedHWCList.size(); i++) { String ctrname = selectedHWCList.get(i).getCollectorString(); addOne(cmd_list, "-h", ctrname); } } if (!profile_running_process && !system_profiling) { // Tracing options addOne(cmd_list, "-s", sync_trace.getValue()); if ((null != io_trace.getValue()) && (!io_trace.getValue().equals(ipc_str_off))) { addOne(cmd_list, "-i", io_trace.getValue()); } addOne(cmd_list, "-H", heap_trace.getValue()); // thread analyzer parameters if ((data_race.isChecked()) || (deadlock_trace.isChecked())) { boolean comma_is_required = false; String tha_params = ipc_str_empty; if (data_race.isChecked()) { comma_is_required = true; tha_params += "race"; } if (deadlock_trace.isChecked()) { tha_params += comma_is_required ? ipc_str_comma : ipc_str_empty; tha_params += "deadlock"; } addOne(cmd_list, "-r", tha_params); } addOne(cmd_list, "-c", count_data.getValue()); String mpi_trace_value = mpi_trace.getValue(); if (mpi_trace_value != null) { if (!mpi_trace_value.equals(ipc_str_off)) { addOne(cmd_list, "-M", mpi_trace_value); } } String java_prof = jvm_prof.getValue(); if (java_prof == null) { // pass "-j off" java_prof = ipc_str_off; addOne(cmd_list, "-j", java_prof); } // no need to pass "-j on" because it is the default } else // tracing is not supported by 'collect -P' { if (!system_profiling) { // Now 'collect -P' can support java profiling addOne(cmd_list, "-j", jvm_prof.getValue()); } } if (!profile_running_process /* && !system_profiling */) { target_type = getTargetType(target.getText()); // target command & arguments cmd_list.add(target.getText()); addOne(cmd_list, null, args.getText()); } else { // 'collect -P' does not need target } return cmd_list; } // Initialize the HWC configuration dialog public void showHWCPropertyDialog(HWCEntry entry) { String title = AnLocale.getString("Hardware Counter Properties"); AnDialog2 hwcPropertyDialog2 = new AnDialog2(m_dialog, m_dialog, title); hwcPropertyDialog2.getAccessibleContext().setAccessibleDescription(title); hwcPropertyDialog2.setCustomPanel(getHwcPanel(entry)); hwcPropertyDialog2.getOKButton().setText(AnLocale.getString("Update")); hwcPropertyDialog2.setVisible(true); if (hwcPropertyDialog2.getStatus() == AnDialog2.Status.OK) { int selectedIndex = hwcList.getSelectedIndex(); updateCtrList(entry); hwcList.setSelectedIndex(selectedIndex); } } // Initialize the HWC configuration dialog public void showHWCSelectDialog() { if (hwcSelectDialog == null) { hwcSelectDialog = new HWCSelectDialog(m_dialog, this, hwcFlatList, hwcNameMap); } hwcSelectDialog.setVisible(true); } public void closeHWCDialogs() { if (hwcSelectDialog != null) { hwcSelectDialog.setVisible(false); } if (availableCountersDialog != null) { availableCountersDialog.setVisible(false); } } protected void addHWCEntry(List<HWCEntry> selectedList) { int oldSize = selectedHWCList.size(); for (HWCEntry entry : selectedList) { if (entry.isSet()) { List<String> names = entry.getSetNames(); for (String name : names) { HWCEntry nameEntry = hwcNameMap.get(name); if (nameEntry != null) { selectedHWCList.add(nameEntry); } else { // FIXUP.... } } } else { selectedHWCList.add(entry); } } updateButtons(); int newSelectedIndex = oldSize++; // if (newSelectedIndex >= 0) { //FIXUP always >0 hwcList.setSelectedIndex(newSelectedIndex); // } hwcList.requestFocus(); } // Update list of selected counters void updateCtrList(HWCEntry hwcEntry) { String hwc1; String regval = ipc_str_empty; String attr = ipc_str_empty; // Warn user if add attribute wasn't hit after a change if (attr_warn == true) { final String msg = AnLocale.getString( "Attribute selection changed and Add Attribute was not clicked, do you want to" + " discard changes"); final int user_choice = JOptionPane.showConfirmDialog( this, msg, AnLocale.getString("Question"), JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if (user_choice == JOptionPane.NO_OPTION) // do not discard changes { return; } } if (toAdd == true) { if ((hwc1 = hwc2_prof.getValue()) != null) { final String aggr_prof1 = dspace_hwc1.getValue() != null && dspace_hwc1.getValue().equals(ipc_str_on) ? "+" : ipc_str_empty; String[] hwcs = hwc1.split(ipc_str_comma); for (int i = 0; i < sel_attr.size(); i++) { attr = attr + (String) sel_attr.get(i); } if (!reg_alloc.getValue().equals("None")) { regval = "/" + reg_alloc.getValue(); } String suffix = ipc_str_comma + hwc1_val.getValue(); if (suffix != null && suffix.equals(ipc_str_comma)) { suffix = ipc_str_empty; } // if (!hwcs[0].equals(ipc_str_hwc_default) && // ipc_str_on.equals(hwc1_val.getValue())) { // suffix = ipc_str_empty; // default // } String ctrstr = aggr_prof1 + hwcs[0] + attr + regval + suffix; // HWCEntry hwcEntry = null; // for (HWCEntry entry : selectedHWCList) { // if (entry.getName().equals(hwcs[0])) { // hwcEntry = entry; // break; // } // } // if (hwcEntry == null) { // hwcEntry = hwcNameMap.get(hwcs[0]); // } if (hwcEntry != null) { hwcEntry.setCollectorString(ctrstr); } // // If this register was already added - remove it // for (int i = 0; i < selectedHWCList.size(); i++) { // String s = selectedHWCList.get(i); // int k = s.indexOf(ipc_str_comma); // if (k > 0) { // s = s.substring(0, k); // } // int m = hwc1.indexOf(ipc_str_comma); // String newhwc = hwc1; // if (m > 0) { // newhwc = hwc1.substring(0, m); // } // if (s.equals(newhwc)) { // selectedHWCList.remove(i); // remove duplicate // } // } // selectedHWCList.add(ctrstr); // FIXUP updateButtons(); } } else // Modify existing entry { System.out.println(AnLocale.getString("Existing counter to be modified")); } attr_warn = false; } // Delete counter from list void deleteCtrFromList() { int idx = hwcList.getSelectedIndex(); selectedHWCList.remove(idx); updateButtons(); } // Add/Update attribute list void addAttribute() { attr_warn = false; String attrname = (String) ctr_attr.combo.getSelectedItem(); String attrStr = "~" + attrname + "="; String attrEntry = attrStr + ctr_attr.getValue(); Iterator en; boolean found = false; int i; for (i = 0, en = sel_attr.iterator(); en.hasNext(); i++) { String cur_elem = (String) en.next(); if (cur_elem.indexOf(attrStr) != -1) { sel_attr.set(i, attrEntry); // replace element found = true; } } if (!found) { sel_attr.add(attrEntry); } setAttrButtons(); } // Delete attribute from list void removeAttribute() { int idx = attrList.getSelectedIndex(); sel_attr.remove(idx); setAttrButtons(); } private void showChooser(String cmd) { if (cmd.equals(CSTR_TARGET)) { if (target_chooser == null) { target_chooser = new CollectChooser(AnChooser.TARGET_CHOOSER); } target_chooser.setDialogTitle(cmd); target_chooser.getFile(cmd); } else if (cmd.equals(CSTR_GROUP)) { if (exp_group_chooser == null) { exp_group_chooser = new CollectChooser(AnChooser.EXP_GROUP_CHOOSER); } exp_group_chooser.setDialogTitle(cmd); exp_group_chooser.getFile(cmd); } else if (cmd.equals(CSTR_DIR) || cmd.equals(CSTR_WORK) || cmd.equals(CSTR_TARGET_JDK)) { if (dir_chooser == null) { dir_chooser = new CollectChooser(AnChooser.DIR_CHOOSER); } dir_chooser.setDialogTitle(cmd); dir_chooser.getFile(cmd); } } private boolean checkSignals() { if (pause_sig.getValue() != null) { if (!pause_sig.getValue().equals(ipc_str_off)) { if (AnUtility.getSignalValue(pause_sig.getValue()) == -1) { AnUtility.showMessage( work_panel, AnLocale.getString("Illegal pause signal: ") + pause_sig.getValue(), JOptionPane.ERROR_MESSAGE); return false; } } } if (sample_sig.getValue() != null) { if (!sample_sig.getValue().equals(ipc_str_off)) { if (AnUtility.getSignalValue(sample_sig.getValue()) == -1) { AnUtility.showMessage( work_panel, AnLocale.getString("Illegal sample signal: ") + sample_sig.getValue(), JOptionPane.ERROR_MESSAGE); return false; } } } return true; } /** * checks java version used and warn user if its earlier then 1.4.2_02 TODO: Don't use AWT thread! * Create a special thread to call this method */ // NM public void checkJavaVersion() { // boolean check = false; // String line; // String version_str = "unknown"; // int ind; // // try { // final String[] javaversion = {getJavaStr(), "-version"}; // final Process p = Runtime.getRuntime().exec(javaversion); // p.waitFor(); // final InputStream data = p.getErrorStream(); // final BufferedReader br = new BufferedReader(new InputStreamReader(data)); // // while ((line = br.readLine()) != null) { // ind = line.indexOf("java version"); // if (ind != -1) { // version_str = (line.substring(ind + 13, line.length())).trim(); // break; // } // } // writeln(AnLocale.getString("Using java version ") + version_str + " ...", // getOutLog()); // version_str = version_str.substring(1, version_str.length() - 1); // skip quotes // ind = version_str.lastIndexOf('-'); // if (ind != -1) // cut -rc, -beta etc. from the end of the version string // { // version_str = version_str.substring(0, ind); // } // // ind = version_str.indexOf('.'); // if (ind != -1) { // String ver = version_str.substring(0, ind); // major version // int v = Integer.parseInt(ver); // if (v == 1) { // 1.?.? // int ind_next = version_str.indexOf('.', ind + 1); // ver = version_str.substring(ind + 1, ind_next); // ind = ind_next; // v = Integer.parseInt(ver); // if (v == 4) { // 1.4.? // ind_next = version_str.indexOf('_', ind + 1); // if (ind_next != -1) { // ver = version_str.substring(ind + 1, ind_next); // ind = ind_next; // v = Integer.parseInt(ver); // if (v == 2) { // 1.4.2_?? // ver = version_str.substring(ind + 1, version_str.length()); // v = Integer.parseInt(ver); // if (v >= 2) // 1.4.2_02 or later // { // check = true; // } else // 1.4.2_01 or earlier // { // check = false; // } // } else if (v > 2) // 1.4.3_?? // { // check = true; // } else { // check = false; // } // } else { // ver = version_str.substring(ind + 1, version_str.length()); // v = Integer.parseInt(ver); // if (v > 2) // 1.4.3 or later // { // check = true; // } else // 1.4.2 or earlier // { // check = false; // } // } // } else if (v < 4) // 1.3.* // { // check = false; // } else // 1.5.0 or later // { // check = true; // } // } else if (v > 1) // 2.*.* // { // check = true; // } else // major version less then 1 // { // check = false; // } // } // data.close(); // close Input Stream // } catch (NumberFormatException e) { // check = false; // } catch (IOException e) { // writeln(e.getMessage(), getOutLog()); // check = false; // } catch (InterruptedException e) { // writeln(e.getMessage(), getOutLog()); // check = false; // } // if (!check) { // writeln(AnLocale.getString("Warning: Java profiling requires JVM version 1.4.2_02 or // later"), // getOutLog()); // } // } // NM public String getJavaStr() { // String java_str = "java"; // final String header = target_jdk.getHeader(); // String jdk_path; // if (header.equals(AnLocale.getString("Path:"))) // { // jdk_path = target_jdk.getText().trim(); // } else if (header.equals(AnLocale.getString("Default (PATH based)"))) // { // jdk_path = "java"; // } else { // jdk_path = target_jdk.getText(); // } // // if (!jdk_path.equals(ipc_str_empty)) { // // // if (!jdk_path.equals(java_str)) { // Not Default (PATH based) // if (!jdk_path.endsWith(File.separator)) { // jdk_path += File.separatorChar; // } // java_str = jdk_path + "bin" + File.separatorChar + java_str; // } // } // return java_str; // } private String dbeGetExpParams(final String exp_name) { synchronized (IPC.lock) { anWindow.IPC().send("dbeGetExpParams"); anWindow.IPC().send(exp_name); return anWindow.IPC().recvString(); } } public void loadExpDefaults() { if (collector.isProcRunning()) { return; } if (null != work_dir) { // Set working directory work_dir.setText(Analyzer.getInstance().getWorkingDirectory()); // Still experimental..... } AnUtility.checkIPCOnWrongThread(false); final String[] exp_names = anWindow.getExpName(); // IPC AnUtility.checkIPCOnWrongThread(true); if (exp_names != null && exp_names.length != 0) { // find first non filtered experiment AnUtility.checkIPCOnWrongThread(false); final boolean[] expstats = anWindow.getExpEnable(); // IPC AnUtility.checkIPCOnWrongThread(true); int i = 0; String str_args = null; if (expstats != null) { while (i < expstats.length) { if (expstats[i]) { AnUtility.checkIPCOnWrongThread(false); str_args = dbeGetExpParams(exp_names[i]); // IPC AnUtility.checkIPCOnWrongThread(true); break; } i++; } } if (str_args != null) { final String[] arguments = str_args.split(ipc_str_space); final StringBuffer vargs = new StringBuffer(); final StringBuffer params = new StringBuffer(); final String trg; String trg_jdk = null; i = 0; if (arguments.length > 1) { // Check for java experiment if (new File(arguments[i]).getName().equals("java")) { final File jdk_dir = new File(arguments[i]).getParentFile(); if (jdk_dir != null) { trg_jdk = jdk_dir.getParent(); } else // Default java from $PATH { trg_jdk = ipc_str_empty; } i++; // skip -Xruncollector (it will be set later in collect) if (arguments[i].equals("-Xruncollector")) { i++; } while (arguments[i].startsWith("-") && i < arguments.length) { vargs.append(arguments[i] + ipc_str_space); if (arguments[i].equals("-cp") || arguments[i].equals("-classpath")) { vargs.append(arguments[++i] + ipc_str_space); } i++; } } } trg = arguments[i++]; while (i < arguments.length) { params.append(arguments[i++] + ipc_str_space); } setComponents(trg, params.toString().trim(), trg_jdk, vargs.toString().trim()); } } } // Show error mesg private void showError(final int err_type) { String msg = null; switch (err_type) { case TARG_UNKNOWN_TYPE: msg = AnLocale.getString("Target has unknown file type"); break; case TARG_NOT_EXISTS: msg = AnLocale.getString("Target doesnt't exist"); break; case TARG_IS_NOT_FILE: msg = AnLocale.getString("Target is not a file"); break; case TARG_IS_NOT_READABLE: msg = AnLocale.getString("Target is not readable"); break; } AnUtility.showMessage(work_panel, msg, JOptionPane.ERROR_MESSAGE); } @Override public void actionPerformed(final ActionEvent event) { String col_cmd; final Iterator iter; int i; final String cmd = event.getActionCommand(); final String empty = ipc_str_empty; Date date = new Date(); String sdate = date.toString(); if (cmd.equals(empty)) { int theState = event.getID(); // state change event if (theState == Collector.COLLECTING_RUNNING) { if (buttons[0].isEnabled()) { // the collection has just started String current_target_name = target.getText(); if (!profile_running_process && !system_profiling) { current_target_name = new File(current_target_name).getName(); } writeln( sdate + ": " + AnLocale.getString("Running: ") + current_target_name, getOutLog()); set_runtime_buttons(); } else { // the collection has been resumed String p = " (" + AnLocale.getString("process id ") + collector.getProcessPID() + ")"; writeln(sdate + ": " + AnLocale.getString("Data collection resumed" + p), getOutLog()); buttons[2].setText(AnLocale.getString("Pause")); buttons[2].setActionCommand(AnLocale.getString("Pause")); } } else if (theState == Collector.COLLECTING_PAUSED) { String p = " (" + AnLocale.getString("process id ") + collector.getProcessPID() + ")"; writeln(sdate + ": " + AnLocale.getString("Data collection paused" + p), getOutLog()); buttons[2].setText(AnLocale.getString("Resume")); buttons[2].setActionCommand(AnLocale.getString("Resume")); } else if (theState == Collector.COLLECTING_TERMINATING) { writeln(sdate + ": " + AnLocale.getString("Data collection terminating"), getOutLog()); } else if ((theState == Collector.COLLECTING_TERMINATED) || (theState == Collector.COLLECTING_COMPLETED)) { if (theState == Collector.COLLECTING_TERMINATED) { writeln(sdate + ": " + AnLocale.getString("Data collection terminated"), getOutLog()); } if (output_thread != null) { // There is a potential problem - we have to make sure that // the output thread had enough time to copy all messages // from the output Vector to the Text area. // Wait till output_thread is still working int c = 0; while (output_thread != null) { if (c++ > 100) { break; // timeout 1 second } try { Thread.sleep(10); } catch (Exception e) { // continue } } output_thread = null; } collector.read_collect_output_file(collect_output_file); collector.removeTempFile(collect_output_file); collector.removeTempFile(temp_file_name); if (collector.getProcessPID() > 0) { writeln( sdate + ": " + AnLocale.getString("Execution completed, exit status is ") + collector.getProcessExitValue(), getOutLog()); } else { writeln(sdate + ": " + AnLocale.getString("Execution failed"), getOutLog()); } writeln(AnLocale.getString("Process ID: ") + collector.getProcessPID(), getOutLog()); writeln( AnLocale.getString("Elapsed Time: ") + collector.getElapsedTime() + " ms", getOutLog()); String s = collector.getCollectOutput(); if (s.length() > 0) { writeln(s, getOutLog()); } String actualExperimentName = collector.getActualExpName(); String experimentGroup = collector.getExperimentGroup(); if (experimentGroup != null && experimentGroup.length() > 0) { actualExperimentName = experimentGroup; // Open group instead of experiment } getBtClear().setEnabled(true); if (collector.getProcessPID() > 0) { if (actualExperimentName != null) { String wd; if (exp_dir.getText().length() > 0) { wd = exp_dir.getText(); } else { wd = work_dir.getText(); } final String experimentPath = getExperimentPath(actualExperimentName); AnDialog2 openDialog = new AnDialog2(m_dialog, m_dialog, AnLocale.getString("Open Experiment")); final CollectorOpenPanel collectorOpenPanel = new CollectorOpenPanel(experimentPath, wd); final String workingDirectory = wd; openDialog.setCustomPanel(collectorOpenPanel); openDialog.setHelpTag(null); openDialog.setVisible(true); if (openDialog.getStatus() == AnDialog2.Status.OK) { // Not Cancel try { // Wait till the Analyzer workspace has been initialized SwingUtilities.invokeLater( new Runnable() { @Override public void run() { final List<String> exp_list = AnUtility.getExpList(new String[] {experimentPath}); if (anWindow != null) { // String workingDirectory = // collectorOpenPanel.getWorkingDirectory(); String configurationPath = collectorOpenPanel.getConfiguration(); boolean alwaysUseThisConfiguration = collectorOpenPanel.alwaysUseThisConfiguration(); anWindow.loadExperimentList( exp_list, false, workingDirectory, true, configurationPath, alwaysUseThisConfiguration); } // Close Collector dialog resetButtons(); m_dialog.setVisible(false); } }); return; // dialog is closed } catch (Exception e) { // e.printStackTrace(); showError(AnLocale.getString("Internal Error: open experiment failed.")); } } } else { // Report error showError(AnLocale.getString("Internal Error: no experiment.")); } } else { // Report profiling error String err = collector.getErrorMessage(); if (err == null) { err = "\nPlease, look at the Process output window for details"; } showError(AnLocale.getString("Error: Data collection failed: ") + err); // Clear old error message collector.setErrorMessage(ipc_str_empty); } resetButtons(); if (null != exp_name) { exp_name.setValue(collector.getNextExpName()); } } } else if (cmd.equals(AnLocale.getString("Run"))) { if (profile_running_process || system_profiling) { // Have to implement: check target, work_dir, exp_dir } else { // check target, work_dir, exp_dir if (target.getText().length() == 0) { tab_pane.setSelectedIndex(0); AnUtility.showMessage( work_panel, AnLocale.getString("The target name cannot be blank"), JOptionPane.ERROR_MESSAGE); return; } if ((work_dir.getText() == null) || (work_dir.getText().length() < 1)) { work_dir.setValue(Analyzer.getInstance().getWorkingDirectory()); } if (!collector.checkWorkDir(work_dir.getText())) { String errorMessage = AnLocale.getString("The working directory does not exist"); if (null != anWindow.getAnalyzer().remoteConnection) { errorMessage = AnLocale.getString("The working directory does not exist on remote system"); } AnUtility.showMessage(work_panel, errorMessage, JOptionPane.ERROR_MESSAGE); return; } if ((exp_dir.getText() != null) && exp_dir.getText().length() > 0) { if (!collector.checkWorkDir(exp_dir.getText())) { String errorMessage = AnLocale.getString("The experiment directory does not exist"); if (null != anWindow.getAnalyzer().remoteConnection) { errorMessage = AnLocale.getString("The experiment directory does not exist on remote system"); } AnUtility.showMessage(work_panel, errorMessage, JOptionPane.ERROR_MESSAGE); return; } } // THIS CHECK IS NOT CORRECT - commented out (NM) // if (target_type < 0) { // showError(target_type); // return; // } if (!checkSignals()) { return; } // THIS CHECK IS NOT CORRECT - commented out (NM) // if (jvm_prof.isChecked()) { // checkJavaVersion(); // } } /* ^profile_running_process */ // Create commands list and invoke collect final ArrayList cmdList = getCmdList(); final String[] cmds = new String[ /*getCmdList()*/cmdList.size()]; col_cmd = empty; // Define a temporary file for collect's output String output_file_name = null; if (!profile_running_process) { // 'collect -P' cannot redirect dbx's output (bug 17885089) if (!system_profiling) { // 'er_kernel -P' is not implemented yet if (!Analyzer.getInstance().isRemote()) { // not remote long t = System.currentTimeMillis(); output_file_name = "/tmp/collect_" + t + "_pid.txt"; } } /* ^system_profiling */ } /* ^profile_running_process */ for (i = 0, iter = /*getCmdList()*/ cmdList.iterator(); iter.hasNext(); i++) { cmds[i] = (String) iter.next(); col_cmd += cmds[i] + ipc_str_space; if ((i == 0) && (null != output_file_name)) { col_cmd += "--outfile" + ipc_str_space + output_file_name + ipc_str_space; } } // Temporary correction of default HWC set if (col_cmd.contains("-h default,")) { String pattern = "-h default,"; int k = col_cmd.indexOf(pattern); String s = col_cmd.substring(0, k); s += "-h "; k += pattern.length(); s += col_cmd.substring(k, col_cmd.length()); col_cmd = s; } preview_cmd.setText(col_cmd); if ((null != input_output_btn1) && input_output_btn1.isSelected()) { // Use external terminal // - Show Output tab, because it may show gnome-terminal errors tab_pane.setSelectedIndex(2); } else { // Show Output tab tab_pane.setSelectedIndex(2); } // Create a pipe and read stdout try { if (profile_running_process || system_profiling) { // 'collect -P' cannot redirect dbx's output (bug 17885089) // don't use vector, use pipe final PipedOutputStream pos = new PipedOutputStream(); final PipedInputStream pis = new PipedInputStream(pos); collector.setLog(pos); output_thread = new Thread("Collector Panel Output Thread") { @Override public void run() { output(pis, getOutLog()); } }; } else { final PipedInputStream pis = null; final List logVector = new ArrayList(); collector.setLog(logVector); output_thread = new Thread("Collector Panel Output Thread") { @Override public void run() { output(pis, logVector); } }; } output_thread.start(); } catch (Exception e) { // pis = null; } String run_cmd = col_cmd; String envs = env_vars.getText().trim(); if (null != envs && envs.length() > 0) { run_cmd = envs + " " + col_cmd; } if ((null != input_output_btn1) && input_output_btn1.isSelected()) { // Use external terminal // String gt_options = " --disable-factory "; String gt_options = " --window "; // New window // Create temporary script String s1 = "#!/bin/sh\n"; String s2 = "echo \"" + run_cmd + "\"\n"; String s3 = run_cmd; String l4 = AnLocale.getString("Exit status:"); String s4 = "\necho \"" + l4 + " $?\"\n"; String l5 = AnLocale.getString("Profiling is done, you can close this window."); String s5 = "echo \"# " + l5 + "\"\n"; String l6 = AnLocale.getString("The window will be automatically closed in 5 seconds."); String s6 = "echo \"# " + l6 + "\"\n"; String s7 = "sleep 5\n"; if (temp_file_name == null) { try { File tempFile = File.createTempFile("collect", ".tmp"); temp_file_name = tempFile.getCanonicalPath(); } catch (Exception e) { temp_file_name = "/tmp/collect.sh.tmp"; // Use default name } } String contents = s1 + s2 + s3 + s4 + s5 + s6 + s7; AnUtility.checkIPCOnWrongThread(false); anWindow.writeFile(temp_file_name, contents); AnUtility.checkIPCOnWrongThread(true); String tmp_cmd = "\" /bin/sh " + temp_file_name + " \""; run_cmd = external_terminal + gt_options + " -e " + tmp_cmd; } // Clean output window if (null != pioTextArea) { pioTextArea.setText(empty); } if (null != getOutLog()) { getOutLog().setText(empty); } String experimentGroup = ""; if (!profile_running_process && !system_profiling) { experimentGroup = exp_group.getText(); } else if (profile_running_process) { experimentGroup = collectPanel2.getExperimentGroup(); } else if (system_profiling) { experimentGroup = collectPanel3.getExperimentGroup(); } if (profile_running_process) { // fill fake fields target.text.setText(collectPanel2.getProcessID()); target.setText(run_cmd); // This is used to print what is running work_dir.text.setText(collectPanel2.getExperimentDirectory()); work_dir.setText(collectPanel2.getExperimentDirectory()); exp_dir.text.setText(collectPanel2.getExperimentDirectory()); exp_name.text.setText(collectPanel2.getExperimentName()); env_vars.text.setText(empty); } if (system_profiling) { // fill fields exp_dir.text.setText(collectPanel3.getExperimentDirectory()); exp_name.text.setText(collectPanel3.getExperimentName()); } collect_output_file = output_file_name; collector.collect( target.getText(), run_cmd, work_dir.getText(), exp_name.getText(), exp_dir.getText(), env_vars.getText().trim(), output_file_name, experimentGroup); } else if (cmd.equals(AnLocale.getString("Pause"))) { if (collector.pause(AnUtility.getSignalValue(pause_sig.getValue()))) {} tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Resume"))) { if (collector.resume(AnUtility.getSignalValue(pause_sig.getValue()))) {} tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Sample"))) { if (collector.sample(AnUtility.getSignalValue(sample_sig.getValue()))) { writeln(AnLocale.getString("Manual sample"), getOutLog()); } tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Terminate"))) { final String msg = AnLocale.getString("Do you want to terminate the running experiment?"); final int user_choice = JOptionPane.showConfirmDialog( this, msg, AnLocale.getString("Question"), JOptionPane.YES_NO_OPTION); if (user_choice == JOptionPane.YES_OPTION) { collector.terminate_expt(profile_running_process); } } else if (cmd.equals(AnLocale.getString("Preview Command:"))) { col_cmd = empty; for (i = 0, iter = getCmdList().iterator(); iter.hasNext(); i++) { col_cmd += ((String) iter.next()) + ipc_str_space; } // Temporary correction of default HWC set String pattern = "-h " + ipc_str_hwc_default + ipc_str_comma; if (col_cmd.contains(pattern)) { int k = col_cmd.indexOf(pattern); String s = col_cmd.substring(0, k); s += "-h "; k += pattern.length(); s += col_cmd.substring(k, col_cmd.length()); col_cmd = s; } // Temporary correction of default HWC set pattern = "-h " + ipc_str_hwc_default + ipc_str_space; if (col_cmd.contains(pattern)) { int k = col_cmd.indexOf(pattern); String s = col_cmd.substring(0, k); s += "-h on "; k += pattern.length(); s += col_cmd.substring(k, col_cmd.length()); col_cmd = s; } // Remove "-j on" pattern = "-j " + ipc_str_on + ipc_str_space; if (col_cmd.contains(pattern)) { int k = col_cmd.indexOf(pattern); String s = col_cmd.substring(0, k); k += pattern.length(); s += col_cmd.substring(k, col_cmd.length()); col_cmd = s; } preview_cmd.setText(col_cmd); } else if (cmd.equals(AnLocale.getString("Properties"))) { toAdd = true; HWCEntry entry = (HWCEntry) hwcList.getSelectedValue(); showHWCPropertyDialog(entry); } else if (cmd.equals(AnLocale.getString("Add"))) { showHWCSelectDialog(); } else if (cmd.equals(AnLocale.getString("Remove"))) { int selectedIndex = hwcList.getSelectedIndex(); deleteCtrFromList(); if (selectedIndex >= (selectedHWCList.size() - 1)) { selectedIndex = selectedHWCList.size() - 1; } if (selectedIndex >= 0) { hwcList.setSelectedIndex(selectedIndex); } } else if (cmd.equals(AnLocale.getString("Add Attribute"))) { addAttribute(); } else if (cmd.equals(AnLocale.getString("Remove Attribute"))) { removeAttribute(); // } else if (cmd.equals(AnLocale.getString("Update"))) { // int selectedIndex = hwcList.getSelectedIndex(); // HWCEntry entry = (HWCEntry) hwcList.getSelectedValue(); // updateCtrList(entry); // hwcList.setSelectedIndex(selectedIndex); // } else if (cmd.equals(AnLocale.getString("Cancel"))) { // closeHWCPropertyDialog(); // } else if (cmd.equals(AnLocale.getString("Available Counters"))) { // String[] availableCounterText = hwc_help; // int noLines = availableCounterText.length; //// tab_pane.setSelectedIndex(2); //// for (i = 0; i < noLines; i++) { //// write(availableCounterText[i], getOutLog()); // Show available list //// } // // AnDialog2 availableCountersDialog = new AnDialog2(this, "Available Counters"); // JPanel panel = new JPanel(new BorderLayout()); // JScrollPane scrollPane = new JScrollPane(); // JTextArea textArea = new JTextArea(); // for (i = 0; i < noLines; i++) { // textArea.append(availableCounterText[i]); // } // textArea.setCaretPosition(0); // textArea.setFont(new Font("monospaced", Font.PLAIN, // textArea.getFont().getSize())); // scrollPane.setViewportView(textArea); // panel.add(scrollPane, BorderLayout.CENTER); // availableCountersDialog.setCustomPanel(panel); // availableCountersDialog.setModal(false); // availableCountersDialog.getCancelButton().setVisible(false); // availableCountersDialog.setPreferredSize(new // Dimension(availableCountersDialog.getPreferredSize().width - 300, 700)); // availableCountersDialog.pack(); // availableCountersDialog.setVisible(true); } else if (cmd.equals(AnLocale.getString("Clear"))) { // pioTerm.clearHistory(); pioTextArea.setText(empty); getOutLog().setText(empty); getBtClear().setEnabled(false); } else { showChooser(cmd); } } protected void showAvailableCountersDialog() { if (availableCountersDialog == null) { String[] availableCounterText = hwc_help; int noLines = availableCounterText.length; availableCountersDialog = new AnDialog2(m_dialog, this, "Hardware Counter Help"); JPanel panel = new JPanel(new BorderLayout()); JScrollPane scrollPane = new JScrollPane(); JTextArea textArea = new JTextArea(); for (int i = 0; i < noLines; i++) { textArea.append(availableCounterText[i]); } textArea.setCaretPosition(0); textArea.setEditable(false); textArea.setFont(new Font("monospaced", Font.PLAIN, textArea.getFont().getSize())); scrollPane.setViewportView(textArea); panel.add(scrollPane, BorderLayout.CENTER); availableCountersDialog.setCustomPanel(panel); availableCountersDialog.setModal(false); availableCountersDialog.getCancelButton().setVisible(false); availableCountersDialog.setPreferredSize(new Dimension(800, 850)); availableCountersDialog.pack(); } availableCountersDialog.setVisible(true); } private String getExperimentPath(String actual_expname) { String experimentPath = actual_expname; if (!actual_expname.startsWith("/")) { String path = exp_dir.getText(); if (path.length() > 0) { experimentPath = path + "/" + actual_expname; } else { // Get full path path = work_dir.getText(); if (null == path) { path = Analyzer.getInstance().getWorkingDirectory(); } path = path.trim(); if (path.length() > 0) { experimentPath = path + "/" + actual_expname; } else { // BUG: CGetCurDir() may not work properly in remote mode path = Analyzer.getInstance().getWorkingDirectory(); work_dir.setValue(path); experimentPath = path + "/" + actual_expname; } } } return experimentPath; } private void setComponents( final String target, final String params, final String target_jdk, final String vm_args) { // System.out.println("CollectPanel:setComponents:" + target); this.target.setText(target); this.args.setText(params); if (target_jdk != null) { this.jvm_prof.setChecked(true); // default java if (target_jdk.equals(ipc_str_empty)) { this.target_jdk.setSelectedIndex(this.target_jdk.getItemCount() - 1); } else { final String java_bin = target_jdk + File.separatorChar + "bin" + File.separatorChar + "java"; if (new File(java_bin).exists()) { this.target_jdk.setValue(target_jdk); } else { this.target_jdk.setSelectedIndex(1); } } if (!vm_args.equals(ipc_str_empty)) { this.vm_args.setValue(vm_args); } } else { this.jvm_prof.setChecked(false); } this.updateTitle(target); } private void showError(String msg) { AnUtility.showMessage(work_panel, msg, JOptionPane.ERROR_MESSAGE); } private String CGetExpName(String str) { return Collector.getExpName1(str); // IPC } public void updateTitle(String target) { m_prov.setTitleStr(title + " [" + new File(target).getName() + "]"); } public String getenv(String name) { return AnUtility.getenv(name); } public int getTargetType(String target_name) { // TODO: Check java class files to ensure that it has a main public method if (target_name == null) { return TARG_NOT_EXISTS; } if (!target_name.startsWith("/") && !target_name.startsWith("./") && !target_name.startsWith("../")) { return TARG_UNKNOWN_TYPE; } AnFile targ_file = new AnFile(target_name); /* NM if (!targ_file.exists()) { final String target_class_name = toJavaClassFileName(target_name); targ_file = new File(target_class_name); if (!targ_file.exists()) { final String work_str = work_dir.getText(); targ_file = new File(work_str, target_name); if (!targ_file.exists()) { targ_file = new File(work_str, target_class_name); if (!targ_file.exists() || !targ_file.isFile()) { return TARG_NOT_EXISTS; } } } } */ if (!targ_file.exists()) { return TARG_NOT_EXISTS; } if (!targ_file.isFile()) { return TARG_IS_NOT_FILE; } /* NM switch (AnUtility.getMimeFormat(targ_file)) { case AnUtility.MIME_ELF_EXECUTABLE: return TARG_ELF_EXECUTABLE; case AnUtility.MIME_JAVA_CLASS_FILE: return TARG_JAVA_CLASS_FILE; case AnUtility.MIME_JAR_FILE: return TARG_JAR_FILE; case AnUtility.MIME_CANNOT_READ_FILE: return TARG_IS_NOT_READABLE; default: */ return TARG_UNKNOWN_TYPE; /* NM } */ } // Log panel for process and collector output public Component getOutputPane() { if (out_log != null) { return null; } out_log = new JTextArea(8, 40); out_log.setEditable(false); out_log.getAccessibleContext().setAccessibleName(AnLocale.getString("Collector output")); out_log.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Collector output")); JScrollPane out_scroll = new AnJScrollPane( out_log, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); out_scroll.setBorder(BorderFactory.createLineBorder(AnEnvironment.SCROLLBAR_BORDER_COLOR)); out_scroll.getAccessibleContext().setAccessibleName(AnLocale.getString("Collector output")); out_scroll .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Collector output")); final JPanel out_panel = new JPanel(new BorderLayout()); JLabel label = new JLabel(); AnUtility.setTextAndAccessibleContext(label, AnLocale.getString("Collector output")); out_panel.add(label, BorderLayout.NORTH); out_panel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); out_panel.add(out_scroll, BorderLayout.CENTER); final JPanel bt_panel = new JPanel(new BorderLayout()); bt_clear = new JButton(AnLocale.getString("Clear")); bt_clear.setMnemonic(AnLocale.getString('l', "MNEM_COLLECTOR_OUTPUT_CLEAR")); bt_clear.setToolTipText(AnLocale.getString("Clear output")); bt_clear.setHorizontalTextPosition(SwingConstants.RIGHT); bt_clear.setActionCommand(AnLocale.getString("Clear")); bt_clear.getAccessibleContext().setAccessibleName(AnLocale.getString("Clear")); bt_clear.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Clear output")); bt_clear.addActionListener(this); bt_clear.setEnabled(false); JPanel clearButtonPanel = new JPanel(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(4, 0, 0, 0); clearButtonPanel.add(bt_clear, gridBagConstraints); bt_panel.add(clearButtonPanel, BorderLayout.EAST); out_panel.add(bt_panel, BorderLayout.SOUTH); pioTextArea = new JTextArea(8, 40); if (!system_profiling) { pioTextArea.setEditable(false); pioTextArea.getAccessibleContext().setAccessibleName(AnLocale.getString("Process output")); pioTextArea .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Process output")); JScrollPane pio_scroll = new AnJScrollPane( pioTextArea, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); pio_scroll.setBorder(BorderFactory.createLineBorder(AnEnvironment.SCROLLBAR_BORDER_COLOR)); pioPanel = new JPanel(new BorderLayout()); label = new JLabel(); AnUtility.setTextAndAccessibleContext(label, AnLocale.getString("Process output")); pioPanel.add(label, BorderLayout.NORTH); pioPanel.getAccessibleContext().setAccessibleName(AnLocale.getString("Process input/output")); pioPanel .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Process input/output")); pioPanel.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6)); pioPanel.add(pio_scroll, BorderLayout.CENTER); } else { return out_panel; } JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, out_panel, pioPanel); splitPane.setDividerSize(3); return (splitPane); } private void initButtons() { buttons[0].setText(AnLocale.getString("Run")); buttons[0].setActionCommand(AnLocale.getString("Run")); // buttons[0].setMnemonic(AnLocale.getString('R', "MNEM_COLLECTOR_RUN")); buttons[0].getAccessibleContext().setAccessibleDescription(AnLocale.getString("Run")); buttons[1].setText(AnLocale.getString("Terminate")); buttons[1].setActionCommand(AnLocale.getString("Terminate")); buttons[1].setMnemonic(AnLocale.getString('e', "MNEM_COLLECTOR_TERMINATE")); buttons[1].getAccessibleContext().setAccessibleDescription(AnLocale.getString("Terminate")); // Set size of pause/resume button final Dimension pausePrefSize = buttons[2].getPreferredSize(); final JButton resumebutton = new JButton(AnLocale.getString("Resume")); final Dimension resumePrefSize = resumebutton.getPreferredSize(); final Dimension prPrefSize = new Dimension( Math.max(pausePrefSize.width, resumePrefSize.width), Math.max(pausePrefSize.height, resumePrefSize.height)); buttons[2].setPreferredSize(prPrefSize); buttons[2].setText(aux[0]); // Pause buttons[2].setMnemonic(mnemonic[0]); buttons[2].getAccessibleContext().setAccessibleDescription(aux[0]); buttons[3].setText(aux[1]); // Sample buttons[3].setMnemonic(mnemonic[1]); buttons[3].getAccessibleContext().setAccessibleDescription(aux[1]); buttons[4].setText(AnLocale.getString("Close", "DIALOG_CLOSE")); buttons[4].setMnemonic(AnLocale.getString('C', "MNEM_DIALOG_CLOSE")); buttons[4] .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Close", "DIALOG_CLOSE")); resetButtons(); } // Reset button states private void resetButtons() { buttons[0].setEnabled(true); buttons[1].setEnabled(false); buttons[2].setEnabled(false); buttons[2].setText(AnLocale.getString("Pause")); buttons[2].setActionCommand(AnLocale.getString("Pause")); buttons[3].setEnabled(false); setAutoUpdaterState(1); // resume } public void set_runtime_buttons() { setAutoUpdaterState(0); // pause buttons[0].setEnabled(false); // run button disabled buttons[1].setEnabled(true); // terminate button enabled // pause button if ((null == pause_sig.getValue()) || pause_sig.getValue().equals(ipc_str_off)) { buttons[2].setEnabled(false); } else { buttons[2].setEnabled(true); if (startPaused.isSelected()) { buttons[2].setText(AnLocale.getString("Resume")); buttons[2].setActionCommand(AnLocale.getString("Resume")); } } // sample button if ((null == sample_sig.getValue()) || sample_sig.getValue().equals(ipc_str_off)) { buttons[3].setEnabled(false); } else { buttons[3].setEnabled(true); } } private String[][] getHwcSets(boolean forKernel) { synchronized (IPC.lock) { anWindow.IPC().send("getHwcSets"); anWindow.IPC().send(forKernel); return (String[][]) anWindow.IPC().recvObject(); } } private String[] getHwcAttrList(boolean forKernel) { synchronized (IPC.lock) { anWindow.IPC().send("getHwcAttrList"); anWindow.IPC().send(forKernel); return (String[]) anWindow.IPC().recvObject(); } } private String[] getHwcHelp(boolean forKernel) { synchronized (IPC.lock) { anWindow.IPC().send("getHwcHelp"); anWindow.IPC().send(forKernel); return (String[]) anWindow.IPC().recvObject(); } } private Object[] getHwcsAll(boolean forKernel) { synchronized (IPC.lock) { anWindow.IPC().send("getHwcsAll"); anWindow.IPC().send(forKernel); return (Object[]) anWindow.IPC().recvObject(); } } private int getHwcMaxConcurrent(boolean forKernel) { synchronized (IPC.lock) { anWindow.IPC().send("getHwcMaxConcurrent"); anWindow.IPC().send(forKernel); return anWindow.IPC().recvInt(); } } private List<List<HWCEntry>> getHWCsAllProcess(Object[] obj) { List<List<HWCEntry>> types = new ArrayList(); List<HWCEntry> std = new ArrayList(); List<HWCEntry> raw = new ArrayList(); types.add(std); types.add(raw); int ii = 0; boolean recommended = true; for (List<HWCEntry> current : types) { Object fields[] = (Object[]) obj[ii]; int xx = 0; final String[] i18n = (String[]) fields[xx++]; final String[] name = (String[]) fields[xx++]; final String[] int_name = (String[]) fields[xx++]; final String[] metric = (String[]) fields[xx++]; final long[] val = (long[]) fields[xx++]; final int[] timecvt = (int[]) fields[xx++]; final int[] memop = (int[]) fields[xx++]; final String[] short_desc = (String[]) fields[xx++]; final int[][] reg_list = (int[][]) fields[xx++]; final boolean[] supportsAttrs = (boolean[]) fields[xx++]; final boolean[] supportsMemspace = (boolean[]) fields[xx++]; for (int kk = 0; kk < i18n.length; kk++) { HWCEntry hwcEntry = new HWCEntry( false, i18n[kk], name[kk], int_name[kk], metric[kk], val[kk], timecvt[kk], memop[kk], short_desc[kk], reg_list[kk], supportsAttrs[kk], supportsMemspace[kk], recommended); current.add(hwcEntry); } ii++; recommended = false; } return types; } // Initialize register data for selected counter private String[][] setRegData(String hwname) { final HWCEntry ctr = hwcI18NMap.get(hwname); final int ct; if (ctr != null && ctr.getRegList() != null) { ct = ctr.getRegList().length; } else { ct = 0; } int count = ct + 1; String[][] rdata = new String[2][count]; rdata[0][0] = AnLocale.getString("None"); rdata[1][0] = rdata[0][0]; for (int i = 1; i < count; i++) { rdata[0][i] = Integer.toString(ctr.getRegList()[i - 1]); rdata[1][i] = rdata[0][i]; } // Set combo box with the new set of registers if ((reg_alloc != null) && (reg_alloc.combo != null)) { reg_alloc.combo.setSelectedItem(AnLocale.getString("None")); int n = 1; int max = reg_alloc.combo.getItemCount(); while (n < max) { reg_alloc.combo.removeItemAt(1); n++; } for (int k = 1; k < count; k++) { reg_alloc.combo.addItem(rdata[0][k]); } } return rdata; } public JPanel getHwcPanel(HWCEntry entry) { JPanel basePanel = new JPanel(); basePanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); basePanel.setLayout(new BoxLayout(basePanel, BoxLayout.Y_AXIS)); // Create top panel JPanel hwcPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); hwcPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); hwcPanel.setLayout(new BoxLayout(hwcPanel, BoxLayout.Y_AXIS)); hwcPanel.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); hwcPanel .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Counter Selection")); JPanel labelPanel = new JPanel(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); labelPanel.setOpaque(false); gridBagConstraints.gridx = 0; gridBagConstraints.insets = new Insets(8, 8, 0, 8); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; JLabel counterLabel = new JLabel(entry.getMetricText()); AnUtility.setAccessibleContext(counterLabel); counterLabel.setFont(counterLabel.getFont().deriveFont(Font.BOLD)); counterLabel.setOpaque(true); counterLabel.setPreferredSize(new Dimension(600, 20)); counterLabel.setHorizontalAlignment(JLabel.LEFT); labelPanel.add(counterLabel, gridBagConstraints); hwcPanel.add(labelPanel); hwc2_prof = new CollectData( hwc1_prof, '0', null, ' ', AnLocale.getString("Counter Name:"), hwc_name_data, JTextField.LEFT, true, true, ipc_str_hwc2_prof); hwcPanel.add(Box.createRigidArea(new Dimension(8, 8))); hwcPanel.add( hwc1_val = new CollectData( hwc2_prof, '0', null, ' ', AnLocale.getString("Profiling Rate:"), hwc_data, JTextField.LEFT, true, true, ipc_str_hwc1_val)); dspace_hwc1 = new CollectData( hwc1_val, '0', null, ' ', AnLocale.getString("Hardware Counter Dataspace :"), hwc_dsp_data, JTextField.LEFT, true, false, ipc_str_dspace_hwc1); hwcPanel.add(Box.createRigidArea(new Dimension(8, 8))); if (!hwcFlatList.isEmpty()) { HWCEntry first = hwcFlatList.get(0); hwc_reg_data = setRegData(first.getI18n()); } hwcPanel.add( reg_alloc = new CollectData( hwc1_val, '0', null, ' ', AnLocale.getString("Hardware Counter Register:"), hwc_reg_data, JTextField.LEFT, true, false, ipc_str_hwc_reg_alloc)); hwcPanel.add(Box.createRigidArea(new Dimension(8, 8))); hwcPanel.add( ctr_attr = new CollectData( hwc1_val, '0', null, ' ', AnLocale.getString("Attribute:"), hwc_att_data, JTextField.LEFT, true, false, ipc_str_hwc_ctr_attr)); // Attr Buttons JPanel attrButtonPanel1 = new JPanel(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); attrButtonPanel1.setOpaque(false); addAttr = new JButton(AnLocale.getString("Add Attribute")); addAttr.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Add Attribute")); addAttr.addActionListener(this); addAttr.setEnabled(false); gridBagConstraints.gridx = 0; gridBagConstraints.insets = new Insets(4, 8, 0, 0); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; attrButtonPanel1.add(addAttr, gridBagConstraints); modAttr = new JButton(AnLocale.getString("Modify Attribute")); addAttr.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Modify Attribute")); modAttr.addActionListener(this); hwcPanel.add(attrButtonPanel1); hwcPanel.add(Box.createRigidArea(new Dimension(16, 16))); // Create attribute config panel JPanel attrPanel = new JPanel(new BorderLayout()); attrPanel.setBorder(new EmptyBorder(new Insets(1, 8, 1, 8))); attrPanel.setOpaque(false); // Selected attr label selectedAttrLabel = new JLabel(AnLocale.getString("Selected Attributes:")); selectedAttrLabel.setOpaque(false); AnUtility.setAccessibleContext( selectedAttrLabel.getAccessibleContext(), selectedAttrLabel.getText()); selectedAttrLabel.setAlignmentX(JDialog.LEFT_ALIGNMENT); attrPanel.add(selectedAttrLabel, BorderLayout.NORTH); // Selected list sel_attr = new ArrayList(); attrList = new JList(sel_attr.toArray()); attrList.getAccessibleContext().setAccessibleName(AnLocale.getString("Attribute Selection")); attrList .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Attribute Selection")); // list.addListSelectionListener(this); attrScrollPane = new AnJScrollPane(); attrScrollPane.setBorder(BorderFactory.createLineBorder(AnEnvironment.SCROLLBAR_BORDER_COLOR)); attrScrollPane.setViewportView(attrList); Dimension newSize = new Dimension(hwcPanel.getPreferredSize().width - 600, 50); attrScrollPane.setPreferredSize(newSize); attrPanel.add(attrScrollPane, BorderLayout.CENTER); hwcPanel.add(attrPanel); // Attr Buttons JPanel attrButtonPanel2 = new JPanel(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); attrButtonPanel2.setOpaque(false); remAttr = new JButton(AnLocale.getString("Remove Attribute")); AnUtility.setAccessibleContext(remAttr.getAccessibleContext(), remAttr.getText()); // remAttr.setMnemonic(getLocaleStr('R', "MNEM_COLLECTOR_DELETE_ATTRIBUTE")); addAttr.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Remove Attribute")); remAttr.addActionListener(this); gridBagConstraints.gridx = 1; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(4, 8, 0, 0); attrButtonPanel2.add(remAttr, gridBagConstraints); hwcPanel.add(attrButtonPanel2); hwcPanel.add(Box.createRigidArea(new Dimension(8, 8))); setAttrButtons(); setAttributeCombo(); // Create and initialize dialog buttons. buttonPanel = new JPanel(); updateButton = new JButton(AnLocale.getString("Update")); updateButton.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Update")); updateButton.addActionListener(this); cancelButton = new JButton(AnLocale.getString("Cancel")); cancelButton.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Cancel")); cancelButton.addActionListener(this); buttonPanel.add(updateButton); buttonPanel.add(cancelButton); basePanel.add(hwcPanel); // Set dialog to selected counter hwc2_prof.combo.setSelectedItem(entry.getI18n()); return basePanel; } // Initialize GUI components private void initComponents() { final JPanel exp_panel, data_panel, preview, cmd_panel; final CollectUtility.CList list, list_dbx, list_jdk; final JButton button; final JPanel targetPanel = new JPanel(); final JPanel firstPanel = new JPanel(); tab_pane = new JTabbedPane(); AnUtility.setAccessibleContext(tab_pane.getAccessibleContext(), title); // Add target & arguments list = new CollectUtility.CList(false); list_dbx = new CollectUtility.CList(false); // hidden list if (!profile_running_process) { CollectUtility.CList list_target = new CollectUtility.CList(false); boolean required = true; if (system_profiling) { required = false; } target = new CollectExp( CEXP_TARGET, list_target, ipc_str_empty, AnLocale.getString('T', "MNEM_COLLECTOR_TARGET"), CSTR_TARGET, true, '4', required); target.text.setToolTipText(AnLocale.getString("The path name of the target program")); args = new CollectExp( CEXP_NA, list_target, ipc_str_empty, AnLocale.getString('A', "MNEM_COLLECTOR_ARGUMENTS"), AnLocale.getString("Arguments"), false, '0'); args.text.setToolTipText(AnLocale.getString("Target program's command-line arguments")); work_dir = new CollectExp( CEXP_WORK, list_target, Analyzer.getInstance().getWorkingDirectory(), AnLocale.getString('W', "MNEM_COLLECTOR_WORKING_DIR"), CSTR_WORK, true, '7'); work_dir.text.setToolTipText( AnLocale.getString("Full path of the directory where the target program should run")); work_dir.setEditable(true); env_vars = new CollectExp( CEXP_ENV, list_target, ipc_str_empty, AnLocale.getString('V', "MNEM_COLLECTOR_ENVIRONMENT_VARIABLES"), AnLocale.getString("Environment Variables"), false, '0'); env_vars.text.setToolTipText( AnLocale.getString( "Environment variables needed by target program, specified as: NAME1=value1" + " NAME2=value2")); list_target.setAlignmentX(); list_target.setAlignmentY(); TitledBorder titleBorder; titleBorder = BorderFactory.createTitledBorder( new LineBorder(AnEnvironment.ABOUT_BOX_BORDER_COLOR, 1), AnLocale.getString("Specify Application to Profile")); // titleBorder.setTitleFont(titlefont); targetPanel.setBorder(titleBorder); targetPanel.setLayout(new BoxLayout(targetPanel, BoxLayout.Y_AXIS)); targetPanel.add(list_target); if (!Analyzer.getInstance().isRemote()) { // not remote // Allow user to specify external terminal for Input/Output final ButtonGroup group = new ButtonGroup(); group.add( input_output_btn1 = new JRadioButton(AnLocale.getString("Use External Terminal"), true)); // input_output_btn1.setMnemonic(getLocaleStr('X', // "MNEM_EXTERNAL_TERMINAL")); input_output_btn1.setToolTipText( AnLocale.getString("Use External Terminal for input/output")); group.add( input_output_btn2 = new JRadioButton(AnLocale.getString("Use Built-in Output Window"), false)); // input_output_btn2.setMnemonic(getLocaleStr('U', "MNEM_BUILT_IN_WINDOW")); input_output_btn2.setToolTipText( AnLocale.getString("Use Built-in Output Window for output (no input)")); final JPanel io_panel = new JPanel(); input_output_lbl = new JLabel(AnLocale.getString("Target Input/Output: ")); input_output_lbl.setToolTipText(AnLocale.getString("Specify Input/Output")); io_panel.add(input_output_lbl); io_panel.add(input_output_btn1); io_panel.add(input_output_btn2); targetPanel.add(io_panel); // Check if /bin/gnome-terminal is available File f = new File(external_terminal); if (f.exists()) { // Allow external terminal if (system_profiling) { // TEMPORARY: use built-in window by default input_output_btn1.setSelected(false); input_output_btn2.setSelected(true); } } else { // disable external terminal option input_output_lbl.setToolTipText( AnLocale.getString( "External terminal is not available (" + external_terminal + " is not installed)")); input_output_btn1.setToolTipText( AnLocale.getString( "Use External Terminal for input/output (currently disabled because " + external_terminal + " is not installed)")); input_output_btn1.setEnabled(false); input_output_btn1.setSelected(false); input_output_btn2.setSelected(true); } } } if (!profile_running_process && !system_profiling) { // Add experiment name/directory/group exp_name = new CollectExp( CEXP_NAME, list, CGetExpName(null), AnLocale.getString('x', "MNEM_COLLECTOR_EXPERIMENT_NAME"), AnLocale.getString("Experiment Name"), false, '0'); exp_name.text.setToolTipText( AnLocale.getString("File name ending in .er to store collected data as an experiment")); exp_dir = new CollectExp( CEXP_DIR, list, ipc_str_empty, AnLocale.getString('y', "MNEM_COLLECTOR_EXPERIMENT_DIR"), CSTR_DIR, true, '5'); exp_dir.text.setToolTipText( AnLocale.getString("Full path of the directory to store the experiment")); exp_group = new CollectExp( CEXP_GROUP, list, ipc_str_empty, AnLocale.getString('o', "MNEM_COLLECTOR_EXPERIMENT_GROUP"), CSTR_GROUP, true, '6'); exp_group.text.setToolTipText( AnLocale.getString( "Full path of file name ending in .erg for grouping related experiments")); } else { if (profile_running_process) { // AnLog.log("analyzer: profiling running process.\n"); targetPanel.setLayout(new BorderLayout()); collectPanel2 = new CollectPanel2(anWindow); targetPanel.add(collectPanel2, BorderLayout.CENTER); } else { // system_profiling // AnLog.log("analyzer: system profiling.\n"); collectPanel3 = new CollectPanel3(anWindow); targetPanel.add(collectPanel3); } if (profile_running_process) { target = new CollectExp( CEXP_TARGET, list_dbx, ipc_str_empty, AnLocale.getString('T', "MNEM_COLLECTOR_TARGET"), CSTR_TARGET, true, '4', true); work_dir = new CollectExp( CEXP_WORK, list_dbx, Analyzer.getInstance().getWorkingDirectory(), AnLocale.getString('W', "MNEM_COLLECTOR_WORKING_DIR"), CSTR_WORK, false, '7'); env_vars = new CollectExp( CEXP_ENV, list_dbx, ipc_str_empty, AnLocale.getString('V', "MNEM_COLLECTOR_ENVIRONMENT_VARIABLES"), AnLocale.getString("Environment Variables"), false, '0'); } exp_dir = new CollectExp( CEXP_DIR, list_dbx, ipc_str_empty, AnLocale.getString('y', "MNEM_COLLECTOR_EXPERIMENT_DIR"), CSTR_DIR, true, '5'); exp_name = new CollectExp( CEXP_NAME, list_dbx, CGetExpName(null), AnLocale.getString('x', "MNEM_COLLECTOR_EXPERIMENT_NAME"), AnLocale.getString("Experiment Name"), false, '0'); } list.setAlignmentX(); list.setAlignmentY(); firstPanel.setLayout(new BorderLayout()); firstPanel.add(targetPanel, BorderLayout.NORTH); exp_panel = new JPanel(); exp_panel.setLayout(new BoxLayout(exp_panel, BoxLayout.Y_AXIS)); // exp_panel.add(target_panel); TitledBorder titleBorder; titleBorder = BorderFactory.createTitledBorder( new LineBorder(AnEnvironment.ABOUT_BOX_BORDER_COLOR, 1), AnLocale.getString("Specify Experiment")); // titleBorder.setTitleFont(titlefont); exp_panel.setBorder(titleBorder); exp_panel.add(list); JPanel exp_panel2 = new JPanel(); exp_panel2.setLayout(new BoxLayout(exp_panel2, BoxLayout.Y_AXIS)); // exp_panel.add(target_panel); TitledBorder titleBorder2; titleBorder2 = BorderFactory.createTitledBorder( new LineBorder(AnEnvironment.ABOUT_BOX_BORDER_COLOR, 1), AnLocale.getString("Advanced Experiment Settings")); // titleBorder2.setTitleFont(titlefont); exp_panel2.setBorder(titleBorder2); exp_panel2.add( exp_limit = new CollectData( true, ' ', null, '0', AnLocale.getString("Data Limit (MB):"), limit_data, JTextField.RIGHT, false, ipc_str_exp_limit)); exp_limit.text.setToolTipText( AnLocale.getString("Profile the application until the experiment reaches this size")); left_list.add(exp_limit); exp_panel2.add( time_limit = new CollectData( true, ' ', null, '0', AnLocale.getString("Time Limit (Seconds):"), limit_time, JTextField.RIGHT, false, ipc_str_time_limit)); time_limit.text.setToolTipText( AnLocale.getString("Profile the application for this amount of time")); left_list.add(time_limit); exp_panel2.add(Box.createRigidArea(new Dimension(4, 4))); exp_panel2.add( arch_exp = new CollectData( true, ' ', // NM null, '0', getLocaleStr("Archived/Copied into Experiment:"), arch_data, // JTextField.RIGHT, false)); null, '0', AnLocale.getString("Archive Mode:"), arch_data, JTextField.RIGHT, false, ipc_str_arch_exp)); arch_exp.text.setToolTipText( AnLocale.getString("Archive the experiment for analysis on another system")); exp_panel2.add(Box.createRigidArea(new Dimension(4, 4))); left_list.add(arch_exp); if (!profile_running_process) { exp_panel2.add( descendant = new CollectData( true, ' ', null, '0', AnLocale.getString("Follow Descendant Processes:"), desc_data, JTextField.RIGHT, false, ipc_str_descendant)); descendant.text.setToolTipText( AnLocale.getString("Profile the target program and child processes it starts")); exp_panel2.add(Box.createRigidArea(new Dimension(4, 4))); left_list.add(descendant); } if (system_profiling) { exp_panel2.add( prof_idle = new CollectData( true, ' ', null, '0', AnLocale.getString("Do not profile idle CPUs:"), prof_idle_data, JTextField.RIGHT, false, ipc_str_prof_idle)); prof_idle.text.setToolTipText( AnLocale.getString("Do not record profile events from idle CPUs")); exp_panel2.add(Box.createRigidArea(new Dimension(4, 4))); left_list.add(prof_idle); } pause_sig = new CollectData( true, ' ', null, '0', AnLocale.getString("Signal to Pause/Resume Collection:"), sig_data, JTextField.RIGHT, false, ipc_str_pause_resume_sig); pause_sig.text.setToolTipText( AnLocale.getString("Signal you will use to pause and resume profiling the application")); left_list.add(pause_sig); exp_panel2.add(pause_sig); final ButtonGroup group = new ButtonGroup(); group.add(startPaused = new JRadioButton(AnLocale.getString("Paused"), true)); // startPaused.setMnemonic(getLocaleStr('d', "MNEM_COLLECTOR_START_PAUSED")); startPaused.setToolTipText( AnLocale.getString("Begin profiling the application when you send the first signal")); group.add(startResumed = new JRadioButton(AnLocale.getString("Resumed"), false)); // startResumed.setMnemonic(getLocaleStr('m', "MNEM_COLLECTOR_START_RESUMED")); startResumed.setToolTipText( AnLocale.getString( "Profile the application immediately as its process starts and pause when you send the" + " first signal")); final JPanel bg_panel = new JPanel(); start_state = new JLabel(AnLocale.getString("Start state: ")); start_state.setToolTipText( AnLocale.getString( "Whenever the signal is delivered to the process, the Collector switches between paused" + " (no data is recorded) and resumed (data is recorded) states")); bg_panel.add(start_state); bg_panel.add(startPaused); bg_panel.add(startResumed); start_state.setEnabled(false); startPaused.setEnabled(false); startResumed.setEnabled(false); pause_sig.combo.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent event) { final boolean selected = !event.getItem().equals(AnLocale.getString("Off")); start_state.setEnabled(selected); startPaused.setEnabled(selected); startResumed.setEnabled(selected); } }); exp_panel2.add(bg_panel); exp_panel.add(new JLabel(ipc_str_space)); // just space exp_panel.add(exp_panel2); pause_sig.setAlignmentX(left_list); sample_sig = new CollectData( /* NM true */ /* NM true */ false, ' ', AnLocale.getString("Manual Samples of Process Resource Utilization"), ' ', AnLocale.getString("Signal:"), sig_data, JTextField.RIGHT, true, ipc_str_sample_sig); sample_sig.check.setToolTipText( AnLocale.getString("Time-stamped samples taken when you send a signal to the program")); sample_sig.text.setToolTipText( AnLocale.getString("Signal you will send to take a manual sample")); // Add data to collect data_panel = new JPanel(); data_panel.setLayout(new BoxLayout(data_panel, BoxLayout.Y_AXIS)); // NM data_panel.setBorder(new javax.swing.border.EmptyBorder(5, 5, 0, 0)); TitledBorder dataBorder; String dataTitale = AnLocale.getString( "Specify the type of data to collect. As you select data types, other incompatible" + " data types are disabled."); dataBorder = BorderFactory.createTitledBorder(new LineBorder(Color.BLUE, 0), dataTitale); // dataBorder.setTitleFont(titlefont); data_panel.setBorder(dataBorder); data_panel .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Data to Collect")); data_panel.add(Box.createRigidArea(new Dimension(4, 4))); // add some space data_panel.add( clock_prof = new CollectData( clkprof_on_by_default, ' ', AnLocale.getString("Clock Profiling"), ' ', AnLocale.getString("Profiling Rate:"), clock_data, JTextField.RIGHT, true, ipc_str_clkprof)); clock_prof.check.setToolTipText( AnLocale.getString( "Record application state at regular intervals to show where time is spent in" + " functions")); clock_prof.text.setToolTipText( AnLocale.getString("Time between Clock Profiling recordings (milliseconds)")); data_panel.add(Box.createRigidArea(new Dimension(4, 4))); data_panel.add( hwc1_prof = new CollectData( hwcprof_on_by_default, ' ', AnLocale.getString("Hardware Counter Profiling"), '0', null, null, JTextField.LEFT, true, ipc_str_hwcprof)); hwc1_prof.check.setToolTipText( AnLocale.getString("Track the frequency of processor events specified by counters")); if (hwcFlatList.isEmpty()) { hwc1_prof.check.setEnabled(false); } data_panel.add(Box.createRigidArea(new Dimension(4, 4))); initHWCPanel(data_panel); final boolean hwc1_available = hwc1_prof.check.isEnabled(); hwc1_prof.check.addItemListener( new ItemListener() { @Override public void itemStateChanged(final ItemEvent event) { final boolean selected = ((JCheckBox) event.getItem()).isSelected(); if (hwc1_available) { counterLabel.setEnabled(selected); propertyButton.setEnabled(selected); addHWCButton.setEnabled(selected); hwcList.setEnabled(selected); // showButton.setEnabled(selected); updateButtons(); } } }); jvm_prof = new CollectData( javaprof_on_by_default, ' ', AnLocale.getString("Java Profiling"), '0', null, null, JTextField.RIGHT, true /* NM false */, ipc_str_javaprof); jvm_prof.check.setToolTipText( AnLocale.getString("Enable recognition and recording of Java classes and methods")); if (!system_profiling) { data_panel.add(jvm_prof); } data_panel.add(Box.createRigidArea(new Dimension(4, 4))); data_panel.add( sample = new CollectData( sample_on_by_default, ' ', AnLocale.getString("Periodic Samples of Process Resource Utilization"), ' ', AnLocale.getString("Interval (sec.):"), samp_data, JTextField.RIGHT, true, ipc_str_sample)); sample.check.setToolTipText( AnLocale.getString( "Time-stamped samples that show execution state of the profiled program, used in" + " Timeline")); sample.text.setToolTipText( AnLocale.getString("Number of seconds between samples, normally 1 second")); if (null != sample_sig) { data_panel.add(Box.createRigidArea(new Dimension(4, 4))); // new box data_panel.add(sample_sig); } data_panel.add(Box.createRigidArea(new Dimension(4, 4))); io_trace = new CollectData( false, ' ', AnLocale.getString("I/O Tracing"), ' ', null, null, JTextField.RIGHT, true, ipc_str_iotrace); io_trace.check.setToolTipText(AnLocale.getString("Track input/output operations")); if (!profile_running_process && !system_profiling) { data_panel.add(io_trace); data_panel.add(Box.createRigidArea(new Dimension(4, 4))); } heap_trace = new CollectData( false, ' ', AnLocale.getString("Heap Tracing"), '0', null, null, JTextField.RIGHT, true, ipc_str_heaptrace); heap_trace.check.setToolTipText( AnLocale.getString( "Track memory allocation activity to reveal memory leaks or inefficiency")); if (!profile_running_process && !system_profiling) { data_panel.add(heap_trace); } sync_trace = new CollectData( false, ' ', AnLocale.getString("Synchronization Wait Tracing"), ' ', AnLocale.getString("Minimum Delay (usec.):"), sync_data, JTextField.RIGHT, true, ipc_str_synctrace); sync_trace.check.setToolTipText( AnLocale.getString( "Track delays in calls to thread-synchronization routines in multithreaded programs")); sync_trace.text.setToolTipText( AnLocale.getString("Threshold for recording a thread synchonization wait (microseconds)")); if (!profile_running_process && !system_profiling) { data_panel.add(Box.createRigidArea(new Dimension(4, 4))); data_panel.add(sync_trace); data_panel.add(Box.createRigidArea(new Dimension(4, 4))); } mpi_trace = new CollectData( false, ' ', AnLocale.getString("MPI Tracing for specified MPI"), ' ', AnLocale.getString("MPI version:"), mpi_data, JTextField.RIGHT, true, ipc_str_MPIexpt); mpi_trace.check.setToolTipText( AnLocale.getString("Track MPI calls for progams that use Message Passing Interface")); mpi_trace.text.setToolTipText(AnLocale.getString("The version of MPI your program uses")); if (mpi_support() && !profile_running_process && !system_profiling) { data_panel.add(mpi_trace); data_panel.add(Box.createRigidArea(new Dimension(4, 4))); } if (!profile_running_process && !system_profiling) { list_jdk = new CollectUtility.CList(true); // The code below will be removed soon target_jdk = new TargetJDK( list_jdk, jvm_prof, AnLocale.getString('T', "MNEM_COLLECTOR_TARGET_JDK"), CSTR_TARGET_JDK, AnLocale.getString('B', "MNEM_COLLECTOR_JDK_BROWSE")); vm_args = new CollectExp( CEXP_NA, list_jdk, ipc_str_empty, AnLocale.getString('V', "MNEM_COLLECTOR_JAVA_VM_PARAMETERS"), AnLocale.getString("JVM parameters"), false, '0', 0, false); } if (profile_running_process) { data_panel.add( dbxsample = new CollectData( false, ' ', AnLocale.getString("Record Sample When dbx Stops Process"), '0', null, null, JTextField.RIGHT, true, ipc_str_dbxsample)); } // Threading errors checking deadlock_trace = new CollectData( false, ' ', AnLocale.getString("Deadlock Detection"), ' ', null, null, JTextField.RIGHT, true, ipc_str_thatrace); deadlock_trace.check.setToolTipText( AnLocale.getString("Detecting dead locks in threads synchronization")); data_race = new CollectData( false, ' ', AnLocale.getString("Data Race Detection"), ' ', null, null, JTextField.RIGHT, true, ipc_str_thatrace); data_race.check.setToolTipText( AnLocale.getString( "Locate competing data access events in instrumented multithreaded programs")); // Function/Instruction Counts count_data = new CollectData( false, ' ', AnLocale.getString("Function/Instruction Counts"), ' ', AnLocale.getString("Instrumentation:"), count_types, JTextField.RIGHT, true, ipc_str_count); count_data.check.setToolTipText( AnLocale.getString( "Counting Function calls and Instructions. This option cannot be used with other" + " profiling options")); // if GUI is started as RDT, deselect clock-based profiling by default String cmode = AnUtility.getenv("SP_ANALYZER_CONFIG_MODE"); if (cmode != null && cmode.equals("R")) { clock_prof.check.setSelected(false); } // if GUI is started as RDT, select associated checkboxes by default if (cmode != null && cmode.equals("R")) { sample.check.setSelected(false); sample.check.setEnabled(false); data_race.check.setSelected(true); deadlock_trace.check.setSelected(true); } // Check if data_race can be set String val = ipc_str_race; String err = Collector.setCollectorControlValue(data_race.name, val); // IPC call if ((null != err) || profile_running_process || system_profiling) { data_race.check.setSelected(false); data_race.check.setEnabled(false); data_race.available = false; } else { data_panel.add(Box.createRigidArea(new Dimension(4, 4))); data_panel.add(data_race); } if (!data_race.check.isSelected()) { Collector.unsetCollectorControlValue(data_race.name); // IPC call } // Check if deadlock_trace can be set val = ipc_str_deadlock; err = Collector.setCollectorControlValue(deadlock_trace.name, val); // IPC call if ((null != err) || profile_running_process || system_profiling) { deadlock_trace.check.setSelected(false); deadlock_trace.check.setEnabled(false); deadlock_trace.available = false; } else { data_panel.add(Box.createRigidArea(new Dimension(4, 4))); data_panel.add(deadlock_trace); } if (!deadlock_trace.check.isSelected()) { Collector.unsetCollectorControlValue(deadlock_trace.name); // IPC call } // Check if count_data can be set val = ipc_str_on; err = Collector.setCollectorControlValue(count_data.name, val); // IPC call if ((null != err) || profile_running_process || system_profiling) { count_data.check.setEnabled(false); count_data.check.setSelected(false); count_data.available = false; } else { data_panel.add(Box.createRigidArea(new Dimension(4, 4))); data_panel.add(count_data); } Collector.unsetCollectorControlValue(count_data.name); // IPC call data_panel.add(Box.createRigidArea(new Dimension(4, 4))); // add some space sample.setAlignmentX(data_list); if (!profile_running_process && !system_profiling) { firstPanel.add(exp_panel); } else { data_panel.add(exp_panel2); } tab_pane.add(AnLocale.getString("General"), firstPanel); // NM tab_pane.add(AnLocale.getString("Data to Collect"), data_panel); cmd_panel = new JPanel(new BorderLayout()); cmd_panel.add(tab_pane, BorderLayout.CENTER); // if (!profile_running_process) { // Preview command button = new JButton(AnLocale.getString("Preview Command:")); button.setMargin(CollectUtility.buttonMargin); Dimension d = new Dimension(160, 14); button.setPreferredSize(d); button.setMaximumSize(d); button.setMnemonic(AnLocale.getString('P', "MNEM_COLLECTOR_PREVIEW_COMMAND")); button.setToolTipText( AnLocale.getString("Shows the 'collect' command that will be run using your selections")); button.addActionListener(this); button.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Preview Command:")); preview_cmd = new JTextField(40); AnUtility.setAccessibleContext( preview_cmd.getAccessibleContext(), AnLocale.getString("Preview Command:")); preview_cmd.setEditable(false); preview_cmd.setBorder(new SoftBevelBorder(SoftBevelBorder.LOWERED)); preview = new JPanel(new BorderLayout()); preview.add(button, BorderLayout.WEST); preview.add(preview_cmd, BorderLayout.CENTER); /* preview_cmd = new JTextArea(1, 40); preview_cmd.setEditable(false); preview_cmd.getAccessibleContext().setAccessibleName(getLocaleStr("Preview collect command")); preview_cmd.getAccessibleContext().setAccessibleDescription(getLocaleStr("Preview collect command")); final JScrollPane preview_cmd_scroll = new AnJScrollPane(preview_cmd, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); preview_cmd_scroll.getAccessibleContext().setAccessibleName(getLocaleStr("Preview collect command")); preview_cmd_scroll.getAccessibleContext().setAccessibleDescription(getLocaleStr("Preview collect command")); preview = new JPanel(new BorderLayout()); preview.setBorder(new TitledBorder(getLocaleStr("Preview collect command"))); preview.add(button, BorderLayout.WEST); preview.add(preview_cmd_scroll, BorderLayout.CENTER); */ cmd_panel.add(preview, BorderLayout.SOUTH); // tab_pane.add("3. " + getLocaleStr("Input/Output"), getOutputPane()); tab_pane.add(AnLocale.getString("Output"), getOutputPane()); // } tab_pane.setVerifyInputWhenFocusTarget(false); // for (int i = 0; i < tab_pane.getTabCount(); i++) { // tab_pane.setMnemonicAt(i, new Integer(i + 1).toString().charAt(0)); // } // numbers are removed - new mnemonics are needed // work_panel = new AnJScrollPane(); // work_panel.setViewportView(cmd_panel); work_panel = new JPanel(new BorderLayout()); work_panel.add(cmd_panel, BorderLayout.CENTER); } public void initHWCPanel(JPanel data_panel) { hwcSelectDialog = null; selectedHWCList = new ArrayList(); hwcPanel = new JPanel(new BorderLayout()); hwcPanel.setBorder(BorderFactory.createEmptyBorder(0, 16, 6, 8)); counterLabel = new JLabel(AnLocale.getString("Selected Hardware Counters:")); counterLabel.setEnabled(false); counterLabel.setToolTipText(AnLocale.getString("List of hardware counters to profile")); hwcPanel.add(counterLabel, BorderLayout.NORTH); hwcList = new JList(selectedHWCList.toArray()); // Set tooltip hwcList.addMouseMotionListener( new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent evt) { ListModel model = hwcList.getModel(); int index = hwcList.locationToIndex(evt.getPoint()); if (index >= 0) { HWCEntry entry = (HWCEntry) model.getElementAt(index); String ttText = entry.getDescriptionText(hwcNameMap); hwcList.setToolTipText(ttText); } } }); // Handle Enter key hwcList.addKeyListener( new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyChar() == KeyEvent.VK_ENTER) { if (propertyButton.isEnabled()) { propertyButton.doClick(); e.consume(); } } if (e.getKeyChar() == KeyEvent.VK_DELETE || e.getKeyCode() == 8) { if (removeButton.isEnabled()) { removeButton.doClick(); e.consume(); } } } }); // Handle double-click hwcList.addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { if (propertyButton.isEnabled()) { propertyButton.doClick(); e.consume(); } } } }); hwcList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); AnUtility.setAccessibleContext( hwcList.getAccessibleContext(), AnLocale.getString("List of hardware counters to profile")); // list.addListSelectionListener(this); hwcListScrollPane = new AnJScrollPane(); hwcListScrollPane.setViewportView(hwcList); hwcListScrollPane.setBorder(new LineBorder(AnEnvironment.ABOUT_BOX_BORDER_COLOR, 1)); Dimension newSize = new Dimension(data_panel.getPreferredSize().width - 600, 70); hwcListScrollPane.setPreferredSize(newSize); hwcPanel.add(hwcListScrollPane, BorderLayout.CENTER); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.insets = new Insets(4, 0, 0, 0); gridBagConstraints.anchor = GridBagConstraints.WEST; addHWCButton = new JButton(AnLocale.getString("Add")); addHWCButton .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Add hardware counters")); addHWCButton.setToolTipText(AnLocale.getString("Add counters to profile")); addHWCButton.setEnabled(false); addHWCButton.addActionListener(this); addHWCButton.setMnemonic(AnLocale.getString('A', "CollectPanel.addHWCButton")); buttonPanel.add(addHWCButton, gridBagConstraints); gridBagConstraints.gridx = 1; gridBagConstraints.insets = new Insets(4, 4, 0, 0); gridBagConstraints.anchor = GridBagConstraints.WEST; propertyButton = new JButton(AnLocale.getString("Properties")); propertyButton .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Set counter properties")); propertyButton.setToolTipText(AnLocale.getString("Change counter properties")); propertyButton.setEnabled(false); propertyButton.addActionListener(this); buttonPanel.add(propertyButton, gridBagConstraints); gridBagConstraints.gridx = 2; gridBagConstraints.insets = new Insets(4, 4, 0, 0); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; removeButton = new JButton(AnLocale.getString("Remove")); removeButton .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Remove counter")); removeButton.setToolTipText(AnLocale.getString("Remove selected counter")); removeButton.addActionListener(this); buttonPanel.add(removeButton, gridBagConstraints); // gridBagConstraints.gridx = 3; // gridBagConstraints.insets = new Insets(4, 0, 0, 0); // gridBagConstraints.anchor = GridBagConstraints.EAST; //// gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; // gridBagConstraints.weightx = 1.0; // showButton = new JButton(getString("Available Counters")); // showButton.getAccessibleContext().setAccessibleDescription(getString("Available // Counters")); // showButton.setToolTipText(getString("Show all hardware counters that can be profiled // on the current system")); // showButton.setEnabled(false); // showButton.addActionListener(this); // buttonPanel.add(showButton, gridBagConstraints); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new Insets(4, 0, 0, 0); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; errorLabel = new JLabel(); errorLabel.setForeground(Color.red); buttonPanel.add(errorLabel, gridBagConstraints); hwcPanel.add(buttonPanel, BorderLayout.SOUTH); updateButtons(); data_panel.add(hwcPanel); } // Set all HWC related controls public void updateButtons() { if ((selectedHWCList.isEmpty()) || (!hwc1_prof.check.isSelected())) { hwcList.setListData(selectedHWCList.toArray()); removeButton.setEnabled(false); propertyButton.setEnabled(false); hwcListScrollPane.setEnabled(false); } else { hwcList.setListData(selectedHWCList.toArray()); hwcList.setSelectedIndex(0); removeButton.setEnabled(true); propertyButton.setEnabled(true); hwcListScrollPane.setEnabled(true); } hwcListScrollPane.revalidate(); hwcListScrollPane.repaint(); // Check for errors setErrorText(null); // Check max numbers of counters if (selectedHWCList.size() > maxHWC) { setErrorText( String.format( AnLocale.getString("The maximum number of counters allowed is %d"), maxHWC)); } if (getErrorText().length() == 0) { // Check for identical entries for (int i = 0; i < selectedHWCList.size(); i++) { HWCEntry entry1 = selectedHWCList.get(i); String collectorString1 = entry1.getCollectorString().replaceAll("/.*", "").replaceAll(",.*", ""); for (int j = i + 1; j < selectedHWCList.size(); j++) { HWCEntry entry2 = selectedHWCList.get(j); String collectorString2 = entry2.getCollectorString().replaceAll("/.*", "").replaceAll(",.*", ""); if (collectorString1.equals(collectorString2)) { setErrorText( String.format( AnLocale.getString("Identical counters in list: \'%s\' and \'%s\'"), entry1.getCollectorString(), entry2.getCollectorString())); break; } } } } autoUpdate(); } private void setErrorText(String errorText) { if (errorText != null && !errorText.isEmpty()) { errorLabel.setText(errorText); errorLabel.setVisible(true); } else { errorLabel.setText(""); errorLabel.setVisible(false); } } private String getErrorText() { return errorLabel.getText(); } // Set all HWC attribute related controls public void setAttrButtons() { attrList.setListData(sel_attr.toArray()); if (sel_attr.isEmpty()) { remAttr.setEnabled(false); modAttr.setEnabled(false); attrScrollPane.setEnabled(false); } else { attrList.setSelectedIndex(0); remAttr.setEnabled(true); modAttr.setEnabled(true); attrScrollPane.setEnabled(true); } attrScrollPane.revalidate(); attrScrollPane.repaint(); } // Set Attribute comboBox depending on type of counter public void setAttributeCombo() { String select_ctr = (String) hwc2_prof.combo.getSelectedItem(); if (!hasAttributes(select_ctr)) { sel_attr.clear(); setAttrButtons(); attr_warn = false; ctr_attr.combo.setEnabled(false); addAttr.setEnabled(false); attrScrollPane.setEnabled(false); ctr_attr.field.setEnabled(false); } else { String select_attr = (String) ctr_attr.combo.getSelectedItem(); // Get selected attribute and disable/enable buttons based on that if ((select_attr != null) && (select_attr.equals(AnLocale.getString("None")))) { if (hwc_att_data[0].length == 1) { ctr_attr.combo.setEnabled(false); } else { ctr_attr.combo.setEnabled(true); } addAttr.setEnabled(false); attrScrollPane.setEnabled(false); ctr_attr.field.setEnabled(false); } else { addAttr.setEnabled(true); ctr_attr.combo.setEnabled(true); attrScrollPane.setEnabled(true); ctr_attr.field.setEnabled(true); } } } // check if counter has attributes public boolean hasAttributes(String ctr_name) { // machine has no attributes if (hwc_attr_list.length == 0) { return false; } HWCEntry hw_type = hwcI18NMap.get(ctr_name); if (hw_type == null) { return false; } return hw_type.supportsAttrs(); } // Add JDK path combobox with Browse button public final class TargetJDK extends CollectUtility.AnComboBox implements CollectUtility.Browseable, ItemListener { final JPanel panel; final JCheckBox check; final JButton button; final JLabel text; public TargetJDK( final CollectUtility.CList list, final CollectData cdata, final char mnemonic, final String label, final char browser_mnem) { super(50); this.check = cdata.check; String str, head; final List headers = new ArrayList(6); headers.add(AnLocale.getString("Path:")); headers.add("$JDK_HOME"); headers.add("$JAVA_PATH"); headers.add(AnLocale.getString("Installed Java")); headers.add(AnLocale.getString("Current JVM")); headers.add(AnLocale.getString("Default (PATH based)")); add(CollectUtility.AnComboBox.COMBO_TEXT, (String) headers.get(0), ipc_str_empty, true); for (int i = 1; i < 6; i++) { head = (String) headers.get(i); // process environment variables if (head.startsWith("$")) { str = getenv(head.substring(1)); if (str != null && str.equals(ipc_str_empty)) { head += ":"; add(CollectUtility.AnComboBox.COMBO_TEXT, head, str, false); } } else if (head.equals(AnLocale.getString("Installed Java"))) { head += ":"; String os_name = System.getProperty("os.name"); if (os_name.equals("Linux")) { str = "/usr/java/j2sdk1.4.2_06"; } else { str = "/usr/jdk/j2sdk1.4.2_06"; } add(CollectUtility.AnComboBox.COMBO_TEXT, head, str, false); } else if (head.equals(AnLocale.getString("Current JVM"))) { head += ":"; str = System.getProperty("java.home"); add(CollectUtility.AnComboBox.COMBO_TEXT, head, str, false); } else if (head.equals(AnLocale.getString("Default (PATH based)"))) { str = ipc_str_empty; add(CollectUtility.AnComboBox.COMBO_ITEM, head, str, false); } } this.setSelectedIndex(1); // select one of JDK pathes text = (JLabel) CollectUtility.getItem(label + ":"); text.setDisplayedMnemonic(mnemonic); text.getAccessibleContext().setAccessibleName(label); text.getAccessibleContext().setAccessibleDescription(label); text.setLabelFor(this); panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); panel.add(this); button = new JButton(AnLocale.getString("Browse"), AnUtility.open_icon); // button.setMnemonic(browser_mnem); button.setMargin(CollectUtility.buttonMargin); button.addActionListener(CollectPanel.this); // button.addActionListener(this)--; button.setActionCommand(label); button.setToolTipText(AnLocale.getString("Browse...")); // button.setMnemonic(browser_mnem); panel.add(button); list.add(text, panel); if (check != null) { check.addItemListener(this); } text.setEnabled(cdata.isChecked()); button.setEnabled(cdata.isChecked()); setEnabled(cdata.isChecked()); setEditable(cdata.isChecked()); } // Set value @Override public void setValue(final String path) { final String java_bin = path + File.separatorChar + "bin" + File.separatorChar + "java"; if (!(new File(java_bin).exists())) { showError(java_bin + AnLocale.getString(" doesnt't exist")); } else { setSelectedIndex(0); this.setText(path); } } @Override public String getValue() { return getText(); } // Enable/disable setting @Override public void itemStateChanged(final ItemEvent event) { if (event.getSource() == check) { setEnabled(check.isSelected()); setEditable(check.isSelected()); text.setEnabled(check.isSelected()); button.setEnabled(check.isSelected()); vm_args.text.setEnabled(check.isSelected()); vm_args.setEnabled(check.isSelected()); } } } // Add label/text_field with browser public final class CollectExp extends CollectUtility.CText implements FocusListener, CollectUtility.Browseable { final int type; String value; final JLabel text; final JPanel panel; public CollectExp( final int type, final CollectUtility.CList list, final String value, final char mnemonic, final String label, final boolean browser, final char browser_mnem, final int width, boolean required) { super(value, width, JTextField.LEFT); this.type = type; this.value = value; setEditable(true); addFocusListener(this); if (required) { text = (JLabel) CollectUtility.getItem(label + ": *"); } else { text = (JLabel) CollectUtility.getItem(label + ":"); } text.setDisplayedMnemonic(mnemonic); text.getAccessibleContext().setAccessibleName(label); text.getAccessibleContext().setAccessibleDescription(label); text.setLabelFor(this); panel = new JPanel(new FlowLayout(FlowLayout.LEFT)); panel.add(this); // Need file browser if (browser) { final JButton button = new JButton("..."); // button.setMargin(CollectUtility.buttonMargin); button.addActionListener(CollectPanel.this); button.setActionCommand(label); button.setToolTipText(AnLocale.getString("Browse...")); // button.setMnemonic(browser_mnem); panel.add(button); } list.add(text, panel); } public CollectExp( final int type, final CollectUtility.CList list, final String value, final char mnemonic, final String label, final boolean browser, final char browser_mnem) { this(type, list, value, mnemonic, label, browser, browser_mnem, 60, false); } public CollectExp( final int type, final CollectUtility.CList list, final String value, final char mnemonic, final String label, final boolean browser, final char browser_mnem, boolean required) { this(type, list, value, mnemonic, label, browser, browser_mnem, 60, required); } // Set value @Override public void setValue(final String path) { if (checkValue(path)) { setText(path); } } @Override public String getValue() { return getText(); } // Check value public boolean checkValue(final String path) { String exp_name_suffix = ".er"; switch (type) { case CEXP_TARGET: updateTitle(path); break; case CEXP_NAME: if ((path.length() != 0) && !path.endsWith(exp_name_suffix)) { showError(AnLocale.getString("The experiment name must end in the string .er")); value = path + exp_name_suffix; return false; } break; case CEXP_DIR: String en = exp_name.getValue(); if (null != en && en.endsWith(exp_name_suffix)) { // do nothing, user specified the correct experiment name } else if (null != en && en.length() > 0) { // user specified invalid experiment name - add ".er" en = en + exp_name_suffix; exp_name.setText(en); } else { // experiment name is null or empty AnUtility.checkIPCOnWrongThread(false); exp_name.setText(CGetExpName(path.length() == 0 ? "." : path)); AnUtility.checkIPCOnWrongThread(true); } break; case CEXP_GROUP: if ((path.length() != 0) && !path.endsWith(".erg")) { showError(AnLocale.getString("The group name must end in the string .erg")); return false; } break; } value = path; return true; } // Lost focus @Override public void focusLost(final FocusEvent event) { if (event.isTemporary()) { return; } if (!checkValue(getText())) { setText(value); } } // Gain focus @Override public void focusGained(final FocusEvent event) {} } // TEMPORARY SOLUTION // This flag indicates that the error dialog is shown, // but the problem is not fixed yet. boolean errorCollectorControlValue = false; // For collect data public final class CollectData extends JPanel implements ItemListener { final JCheckBox check; final JButton button; JLabel text; JComboBox combo; JTextField field; final String name; final String[][] data; CollectData parent, child; String cust_val; boolean add_child_data; boolean available; // Constructor for the 1st row public CollectData( final boolean set, final char mnemonic, final String title, final char mnemonic_r, final String label, final String[][] data, final int alignment, final boolean do_align, final String name) { this.name = name; this.data = data; parent = null; child = null; button = null; add_child_data = false; available = true; setLayout(new FlowLayout(FlowLayout.LEFT, 4, 0)); // Enable or disable CheckBox if (title != null) { check = new JCheckBox(title, set); check.setMargin(CollectUtility.buttonMargin); if (mnemonic != ' ' && mnemonic != '0') { check.setMnemonic(mnemonic); } check.getAccessibleContext().setAccessibleDescription(title); add(check); } else { check = null; } // Extra options if (data != null) { setOption(set, mnemonic_r, label, alignment); } else if (check != null) { check.addItemListener(this); // NM } if (title == null) { if (mnemonic != ' ' && mnemonic != '0') { text.setDisplayedMnemonic(mnemonic); text.setLabelFor(combo); } text.setEnabled(set); } else if (text != null && combo != null) { text.setLabelFor(combo); text.setEnabled(set); } if (do_align) { data_list.add(this); } } // Constructor for the 2nd row if any public CollectData( final CollectData parent, final char mnemonic, final String title, final char mnemonic_r, final String label, final String[][] data, final int alignment, final boolean do_align, final boolean add_child_data, final String name) { final JPanel head_panel; this.name = name; this.data = data; this.parent = parent; child = null; parent.child = this; parent.add_child_data = add_child_data; check = parent.check; setLayout(new FlowLayout(FlowLayout.LEFT, 4, 0)); // Show button if (title != null) { button = new JButton(title); button.setMargin(CollectUtility.buttonMargin); if (mnemonic != ' ') { button.setMnemonic(mnemonic); } button.addActionListener(CollectPanel.this); button.getAccessibleContext().setAccessibleDescription(title); head_panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0)); head_panel.setOpaque(false); head_panel.add(button); add(head_panel); } else { button = null; // add(new JPanel()); } // Extra options setOption(check.isSelected(), mnemonic_r, label, alignment); if (do_align) { data_list.add(this); } if (check != null) { check.setOpaque(false); } if (button != null) { button.setOpaque(false); } if (text != null) { text.setOpaque(false); } if (combo != null) { combo.setOpaque(false); } if (field != null) { field.setOpaque(false); } setOpaque(false); } // Extra options public void setOption( boolean set, final char mnemonic, final String label, final int alignment) { final String[] list; final String init_val; add(text = (JLabel) CollectUtility.getItem(label)); text.getAccessibleContext().setAccessibleName(label); text.getAccessibleContext().setAccessibleDescription(label); if (mnemonic != ' ' && mnemonic != '0') { text.setDisplayedMnemonic(mnemonic); } if (data[0].length == 0) { check.setEnabled(false); text.setEnabled(false); set = false; list = new String[1]; list[0] = init_val = cust_val = AnLocale.getString("N/A"); } else { list = data[0]; if (data[1] == null) // text value = combo { init_val = cust_val = data[0][0]; } else if ((parent != null) && (parent.data != null) && (parent.data[0].length == 0)) { // not available if (button != null) { button.setEnabled(false); } text.setEnabled(false); init_val = cust_val = data[1][0]; } else { // text value = data[1] init_val = data[1][0]; cust_val = data[1][data[1].length - 1]; } } add(combo = new JComboBox(list)); add(field = new JTextField(init_val, 8)); combo.setEnabled(set); // combo.setSelectedItem(list[0]); final JLabel lab = ((JLabel) CollectUtility.getItem(label)); lab.setLabelFor(combo); lab.getAccessibleContext().setAccessibleName(label); lab.getAccessibleContext().setAccessibleDescription(label); combo.getAccessibleContext().setAccessibleName(label); combo.getAccessibleContext().setAccessibleDescription(label); field.getAccessibleContext().setAccessibleName(label); field.getAccessibleContext().setAccessibleDescription(label); field.setEnabled(set && (data[1] == null)); field.setHorizontalAlignment(alignment); if (check != null) { check.addItemListener(this); } combo.addItemListener(this); } // Get the value public String getValue() { final String value; if (check == null) { return field.getText(); } if (!check.isSelected()) { return null; } if (field == null) { return ipc_str_on; } value = field.getText(); if (child == null || !add_child_data) { return value; } return value + ipc_str_comma + child.getValue(); } // Get the check value public boolean isChecked() { if (check == null || !check.isSelected()) { return false; } return true; } // Set checkbox public void setChecked(final boolean checked) { if (check != null) { check.setSelected(checked); } } // Enable/disable setting @Override public void itemStateChanged(final ItemEvent event) { final Object src = event.getSource(); final int state, size; String item; synchronized (globalSem) { if (inItemStateChanged) { return; // no recursion } inItemStateChanged = true; if (src == check) { state = event.getStateChange(); if (state == ItemEvent.SELECTED) { if ((src == count_data.check) || (src == deadlock_trace.check) || (src == data_race.check)) { // Disable conflicting controls if (src == count_data.check) { clock_prof.check.setEnabled(false); clock_prof.check.setSelected(false); clock_prof.combo.setEnabled(false); clock_prof.text.setEnabled(false); hwc1_prof.check.setEnabled(false); hwc1_prof.check.setSelected(false); // hwc1_prof.??.setEnabled(false); // hwc1_prof.??.setEnabled(false); sample.check.setEnabled(false); sample.check.setSelected(false); sample.combo.setEnabled(false); sample.text.setEnabled(false); sample_sig.check.setEnabled(false); sample_sig.check.setSelected(false); sample_sig.combo.setEnabled(false); sample_sig.text.setEnabled(false); } sync_trace.check.setEnabled(false); sync_trace.check.setSelected(false); sync_trace.combo.setEnabled(false); sync_trace.text.setEnabled(false); io_trace.check.setEnabled(false); io_trace.check.setSelected(false); heap_trace.check.setEnabled(false); heap_trace.check.setSelected(false); if ((src == deadlock_trace.check) || (src == data_race.check)) { count_data.check.setEnabled(false); count_data.check.setSelected(false); } else { deadlock_trace.check.setEnabled(false); deadlock_trace.check.setSelected(false); data_race.check.setEnabled(false); data_race.check.setSelected(false); } mpi_trace.check.setEnabled(false); mpi_trace.check.setSelected(false); jvm_prof.check.setEnabled(false); jvm_prof.check.setSelected(false); if ((target_jdk != null) && (target_jdk.check != null)) { target_jdk.check.setEnabled(false); target_jdk.text.setEnabled(false); } if ((vm_args != null) && (vm_args.text != null)) { vm_args.text.setEnabled(false); } if (vm_args != null) { vm_args.setEnabled(false); } } else { count_data.check.setEnabled(false); count_data.check.setSelected(false); // NM deadlock_trace.check.setEnabled(false); // NM data_race.check.setEnabled(false); if ((null != heap_trace) && (null != jvm_prof)) { if (src == jvm_prof.check) { heap_trace.check.setEnabled(false); heap_trace.check.setSelected(false); } if (src == heap_trace.check) { jvm_prof.check.setEnabled(false); jvm_prof.check.setSelected(false); } } } // NM combo.setEnabled(true); String val = ipc_str_on; if (text != null) { text.setEnabled(true); } if (combo != null) { combo.setEnabled(true); // Enable it if it is 'Custom' item = (String) combo.getSelectedItem(); field.setEnabled((data[1] == null) || item.startsWith(AnLocale.getString("Custom"))); if (item.startsWith(AnLocale.getString("Custom"))) { if (text != null) { val = field.getText(); // Correct? } } else if (data[1] == null) { val = item; } else { val = field.getText(); // Correct? // find value // size = data[0].length; // for (int i = 0; i < size; i++) { // if (item.equals(data[0][i])) { // //field.setText(data[1][i]); // val = data[1][i]; // break; // } // } } } String err = null; String cur_name = name; if ((ipc_str_hwc1_val.equals(name)) || (ipc_str_hwc2_prof.equals(name)) || (ipc_str_dspace_hwc1.equals(name)) || (ipc_str_hwc_reg_alloc.equals(name)) || (ipc_str_hwc_ctr_attr.equals(name))) { // TEMPORARY: use ipc_str_hwcprof cur_name = ipc_str_hwcprof; if (((hwc1_prof.getValue()) != null) && (selectedHWCList.size() > 0)) { String ctrlist = selectedHWCList.get(0).getName(); for (int i = 1; i < selectedHWCList.size(); i++) { ctrlist = ctrlist + ipc_str_comma + selectedHWCList.get(i).getName(); } val = ctrlist; } } if (ipc_str_on.equals(val) && (ipc_str_MPIexpt.equals(cur_name))) { val = "CT"; // TEMPORARY: "-M" is not properly implemented yet } if (ipc_str_hwcprof.equals(cur_name) && (ipc_str_on.equals(val) || val.startsWith(ipc_str_hwc_default))) { // skip this call (TEMPORARY: "-h on" is not implemented yet) // err = null; // We come here when user clicks on "Hardware Counter Profiling" } else if ((ipc_str_zero.equals(val) || ipc_str_None.equals(val) || ipc_str_off.equals(val)) && (ipc_str_hwcprof.equals(cur_name))) { // skip this call (HWC value is not selected yet) } else { err = Collector.setCollectorControlValue(cur_name, val); // IPC call } if (err != null) { // Check if this error is already on the screen if (errorCollectorControlValue) { // Let user fix this problem } else { errorCollectorControlValue = true; // Show error/warning dialog // System.err.println("Error 1: setCollectorControlValue(" + cur_name + ", " + val + // ") returned: " + err); // DEBUG AnUtility.showMessage(work_panel, err, JOptionPane.ERROR_MESSAGE); // Get value String cur_value = Collector.getCollectorControlValue(cur_name); // IPC call // System.err.println("getCollectorControlValue(" + cur_name + ") returned: " + // cur_value); // DEBUG if (ipc_str_MPIexpt.equals(cur_name) || (ipc_str_hwcprof.equals(cur_name))) { // TEMPORARY: skip update } else if (null != field) { item = (String) combo.getSelectedItem(); if (item.startsWith(AnLocale.getString("Custom"))) { field.setText(cur_value); } } } } else { errorCollectorControlValue = false; } } else if (state == ItemEvent.DESELECTED) { if ((ipc_str_hwc1_val.equals(name)) || (ipc_str_hwc2_prof.equals(name)) || (ipc_str_dspace_hwc1.equals(name)) || (ipc_str_hwc_reg_alloc.equals(name)) || (ipc_str_hwc_ctr_attr.equals(name))) { // TEMPORARY: skip unset } else { Collector.unsetCollectorControlValue(name); } if (combo != null) { combo.setEnabled(false); } if (text != null) { text.setEnabled(false); } if (field != null) { field.setEnabled(false); } if ((null != heap_trace) && (null != jvm_prof)) { if (src == jvm_prof.check) { javaprof_not_changed_by_user = false; heap_trace.check.setEnabled(true); } if (src == heap_trace.check) { jvm_prof.check.setEnabled(true); jvm_prof.check.setSelected(javaprof_not_changed_by_user); } } if (src == sample.check) { sample_not_changed_by_user = false; } if (src == clock_prof.check) { clkprof_not_changed_by_user = false; } if ((src == count_data.check) || (src == deadlock_trace.check) || (src == data_race.check)) { if (!(count_data.check.isSelected() || deadlock_trace.check.isSelected() || data_race.check.isSelected())) { // Enable all other controls clock_prof.check.setEnabled(true); clock_prof.check.setSelected(clkprof_not_changed_by_user); clock_prof.combo.setEnabled(clkprof_not_changed_by_user); clock_prof.text.setEnabled(clkprof_not_changed_by_user); sync_trace.check.setEnabled(true); hwc1_prof.check.setEnabled(true); sample.check.setEnabled(true); sample.check.setSelected(sample_not_changed_by_user); sample.combo.setEnabled(sample_not_changed_by_user); sample.text.setEnabled(sample_not_changed_by_user); sample_sig.check.setEnabled(true); io_trace.check.setEnabled(true); heap_trace.check.setEnabled(true); if (count_data.available) { count_data.check.setEnabled(true); } if (deadlock_trace.available) { deadlock_trace.check.setEnabled(true); } if (data_race.available) { data_race.check.setEnabled(true); } mpi_trace.check.setEnabled(true); jvm_prof.check.setEnabled(true); jvm_prof.check.setSelected(javaprof_not_changed_by_user); } } else if (!(clock_prof.check.isSelected() || sync_trace.check.isSelected() || hwc1_prof.check.isSelected() || sample.check.isSelected() || sample_sig.check.isSelected() || io_trace.check.isSelected() || heap_trace.check.isSelected() || mpi_trace.check.isSelected() || jvm_prof.check.isSelected())) { if (count_data.available) { count_data.check.setEnabled(true); } if (deadlock_trace.available) { deadlock_trace.check.setEnabled(true); } if (data_race.available) { data_race.check.setEnabled(true); } } } } else if (src == combo) { if (text.getText().equals(AnLocale.getString("Attribute:"))) { setAttributeCombo(); attr_warn = true; } if (text.getText().equals(AnLocale.getString("Counter Name:"))) { String select_ctr = (String) hwc2_prof.combo.getSelectedItem(); setAttributeCombo(); hwc_reg_data = setRegData(select_ctr); } if (text.getText().equals(AnLocale.getString("Hardware Counter Register:"))) { field.setText((String) combo.getSelectedItem()); } item = (String) combo.getSelectedItem(); // Save the custom value for later use if (item.startsWith(AnLocale.getString("Custom"))) { final int sidx = combo.getSelectedIndex(); cust_val = data[1][sidx]; } item = (String) event.getItem(); // Enable it if it is 'Custom' if (item.startsWith(AnLocale.getString("Custom")) || text.getText().equals(AnLocale.getString("Attribute:"))) { field.setEnabled(true); field.setText(cust_val); String val = cust_val; if (val.isEmpty()) { val = "0"; // default value for empty string if ((src == exp_limit) || (src == exp_limit.combo)) { val = "none"; // default value for unlimited size } } if (ipc_str_descendant.equals(name)) { descendant.field.setToolTipText( AnLocale.getString( "Specify regular expression to match base name of the executable to follow")); } boolean need_check = true; if (ipc_str_hwc2_prof.equals(name) && val.startsWith(ipc_str_hwc_default)) { need_check = false; // TEMPORARY: skip check - CLI cannot check the default HWC set yet } if ((ipc_str_hwc1_val.equals(name)) || (ipc_str_dspace_hwc1.equals(name)) || (ipc_str_hwc_reg_alloc.equals(name)) || (ipc_str_hwc_ctr_attr.equals(name))) { // TEMPORARY: skip check - need new API to check these details need_check = false; // TEMPORARY: Need new API } if (need_check) { String err = Collector.setCollectorControlValue(name, val); // IPC call if (err != null) { // System.err.println("Error 2: setCollectorControlValue(" + name + ", " + val + ") // returned: " + err); // DEBUG AnUtility.showMessage(work_panel, err, JOptionPane.ERROR_MESSAGE); } } inItemStateChanged = false; return; // End of critical section } else if (data[1] == null) { field.setText(item); // ??? String err = Collector.setCollectorControlValue(name, item); if (err != null) { // System.err.println("Error 3: setCollectorControlValue(" + name + ", " + item + ") // returned: " + err); // DEBUG AnUtility.showMessage(work_panel, err, JOptionPane.ERROR_MESSAGE); } inItemStateChanged = false; return; // End of critical section } else { field.setEnabled(false); } // Update value size = data[0].length; for (int i = 0; i < size; i++) { if (item.equals(data[0][i])) { field.setText(data[1][i]); String val = data[1][i]; if (val.isEmpty()) { val = "0"; // default value for empty string if (src == exp_limit.combo) { val = "none"; // default value for unlimited size } } // Check value if (ipc_str_hwc2_prof.equals(name) && ipc_str_hwc_default.equals(val)) { break; // TEMPORARY: CLI cannot check the default HWC set yet } if ((ipc_str_hwc1_val.equals(name)) || (ipc_str_dspace_hwc1.equals(name)) || (ipc_str_hwc_reg_alloc.equals(name)) || (ipc_str_hwc_ctr_attr.equals(name))) { // TEMPORARY: skip check - need new API to check these details break; // TEMPORARY: Need new API } AnUtility.checkIPCOnWrongThread(false); String err = Collector.setCollectorControlValue(name, val); // TEMPORARY AnUtility.checkIPCOnWrongThread(true); if (err != null) { // System.err.println("Error 4: setCollectorControlValue(" + name + ", " + val + ") // returned: " + err); // DEBUG JOptionPane.showMessageDialog( (AnWindow.getInstance()).getFrame(), err, AnLocale.getString("Information"), JOptionPane.INFORMATION_MESSAGE); } AnUtility.checkIPCOnWrongThread(false); err = Collector.getCollectorControlValue(name); // TEMPORARY AnUtility.checkIPCOnWrongThread(true); break; } } } inItemStateChanged = false; } // End of critical section } // Align label/combo-box public void setAlignmentX(final ArrayList data_list) { int i; for (i = 0; i < 4; i++) // 1.check 2.label 3.option 4.text { setAlignmentX(i, data_list); } } public void setAlignmentX(final int index, final ArrayList data_list) { int width, max_width; CollectData cd; JComponent cmp; Dimension psize; Iterator iter = data_list.iterator(); max_width = 0; // Find the maximum width while (iter.hasNext()) { cd = (CollectData) iter.next(); if (index >= cd.getComponentCount()) { continue; } cmp = (JComponent) cd.getComponent(index); width = cmp.getPreferredSize().width; if (max_width < width) { max_width = width; } } // Set the maximum width iter = data_list.iterator(); while (iter.hasNext()) { cd = (CollectData) iter.next(); if (index >= cd.getComponentCount()) { continue; } cmp = (JComponent) cd.getComponent(index); psize = cmp.getPreferredSize(); psize.width = max_width; cmp.setPreferredSize(psize); } } } // Set visible @Override public final void setVisible(final boolean set) { super.setVisible(set); if (!set) { return; } // Make the most interesting part, the end, visible if (!profile_running_process && !system_profiling) { target.setVisibleAlign(CollectUtility.TEXT_RIGHT, true); } exp_name.setVisibleAlign(CollectUtility.TEXT_RIGHT, true); exp_dir.setVisibleAlign(CollectUtility.TEXT_RIGHT, true); exp_group.setVisibleAlign(CollectUtility.TEXT_RIGHT, true); work_dir.setVisibleAlign(CollectUtility.TEXT_RIGHT, false); } /** * Class CollectChooser creates AnChooser using AnWindow.getAnChooser() method and provides * methods: getFile setDialogTitle */ final class CollectChooser { AnChooser ac = null; public CollectChooser(final int chooser_type) { String dir = null; ac = anWindow.getAnChooser(title, chooser_type, dir); } /** * Sets Dialog Title * * @param title */ public void setDialogTitle(final String title) { ac.setDialogTitle(title); } /** * Gets file name from the file chooser and returns value via text.setValue(name); * * @param cmd */ public void getFile(final String cmd) { final CollectUtility.Browseable text; AnFile path_file; // NM replace String path; if (cmd.equals(CSTR_TARGET)) { text = target; path = text.getValue().trim(); if (path.equals(ipc_str_empty) || !path.startsWith("/" /*File.separator*/)) { path = work_dir.getText(); if (!path.equals(ipc_str_empty)) { path_file = new AnFile(path); // NM replace } else { path = exp_dir.getText(); path_file = new AnFile(path); // NM replace } } else { path_file = new AnFile(path); // NM replace if (path_file.isFile()) { path_file = (AnFile) path_file.getParentFile(); } } ac.setFileSelectionMode(AnChooser.FILES_ONLY); } else if (cmd.equals(CSTR_DIR)) { text = exp_dir; path = text.getValue(); if (path.equals(ipc_str_empty)) { path = work_dir.getText(); } path_file = new AnFile(path); // NM replace } else if (cmd.equals(CSTR_GROUP)) { text = exp_group; path = text.getValue(); if (!path.equals(ipc_str_empty)) { path_file = (AnFile) new AnFile(path).getParentFile(); // NM replace } else { path = exp_dir.getText(); if (!path.equals(ipc_str_empty)) { path_file = new AnFile(path); // NM replace } else { path = work_dir.getText(); path_file = new AnFile(path); // NM replace } } } else if (cmd.equals(CSTR_WORK)) { text = work_dir; path_file = new AnFile(text.getValue()); // NM replace ac.setFileSelectionMode(AnChooser.DIRECTORIES_ONLY); } else if (cmd.equals(CSTR_TARGET_JDK)) { text = target_jdk; if (text.getValue() != null) { path_file = new AnFile(text.getValue()); // NM replace } else { path_file = new AnFile("/usr/j2se"); // NM replace } ac.setFileSelectionMode(AnChooser.FILES_AND_DIRECTORIES); } else { return; } ac.setCurrentDirectory(path_file); if ((ac.showOpenDialog(work_panel) == AnChooser.APPROVE_OPTION) && ((ac.getSelectedFile()) != null)) { path_file = new AnFile(ac.getSelectedFile().getAbsolutePath()); String name = path_file.getAbsolutePath(); /* if (!Analyzer.getInstance().isRemote()) { // remove .class and full path for java targets if (cmd.equals(CollectPanel.CSTR_TARGET) && AnUtility.getMimeFormat(path_file) == AnUtility.MIME_JAVA_CLASS_FILE) { if (name.endsWith(".class")) { name = name.substring(0, name.lastIndexOf(".class")); } final int sep_ind = name.lastIndexOf(File.separatorChar); if (sep_ind != -1) { name = name.substring(sep_ind + 1); } } } */ text.setValue(name); } } } // end of Class CollectChooser // public interface Provider { public void setTitleStr(String title); } /*------------------------------------- CONSTANTS --------------------------------------------------------*/ public static final String[] aux = {AnLocale.getString("Pause"), AnLocale.getString("Sample")}; public static final char[] mnemonic = { AnLocale.getString('u', "MNEM_COLLECTOR_PAUSE"), AnLocale.getString('S', "MNEM_COLLECTOR_SAMPLE") }; public static final String title = AnLocale.getString("Profile Application"); public static final String title1 = AnLocale.getString("Profile Running Process"); public static final String title2 = AnLocale.getString("Profile Kernel"); // target types and possible errors static final int TARG_ELF_EXECUTABLE = 0; static final int TARG_JAVA_CLASS_FILE = 1; static final int TARG_JAR_FILE = 2; static final int TARG_UNKNOWN_TYPE = -1; static final int TARG_NOT_EXISTS = -2; static final int TARG_IS_NOT_FILE = -3; static final int TARG_IS_NOT_READABLE = -4; } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectorOpenPanel.java������������������������������������0000644�0001750�0001750�00000013105�14517772113�021755� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.collect; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnFile; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.ConfigurationPanel; import java.awt.BorderLayout; import javax.swing.BorderFactory; public class CollectorOpenPanel extends javax.swing.JPanel { private ConfigurationPanel configurationPanel; public CollectorOpenPanel(String experimentPath, String workingDir) { initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); configurationOuterPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); label1.setText( AnLocale.getString("Data collection is complete. Do you want to open the experiment?")); experimentLabel.setText(AnLocale.getString("Experiment:")); pathTextField.setText(experimentPath); pathTextField.setToolTipText(experimentPath); // pathTextField.setFont(pathTextField.getFont().deriveFont(Font.BOLD)); pathTextField.setBorder(BorderFactory.createLineBorder(pathTextField.getBackground(), 5)); // pathTextField.setBorder(null); configurationOuterPanel.setLayout(new BorderLayout()); configurationPanel = new ConfigurationPanel(false); configurationPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); configurationOuterPanel.add(configurationPanel, BorderLayout.CENTER); AnFile file = new AnFile(experimentPath); if (file.exists()) { configurationPanel.initConfigurationChoices(file); configurationPanel.setWorkingDirectory(workingDir); } } public String getWorkingDirectory() { return configurationPanel.getWorkingDirectory(); } public String getConfiguration() { return configurationPanel.getConfiguration(); } public boolean alwaysUseThisConfiguration() { return configurationPanel.alwaysUseThisConfiguration(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; label1 = new javax.swing.JLabel(); experimentLabel = new javax.swing.JLabel(); pathTextField = new javax.swing.JTextField(); configurationOuterPanel = new javax.swing.JPanel(); setLayout(new java.awt.GridBagLayout()); label1.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; add(label1, gridBagConstraints); experimentLabel.setText("jLabel3"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(experimentLabel, gridBagConstraints); pathTextField.setEditable(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); add(pathTextField, gridBagConstraints); javax.swing.GroupLayout configurationOuterPanelLayout = new javax.swing.GroupLayout(configurationOuterPanel); configurationOuterPanel.setLayout(configurationOuterPanelLayout); configurationOuterPanelLayout.setHorizontalGroup( configurationOuterPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 0, Short.MAX_VALUE)); configurationOuterPanelLayout.setVerticalGroup( configurationOuterPanelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 0, Short.MAX_VALUE)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 0, 12, 0); add(configurationOuterPanel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel configurationOuterPanel; private javax.swing.JLabel experimentLabel; private javax.swing.JLabel label1; private javax.swing.JTextField pathTextField; // End of variables declaration//GEN-END:variables } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectPanel3.java�����������������������������������������0000644�0001750�0001750�00000123215�14517772113�020661� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.collect; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.PsParser; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.datatransfer.Clipboard; import java.awt.datatransfer.StringSelection; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import javax.accessibility.AccessibleContext; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.PopupMenuEvent; import javax.swing.table.DefaultTableModel; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; /** Creates first page for Collector GUI to profile a running application */ public class CollectPanel3 extends JPanel { private final String STR_ACTION_UPDATE = AnLocale.getString("Refresh"); private final String STR_ACTION_SORTBY = AnLocale.getString("Sort by"); private final String STR_ACTION_COPY_ALL = AnLocale.getString("Copy All"); private JPanel workPanel; private AnWindow anWindow; private AnMenuListener menuListener; private String processID; private String processName; private String[] tableColumns = new String[6]; /** * Creates new form CollectPanel3 * * @param aWindow */ public CollectPanel3(final AnWindow aWindow) { workPanel = this; this.anWindow = aWindow; initComponents(); postInitComponents(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; jPanel2 = new javax.swing.JPanel(); jLabel2 = new javax.swing.JLabel(); jLabel1 = new javax.swing.JLabel(); jComboBox1 = new javax.swing.JComboBox(); jButton1 = new javax.swing.JButton(); jScrollPane2 = new javax.swing.JScrollPane(); processesTable = new javax.swing.JTable(); jPanel3 = new javax.swing.JPanel(); jTextField1 = new javax.swing.JTextField(); jLabel3 = new javax.swing.JLabel(); jComboBox2 = new javax.swing.JComboBox(); jLabel4 = new javax.swing.JLabel(); jComboBox3 = new javax.swing.JComboBox(); jLabel5 = new javax.swing.JLabel(); jComboBox4 = new javax.swing.JComboBox(); jLabel6 = new javax.swing.JLabel(); jTextField2 = new javax.swing.JTextField(); jLabel7 = new javax.swing.JLabel(); jButton2 = new javax.swing.JButton(); jButton6 = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); jPanel2.setLayout(new java.awt.GridBagLayout()); jLabel2.setLabelFor(processesTable); jLabel2.setText("Select the Process to profile"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; jPanel2.add(jLabel2, gridBagConstraints); jLabel1.setLabelFor(jComboBox1); jLabel1.setText("Filter:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); jPanel2.add(jLabel1, gridBagConstraints); jComboBox1.setEditable(true); jComboBox1.setModel(new javax.swing.DefaultComboBoxModel(new String[] { " " })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); jPanel2.add(jComboBox1, gridBagConstraints); jButton1.setText("Refresh"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); jPanel2.add(jButton1, gridBagConstraints); processesTable.setAutoCreateRowSorter(true); processesTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null}, {null, null, null, null, null, null} }, new String [] { "User Name", "PID", "PPID", "Start Time", "CPU time", "Command" } ) { Class[] types = new Class [] { java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class, java.lang.String.class }; boolean[] canEdit = new boolean [] { false, false, false, false, false, false }; public Class getColumnClass(int columnIndex) { return types [columnIndex]; } public boolean isCellEditable(int rowIndex, int columnIndex) { return canEdit [columnIndex]; } }); processesTable.setToolTipText("Select the process to profile"); processesTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS); processesTable.setMaximumSize(new java.awt.Dimension(32768, 32768)); processesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); jScrollPane2.setViewportView(processesTable); processesTable.getColumnModel().getSelectionModel().setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); jPanel2.add(jScrollPane2, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 12); add(jPanel2, gridBagConstraints); jPanel3.setLayout(new java.awt.GridBagLayout()); jTextField1.setColumns(20); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); jPanel3.add(jTextField1, gridBagConstraints); jLabel3.setLabelFor(jTextField1); jLabel3.setText("Target PID:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); jPanel3.add(jLabel3, gridBagConstraints); jComboBox2.setEditable(true); jComboBox2.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "ktest.1.er" })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jComboBox2, gridBagConstraints); jLabel4.setLabelFor(jComboBox2); jLabel4.setText("Experiment Name:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); jPanel3.add(jLabel4, gridBagConstraints); jComboBox3.setEditable(true); jComboBox3.setModel(new javax.swing.DefaultComboBoxModel(new String[] { " " })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jComboBox3, gridBagConstraints); jLabel5.setLabelFor(jComboBox3); jLabel5.setText("Experiment Directory:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); jPanel3.add(jLabel5, gridBagConstraints); jComboBox4.setEditable(true); jComboBox4.setModel(new javax.swing.DefaultComboBoxModel(new String[] { " " })); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jComboBox4, gridBagConstraints); jLabel6.setLabelFor(jComboBox4); jLabel6.setText("Experiment Group:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); jPanel3.add(jLabel6, gridBagConstraints); jTextField2.setEditable(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); jPanel3.add(jTextField2, gridBagConstraints); jLabel7.setLabelFor(jTextField2); jLabel7.setText("Target Name:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 8, 0, 0); jPanel3.add(jLabel7, gridBagConstraints); jButton2.setText("..."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jButton2, gridBagConstraints); jButton6.setText("..."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 5; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); jPanel3.add(jButton6, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(12, 12, 12, 12); add(jPanel3, gridBagConstraints); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; private javax.swing.JButton jButton2; private javax.swing.JButton jButton6; private javax.swing.JComboBox jComboBox1; private javax.swing.JComboBox jComboBox2; private javax.swing.JComboBox jComboBox3; private javax.swing.JComboBox jComboBox4; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JLabel jLabel4; private javax.swing.JLabel jLabel5; private javax.swing.JLabel jLabel6; private javax.swing.JLabel jLabel7; private javax.swing.JPanel jPanel2; private javax.swing.JPanel jPanel3; private javax.swing.JScrollPane jScrollPane2; private javax.swing.JTextField jTextField1; private javax.swing.JTextField jTextField2; private javax.swing.JTable processesTable; // End of variables declaration//GEN-END:variables /** Initialize combo boxes with default values */ public void postInitComponents() { AnUtility.setTextAndAccessibleContext(jLabel2, AnLocale.getString("Process")); AnUtility.setTextAndAccessibleContext(jLabel1, AnLocale.getString("Filter:")); jLabel1.setDisplayedMnemonic(AnLocale.getString('F', "MN_PROFILE_RUNNING_PROCESS_Filter")); jLabel1.setLabelFor(jComboBox1); AnUtility.setTextAndAccessibleContext(jLabel3, AnLocale.getString("Target PID:")); AnUtility.setTextAndAccessibleContext(jLabel4, AnLocale.getString("Experiment Name:")); AnUtility.setTextAndAccessibleContext(jLabel5, AnLocale.getString("Experiment Directory:")); AnUtility.setTextAndAccessibleContext(jLabel6, AnLocale.getString("Experiment Group:")); AnUtility.setTextAndAccessibleContext(jLabel7, AnLocale.getString("Target Name:")); AnUtility.setAccessibleContext(jButton1.getAccessibleContext(), AnLocale.getString("Refresh")); jButton1.setMnemonic(AnLocale.getString('R', "MN_PROFILE_RUNNING_PROCESS_Refresh")); AnUtility.setAccessibleContext(jButton2.getAccessibleContext(), AnLocale.getString("Browse")); AnUtility.setAccessibleContext(jButton6.getAccessibleContext(), AnLocale.getString("Browse")); AnUtility.setAccessibleContext( processesTable.getTableHeader().getAccessibleContext(), AnLocale.getString("Process Table")); processesTable.getSelectionModel().addListSelectionListener(new SelectionHandler()); jComboBox1.setSelectedItem(""); // Filter String user = System.getProperty("user.name"); jComboBox1.addItem(user); // Filter jComboBox2.setSelectedItem("test.1.er"); // Experiment name // jComboBox2.addItem(empty_str); // Experiment name jComboBox3.setSelectedItem(""); // Experiment directory // jComboBox3.addItem(empty_str); // Experiment directory jComboBox4.setSelectedItem(""); // Experiment group // jComboBox4.addItem(empty_str); // Experiment group jButton1.addActionListener(new RefreshActionHandler()); // Refresh jButton2.addActionListener(new ExpDirActionHandler()); // Experiment directory browser jButton6.addActionListener(new ExpGroupActionHandler()); // Experiment group browser // Init column names tableColumns[0] = AnLocale.getString("User Name") + " (UID)"; tableColumns[1] = AnLocale.getString("Process ID") + " (PID)"; tableColumns[2] = AnLocale.getString("Parent Process ID") + " (PPID)"; tableColumns[3] = AnLocale.getString("Start Time") + " (START TIME)"; tableColumns[4] = AnLocale.getString("CPU Time") + " (CPU TIME)"; tableColumns[5] = AnLocale.getString("Process name") + " (COMMAND)"; // Popup menu menuListener = new AnMenuListener(this, processesTable); processesTable.addMouseListener(menuListener); KeyStroke ks = KeyboardShortcuts.contextMenuActionShortcut; processesTable.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, ks); processesTable .getActionMap() .put( ks, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { JPopupMenu popup = initPopup(processesTable); if (popup != null) { JTable src = (JTable) ev.getSource(); Rectangle cellRect, visRect; visRect = src.getVisibleRect(); cellRect = visRect; if (cellRect.width > 0) { // calculate a good place to show the menu cellRect.x += cellRect.width / 4; } if (cellRect.height > 0) { cellRect.y += cellRect.height / 4; } popup.show(src, cellRect.x, cellRect.y); } } }); jTextField2.setColumns(50); } /** Copy all lines to the system clipboard */ protected void copyAll() { String text = ""; int rows = processesTable.getRowCount(); int columns = processesTable.getColumnCount(); int collen[] = new int[columns]; // Print table header for (int j = 0; j < columns; j++) { if (tableColumns.length > j) { String s = tableColumns[j]; text += s; collen[j] = s.length(); } if (columns - 1 == j) { break; } text += " | "; } text += "\n"; // Print table rows for (int i = 0; i < rows; i++) { for (int j = 0; j < columns; j++) { String s = processesTable.getValueAt(i, j).toString(); text += s; // Try to format the string if (columns - 1 == j) { break; } int k = collen[j] - s.length(); while (k > 0) { text += " "; k--; } text += " | "; } text += "\n"; } // copyToClipboard(text); StringSelection data = new StringSelection(text); Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard(); clipboard.setContents(data, data); } public void update() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { updateTable(); updateSelection(); updateTextFields(); } }); } private void updateTable() { AnUtility.checkIfOnAWTThread(true); final String f = "/bin/ps -ef"; AnUtility.checkIPCOnWrongThread(false); String p = Collector.getRunningProcesses(f); // IPC call String o = Collector.getOSFamily(); // IPC call AnUtility.checkIPCOnWrongThread(true); PsParser psParser = PsParser.getDefault(o); psParser.setPsOutput(p); List<String> th = psParser.getData(true).header(); // Headers // Customize column names for (int i = 0; i < th.size(); i++) { String s = th.get(i); if ("STIME".equals(s)) { th.set(i, "START TIME"); } if ("TIME".equals(s)) { th.set(i, "CPU TIME"); } if ("CMD".equals(s)) { th.set(i, "COMMAND"); } } java.util.regex.Pattern re = java.util.regex.Pattern.compile("."); String filter = getFilter(); if (!"".equals(filter)) { re = java.util.regex.Pattern.compile(".*" + filter + ".*"); } List<List<String>> tp = psParser.getData(true).processes(re); // Processes // Convert List<List<String>> to Object[][].... List<Object[]> tpList = new ArrayList<Object[]>(); for (List<String> object : tp) { tpList.add(object.toArray()); } Object[][] tpArray = new Object[tpList.size()][]; int index = 0; for (Object[] x : tpList) { tpArray[index++] = x; } ((DefaultTableModel) processesTable.getModel()).setDataVector(tpArray, th.toArray()); // Set coulumn widths (available space goes to last column) for (int i = 0; i < processesTable.getColumnCount() - 1; i++) { processesTable.getColumnModel().getColumn(i).setPreferredWidth(80); processesTable.getColumnModel().getColumn(i).setMaxWidth(300); } } /** * Get Filter * * @return String filter */ private String getFilter() { String filter = ""; if (null != jComboBox1.getSelectedItem()) { filter = jComboBox1.getSelectedItem().toString(); } return filter; } /** * Get Process ID * * @return String PID */ public String getProcessID() { String PID = ""; processID = jTextField1.getText(); if (null != processID) { PID = processID; } return PID; } /** * Get Process Name * * @return name */ public String getProcessName() { String proc = ""; processName = jTextField1.getText(); // TEMPORARY if (null != processName) { proc = processName; } return proc; } /** * Get Experiment Directory * * @return String directory */ public String getExperimentDirectory() { String expdir = ""; if (null != jComboBox3.getSelectedItem()) { expdir = jComboBox3.getSelectedItem().toString(); } if (expdir.length() < 1) { // XXX should it be here? expdir = CGetCurDir(); // IPC call } return expdir; } /** * Set Experiment Directory * * @param expdir */ public void setExperimentDirectory(String expdir) { jComboBox3.setSelectedItem(expdir); } /** * Get Experiment Name * * @return String directory */ public String getExperimentName() { String expdir = ""; if (null != jComboBox2.getSelectedItem()) { expdir = jComboBox2.getSelectedItem().toString(); } return expdir; } /** * Get Experiment Group * * @return String group */ public String getExperimentGroup() { String group = ""; if (null != jComboBox4.getSelectedItem()) { group = jComboBox4.getSelectedItem().toString(); } return group; } /** * Set Experiment Group * * @param expdir */ public void setExperimentGroup(String group) { jComboBox4.setSelectedItem(group); } /** * Get Current Directory * * @return */ private String CGetCurDir() { return Analyzer.getInstance().getWorkingDirectory(); } /** * Get Preview Command * * @return String command */ public String getPreviewCommand() { String col_cmd = "er_kernel"; String pid = getProcessID(); // jTextField1.getText(); if ((null != pid) && (pid.length() > 0)) { col_cmd += " -F =" + pid; } col_cmd += " -d " + getExperimentDirectory(); // jComboBox3.getItemAt(0); col_cmd += " -o " + getExperimentName(); // jComboBox2.getItemAt(0); col_cmd += " -g " + getExperimentGroup(); // jComboBox4.getItemAt(0); System.out.println(col_cmd); // DEBUG return col_cmd; } private void actionPerformed2(final ActionEvent event) { // final Iterator iter; int i; final String cmd = event.getActionCommand(); final String empty = ""; final String slash = "/"; if (cmd.equals(empty)) { int theState = event.getID(); // state change event if (theState == Collector.COLLECTING_RUNNING) { // if (buttons[0].isEnabled()) { // the collection has just started // writeln(AnLocale.getString("Running: ") + new File(target.getText()).getName(), // getOutLog()); // set_runtime_buttons(); // } else { // the collection has been resumed // writeln(AnLocale.getString("Data collection resumed"), getOutLog()); // writeln("(" + AnLocale.getString("process id ") + m_collector.getProcessPID() + ")", // getOutLog()); // buttons[2].setText(AnLocale.getString("Pause")); // buttons[2].setActionCommand(AnLocale.getString("Pause")); // } } else if (theState == Collector.COLLECTING_PAUSED) { // writeln(AnLocale.getString("Data collection paused"), getOutLog()); // writeln("(" + AnLocale.getString("process id ") + m_collector.getProcessPID() + ")", // getOutLog()); // buttons[2].setText(AnLocale.getString("Resume")); // buttons[2].setActionCommand(AnLocale.getString("Resume")); } else if (theState == Collector.COLLECTING_TERMINATING) { // writeln(AnLocale.getString("Data collection terminating"), getOutLog()); } else if ((theState == Collector.COLLECTING_TERMINATED) || (theState == Collector.COLLECTING_COMPLETED)) { if (theState == Collector.COLLECTING_TERMINATED) { // writeln(AnLocale.getString("Data collection terminated"), getOutLog()); } // NM if (output_thread != null) { // NM Thread stopped = output_thread; // NM output_thread=null; // NM stopped.interrupt(); // NM } // writeln(AnLocale.getString("Process ID: ") + m_collector.getProcessPID(), getOutLog()); // writeln(AnLocale.getString("Elapsed Time: ") + m_collector.getElapsedTime() + " ms", // getOutLog()); // writeln(AnLocale.getString("Execution completed, exit status is ") + // m_collector.getProcessExitValue(), getOutLog()); // final String actual_expname = m_collector.getActualExpName(); // getBtClear().setEnabled(true); // resetButtons(); // exp_name.setValue(m_collector.getNextExpName()); } } else if (cmd.equals(AnLocale.getString("Refresh"))) { if (anWindow != null) { update(); } else { // TEST refreshPS(processesTable); updateSelection(); updateTextFields(); } } else if (cmd.equals(AnLocale.getString("Pause"))) { // if (m_collector.pause(AnUtility.getSignalValue(pause_sig.getValue()))) { // } // tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Resume"))) { // if (m_collector.resume(AnUtility.getSignalValue(pause_sig.getValue()))) { // } // tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Sample"))) { // if (m_collector.sample(AnUtility.getSignalValue(sample_sig.getValue()))) { // writeln(AnLocale.getString("Manual sample"), getOutLog()); // } // tab_pane.setSelectedIndex(2); } else if (cmd.equals(AnLocale.getString("Terminate"))) { } else if (cmd.equals(AnLocale.getString("Preview Command:"))) { System.out.println(getPreviewCommand()); } else if (cmd.equals(AnLocale.getString("Cancel"))) { } else { // showChooser(cmd); } } private void updateSelection() { AnUtility.checkIfOnAWTThread(true); String last_pid = processID; // jTextField1.getText(); if ((last_pid != null) && (last_pid.length() > 0)) { // Check if selection is still correct int row = processesTable.getSelectedRow(); int count = processesTable.getRowCount(); if (count < row) { row = -1; } if (row >= 0) { String s = processesTable.getModel().getValueAt(row, 1).toString(); if (!last_pid.equals(s)) { row = -1; } } if (row < 0) { // Find last_pid in the table for (row = 0; row < count; row++) { String s = processesTable.getModel().getValueAt(row, 1).toString(); if (last_pid.equals(s)) { if (row != processesTable.getSelectedRow()) { processesTable.setRowSelectionInterval(row, row); } return; } } // Not found - select first row row = 0; } // New selection if (row < count) { processesTable.setRowSelectionInterval(row, row); return; } } if (null == processID) { // first time processesTable.clearSelection(); } else { int count = processesTable.getRowCount(); if (count > 0) { // select first row int row = 0; processesTable.setRowSelectionInterval(row, row); } } } private void updateTextFields() { AnUtility.checkIfOnAWTThread(true); int rows = processesTable.getRowCount(); if (rows <= 0) { return; } int row = processesTable.getSelectedRow(); if (row < 0) { return; // No selection by default } if (rows < row) { row = 0; } int lastCol = processesTable.getColumnCount() - 1; if (lastCol > 0) { // Get process ID String p = processesTable.getValueAt(row, 1).toString(); jTextField1.setText(p); // Process ID processID = p; // Get process name String s = processesTable.getValueAt(row, lastCol).toString(); int spaceind = s.indexOf(' '); if (spaceind > 0) { s = s.substring(0, spaceind); } jTextField2.setText(s); // Process name } } private final class SelectionHandler implements ListSelectionListener { @Override public void valueChanged(ListSelectionEvent evt) { updateTextFields(); } } /** Refresh Action handler */ private final class RefreshActionHandler implements ActionListener { @Override public void actionPerformed(final ActionEvent event) { processID = jTextField1.getText(); update(); } } /** * "Choose Experiment Directory" action handler Call file chooser and update Experiment Directory */ private final class ExpDirActionHandler implements ActionListener { AnChooser ac = null; String dir = null; @Override public void actionPerformed(final ActionEvent event) { String title = AnLocale.getString("Experiment Directory"); if (null == ac) { ac = anWindow.getAnChooser(title, AnChooser.DIR_CHOOSER, dir); } if ((ac.showOpenDialog(workPanel) == AnChooser.APPROVE_OPTION) && ((ac.getSelectedFile()) != null)) { dir = ac.getSelectedFile().getAbsolutePath(); setExperimentDirectory(dir); } } } /** "Choose Experiment Group" action handler Call file chooser and update Experiment Group */ private final class ExpGroupActionHandler implements ActionListener { AnChooser ac = null; String dir = null; @Override public void actionPerformed(final ActionEvent event) { String title = AnLocale.getString("Experiment Group"); if (null == ac) { ac = anWindow.getAnChooser(title, AnChooser.EXP_GROUP_CHOOSER, dir); } if ((ac.showOpenDialog(workPanel) == AnChooser.APPROVE_OPTION) && ((ac.getSelectedFile()) != null)) { dir = ac.getSelectedFile().getParent(); String group = ac.getSelectedFile().getName(); setExperimentGroup(group); } } } /* * Generic action for context menu items. * Action name is passed as String. */ class UpdateAction extends AbstractAction { String actionName = null; public UpdateAction(String name) { super(name); this.actionName = name; } public UpdateAction(String name, String actionName) { super(name); this.actionName = actionName; } @Override public void actionPerformed(ActionEvent ev) { // Use AWT thread to perform some actions if (actionName.equals(STR_ACTION_UPDATE)) { update(); return; } if (actionName.equals(STR_ACTION_COPY_ALL)) { copyAll(); return; } // if (actionName.startsWith(STR_ACTION_SORTBY)) { for (int i = 0; i < tableColumns.length; i++) { if (actionName.contains(tableColumns[i])) { processesTable.getRowSorter().toggleSortOrder(i); return; } } // } } } private JPopupMenu initPopup(JTable table) { AccessibleContext ac; JMenuItem mi; JPopupMenu popup = new JPopupMenu(); String txt; boolean row_selected = false; int row = table.getSelectedRow(); if (row >= 0) { row_selected = true; } // Add "Update List of Processes" action txt = STR_ACTION_UPDATE; mi = new JMenuItem(new UpdateAction(txt)); mi.setMnemonic(AnLocale.getString('R', "MN_PROFILE_PROCESS_Refresh_MENU_ITEM")); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); // String hotkey = "CTRL_R"; // KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK, // false); // table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, hotkey); // UpdateAction act = new UpdateAction(txt); // table.getActionMap().put(hotkey, act); // mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.CTRL_MASK)); mi.setEnabled(true); popup.add(mi); // Add "Set Metric" action txt = STR_ACTION_SORTBY; UpdateAction sm = new UpdateAction(txt); mi = new JMenuItem(sm); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (tableColumns.length <= 1) { mi.setEnabled(false); popup.add(mi); } else { JMenu submenu1; submenu1 = new JMenu(txt); for (int i = 0; i < tableColumns.length; i++) { txt = tableColumns[i]; sm = new UpdateAction(txt); mi = new JMenuItem(sm); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(STR_ACTION_SORTBY + ":" + txt); mi.setEnabled(true); submenu1.add(mi); } popup.add(submenu1); } // Add separator popup.addSeparator(); // Add menu item "Copy All" txt = STR_ACTION_COPY_ALL; UpdateAction cs = new UpdateAction(txt); mi = new JMenuItem(cs); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); popup.add(mi); return popup; } // ------- Private classes to implement popup menu items ------- // private class AnMenuListener extends MouseAdapter { private boolean debug; CollectPanel3 cp; JTable ptable; AnMenuListener(CollectPanel3 collectPanel, JTable table) { this.cp = collectPanel; this.ptable = table; debug = false; } // Experimental code, mostly "quick and dirty hack" public JPopupMenu initPopup(MouseEvent event) { return cp.initPopup(ptable); } /** Check for double click to performs default action */ @Override public void mouseClicked(final MouseEvent e) {} @Override public void mousePressed(MouseEvent e) { maybeShowPopup(e); } @Override public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { JPopupMenu popup = initPopup(e); if (popup != null) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeInvisible(" + e + ")"); } } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeVisible(" + e + ")"); } } public void popupMenuCanceled(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuCanceled(" + e + ")"); } } } // ================================= UNIT TESTING ===================================== // // For unit testing public static void main(final String[] args) { final int size; String str_args; if (args != null) { size = args.length; if (size > 0) { str_args = ""; for (int i = 1; i < size; i++) { if (i != 1) { str_args += " "; } str_args += args[i]; } } } CollectPanel3 cp = new CollectPanel3(null); cp.Test(cp); } public void Test(CollectPanel3 cp) { final JFrame mframe = new JFrame(); // CollectPanel2 cp = new CollectPanel2(); cp.jButton1.addActionListener(new ActionHandler()); // cp.jButton5.addActionListener(new ActionHandler()); // Preview JScrollPane work_pane = new JScrollPane(cp); work_pane.setMinimumSize(new Dimension(AnVariable.WIN_SIZE)); mframe.add(work_pane); processesTable.setColumnSelectionAllowed(false); processesTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); processesTable.getSelectionModel().addListSelectionListener(new SelectionHandler()); jTextField1.setText("25457"); refreshPS(processesTable); updateSelection(); processesTable.setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS); // jTable1.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN); processesTable.doLayout(); mframe.pack(); mframe.setVisible(true); } // Action handler private final class ActionHandler implements ActionListener { @Override public void actionPerformed(final ActionEvent event) { if (anWindow == null) { // TEST refreshPS(processesTable); } actionPerformed2(event); } } private static String[] ps = { "tester 25258 25257 14:46:37 0:00 /bin/bash", "tester 11582 893 Nov_20 0:00 /bin/sh /bin/firefox", "tester 4664 2140 Nov_28 0:00 vertool" }; static boolean resized = false; // Window handler private void refreshPS(JTable t) { int ps_index = 0; String filter = ""; if (null != jComboBox1.getSelectedItem()) { filter = jComboBox1.getSelectedItem().toString(); } for (int i = 0; i < t.getRowCount(); i++) { char space = ' '; String s1, s2, s3, s4, s5, s6; String s = ""; if ((i < ps.length) && (ps_index < ps.length)) { for (; ps_index < ps.length; ps_index++) { s1 = ps[ps_index]; if (filter.length() > 0) { // Apply filter if (s1.indexOf(filter) < 0) { continue; } } s = s1; ps_index++; break; } } if (s.length() <= 0) { t.setValueAt(s, i, 0); t.setValueAt(s, i, 1); t.setValueAt(s, i, 2); t.setValueAt(s, i, 3); t.setValueAt(s, i, 4); t.setValueAt(s, i, 5); continue; } int p1 = 0; int p2 = s.indexOf(space); // user name s1 = s.substring(p1, p2); t.setValueAt(s1, i, 0); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.indexOf(space, p1); // PID s2 = s.substring(p1, p2); t.setValueAt(s2, i, 1); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.indexOf(space, p1); // PPID s3 = s.substring(p1, p2); t.setValueAt(s3, i, 2); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.indexOf(space, p1); // Start time s4 = s.substring(p1, p2); t.setValueAt(s4, i, 3); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.indexOf(space, p1); // CPU time s5 = s.substring(p1, p2); t.setValueAt(s5, i, 4); while (s.charAt(p2) == space) { p2++; } p1 = p2; p2 = s.length(); // Command s6 = s.substring(p1, p2); t.setValueAt(s6, i, 5); } if (!resized) { resized = true; // Resize jTable1 TableColumnModel tcm = t.getColumnModel(); TableColumn tc = tcm.getColumn(0); int w = tc.getWidth(); tc.setPreferredWidth((w * 2) / 3); tc.setWidth((w * 2) / 3); tc = tcm.getColumn(1); w = tc.getWidth(); tc.setPreferredWidth(w / 2); tc.setWidth(w / 2); tc = tcm.getColumn(2); w = tc.getWidth(); tc.setPreferredWidth(w / 2); tc.setWidth(w / 2); tc = tcm.getColumn(3); w = tc.getWidth(); tc.setPreferredWidth(w / 2); tc.setWidth(w / 2); tc = tcm.getColumn(4); w = tc.getWidth(); tc.setPreferredWidth(w / 2); tc.setWidth(w / 2); tc = tcm.getColumn(5); w = tc.getWidth(); tc.setPreferredWidth(w * 4); tc.setWidth(w * 4); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/Collector.java���������������������������������������������0000644�0001750�0001750�00000107667�14517772113�020174� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.collect; import static java.lang.Thread.sleep; import org.gprofng.mpmt.AnFile; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintStream; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JTextArea; /** Wrapper class for standalone Collect Dialog. */ public class Collector { public static final int COLLECTING_RUNNING = 3; public static final int COLLECTING_PAUSED = 4; public static final int COLLECTING_TERMINATED = 5; public static final int COLLECTING_COMPLETED = 6; public static final int COLLECTING_NONE = 7; public static final int COLLECTING_TERMINATING = 8; // Collection types public static final int PROFILE_APPLICATION = 0; public static final int PROFILE_RUNNING_APPLICATION = 1; public static final int SYSTEM_PROFILING = 2; private String finaldir, curr_exp_name; private String experimentGroup; protected JPanel pioPanel; protected JTextArea pioTextArea; private AnWindow window; private ShellCommand shellCommand; private Collector collector; protected OutputStream logStream; protected BufferedWriter logStreamWriter; protected List logVector; protected List stderr_stdout; private int collectorState; protected List collectingStatusListenersList; private long elapsedTime = 0; private int exitValue = -1; private long processID = -1; private String errorMessage = null; private final String eol = "\n"; private final String empty_string = ""; private String collect_output; private int shortDelay = 10; // 10 milliseconds public long getElapsedTime() { return elapsedTime; } public long getProcessPID() { return processID; } public long setProcessPID(long p) { return processID = p; } public String getErrorMessage() { return errorMessage; } public void setErrorMessage(String m) { errorMessage = m; } public int getProcessExitValue() { return exitValue; } public void setActualExpName(String exp) { curr_exp_name = exp; } private int profiling_type = 0; // XXX Replace with a named const! /** * Constructor * * @param cprov - Interface for common methods (CollectDialog and CollectWindow) * @param buttons - Set of dialog buttons : {run, terminate, pause, sample, close} */ public Collector(final AnWindow aWindow) { this.window = aWindow; collector = this; collectorState = COLLECTING_NONE; collectingStatusListenersList = new ArrayList(); } /** Get Profiling Type */ public int getProfilingType() { return profiling_type; } /** Set Profiling Type */ public void setProfilingType(int profiling_type) { this.profiling_type = profiling_type; } public void addCollectingStatusListener(ActionListener al) { collectingStatusListenersList.add(al); } public void removeCollectingStatusListener(ActionListener al) { collectingStatusListenersList.remove(al); } private void fireCollectingStatusChanged(final int eventId) { // through all listeners for (Iterator it = collectingStatusListenersList.iterator(); it.hasNext(); ) { ((ActionListener) it.next()).actionPerformed(new ActionEvent(0, eventId, empty_string)); } } public int getCollectorState() { return collectorState; } public String getCollectOutput() { return collect_output; } private void setCollectorState(final int newSt) { collectorState = newSt; fireCollectingStatusChanged(collectorState); } public void setPioPanel(final JPanel aPioPanel) { this.pioPanel = aPioPanel; } public void setPioTextArea(final JTextArea aPioTextArea) { this.pioTextArea = aPioTextArea; } public void setLog(final OutputStream outLog) { logStream = outLog; logStreamWriter = new BufferedWriter(new OutputStreamWriter(logStream)); } public void setLog(final List outLog) { logVector = outLog; } public boolean pause(int signum) { if (sendSignal(signum, AnLocale.getString("Pause"))) { setCollectorState(COLLECTING_PAUSED); return true; } else { return false; } } public boolean resume(final int signum) { if (sendSignal(signum, AnLocale.getString("Resume"))) { setCollectorState(COLLECTING_RUNNING); return true; } else { return false; } } public boolean sample(final int signum) { return sendSignal(signum, AnLocale.getString("Sample")); } public boolean terminate_expt(boolean SIGINT) { int signal = 9; // SIGKILL if (SIGINT) { signal = 2; // SIGINT } if (sendSignal(signal, null)) { setCollectorState(COLLECTING_TERMINATING); return true; } return false; } public boolean checkWorkDir(final String work_dir_str) { if (work_dir_str.length() > 0) { AnFile curDir = window.getAnFile(work_dir_str); // IPC call if (curDir.exists()) { if (curDir.isDirectory()) { return true; } } } return false; } // Invoke collect command public void collect( final String target, final String exec_cmd, final String work_str, final String exp_name, final String exp_dir, final String env_vars, final String collect_output_file, final String experimentGroup) { final Thread worker; this.experimentGroup = experimentGroup; setProcessPID(-1); // Not started yet if (null == window.getAnalyzer().remoteConnection) { // checkWorkDir does not support remote yet if (!checkWorkDir(work_str)) { String err = AnLocale.getString("Collector error: cannot access working directory:\n" + work_str); AnUtility.showMessage(window.getFrame(), err, JOptionPane.ERROR_MESSAGE); return; } // Check experiment directory String full_exp_dir = exp_dir; boolean check_full_exp_dir = false; if (full_exp_dir == null) { full_exp_dir = empty_string; } else { full_exp_dir += "/"; } if (exp_name != null) { full_exp_dir += exp_name; } if (full_exp_dir != null) { if (full_exp_dir.endsWith(".er")) { int len = full_exp_dir.length(); for (int i = 4; i < len; i++) { // Is it an autoadjusted name? int c = full_exp_dir.charAt(len - i); if (('0' <= c) && (c <= '9')) { continue; } if (c == '.') { if (i > 4) { break; // autoadjusted name: "*.[0-9].er" } } check_full_exp_dir = true; // not of form "*.[0-9].er" break; } } } if (check_full_exp_dir && checkWorkDir(full_exp_dir)) { String err = AnLocale.getString( "Collector error: experiment directory already exists:\n" + full_exp_dir); AnUtility.showMessage(window.getFrame(), err, JOptionPane.ERROR_MESSAGE); return; } } curr_exp_name = exp_name; collect_output = empty_string; worker = new Thread("Collector Process Thread") { @Override public void run() { boolean collect_failed = false; try { stderr_stdout = new ArrayList(); AnUtility.setLibPath(); String remoteConnection = window.getAnalyzer().remoteConnection; String remoteShell = window.getAnalyzer().remoteShell; String remoteHost = window.getAnalyzer().remoteHost; String cmd = exec_cmd; String dir = work_str; // System.out.println("Collector: cmd = " + cmd); // DEBUG ShellCommand sc = new ShellCommand(); shellCommand = sc; sc.setRemoteConnection(remoteConnection, remoteShell, remoteHost); // try { // TEMPORARY if (null == remoteConnection) { sc.run(dir, cmd); } else { sc.runCmdStr(dir, cmd); } // } catch (Exception e) { // e.printStackTrace(); // // return/*(reply)*/; // collect_failed = true; // } setCollectorState(COLLECTING_RUNNING); final String STDIN_WRITER = "Collector Stdin Writer"; final String STDOUT_READER = "Collector Stdout Reader"; final String STDERR_READER = "Collector Stderr Reader"; // Create StreamThread STDIN_WRITER StreamThread tr0 = new StreamThread(); tr0.setName(STDIN_WRITER); tr0.setTask(tr0.WRITE_STDIN, sc); tr0.start(); // Create StreamThread STDOUT_READER StreamThread tr1 = new StreamThread(); tr1.setName(STDOUT_READER); tr1.setTask(tr1.READ_STDOUT, sc); if (logVector == null) { stderr_stdout = new ArrayList(); // NM1 } else { stderr_stdout = logVector; } tr1.setOut(stderr_stdout); tr1.start(); // Create StreamThread STDERR_READER StreamThread tr2 = new StreamThread(); tr2.setName(STDERR_READER); tr2.setTask(tr2.READ_STDERR, sc); // NM1 Vector stderr = new Vector(); tr2.setOut(stderr_stdout); tr2.start(); // Remote connection if (null != remoteConnection) { // ConnectionChooser cc = window.connect; // if (null == cc) { // System.err.println("Collector: ERROR: remote connection is not established // yet"); // } else { // cc.setVisible(true, window.getWindowID()); Analyzer parent_analyzer = Analyzer.getInstance(); try { parent_analyzer.startRemoteCollect(collector, null /*cc*/); } catch (Exception e) { sc.interrupt(); } // cc.setVisible(false, window.getWindowID()); // } } // Read standard output long time = System.currentTimeMillis(); if (logVector == null) { String line; // NM1 boolean shouldWait = false; while ((sc.isRunning() == true) || (stderr_stdout.size() > 0)) { // copy output to the log file try { // NM1 line = sc.readOutput(shouldWait); // NM1 if ((null != line) && (line.length() > 0)) { // NM1 writeln(line); // NM1 } else { // copy stderr_stdout to the log file while (stderr_stdout.size() > 0) { // NM1 line = stderr_stdout.get(0).toString(); stderr_stdout.remove(0); writeln(line); } // NM1 } } catch (Exception e) { // reply="# Exception: " + e; // Ignore exception } } // NM1 shouldWait = true; } elapsedTime = System.currentTimeMillis() - time; exitValue = sc.exitValue(); setCollectorState(COLLECTING_COMPLETED); // Remove collect output file if (collect_output_file != null) { // Remove local temporary file File f = new File(collect_output_file); if (f.exists()) { f.delete(); } } } catch (/*IO*/ Exception e) { collect_failed = true; // e.printStackTrace(); // printException(e, AnLocale.getString("Collector.collect: I/O exception 2")); // System.err.println("Collector.collect: command failed: " + exec_cmd); } if (collect_failed) { // Try to get error message ShellCommand sc = shellCommand; String err = AnLocale.getString("Collector command:\n\n" + exec_cmd + "\n\n"); writeln(err); boolean closed = false; String prev_line = null; while (!closed) { try { boolean shouldWait = true; // false; String line = sc.readError(shouldWait); if (null == line) { break; } if (line.length() > 0) { writeln(line); if (line.equals(prev_line)) { continue; // Sometimes identical line appear several times } else { prev_line = line; } if (line.contains("Run collect with no arguments for a usage message")) { continue; // Not useful a part of the error message } err += line + eol; } } catch (Exception e) { closed = true; break; } } setErrorMessage(err); // AnUtility.showMessage(window.getFrame(), err, JOptionPane.ERROR_MESSAGE); } shellCommand = null; } }; if (collect_output_file != null) { // Create thread to read collect output file Thread read_output_file = new Thread("Read Collector Output Thread") { public void run() { try { sleep(shortDelay); // sleep 10 milliseconds File f = new File(collect_output_file); while (f.exists()) { // open file, read, try to find process ID read_collect_output_file(collect_output_file); sleep(shortDelay); // sleep 10 milliseconds } } catch (/*IO*/ Exception e) { printException(e, AnLocale.getString("Collector.collect: I/O exception 3")); System.err.println("Collector.collect: cannot read file " + collect_output_file); } } }; read_output_file.start(); } worker.start(); } /** * Read Collect Output File * * @param collect_output_file */ protected void read_collect_output_file(String collect_output_file) { if (null == collect_output_file) { return; } try { File f = new File(collect_output_file); if (f == null) { return; } if (f.exists()) { // open file, read, try to find process ID String line; BufferedReader br = new BufferedReader(new FileReader(f)); while ((line = br.readLine()) != null) { if (line.length() > 0) { collect_output += line + eol; } String pattern1 = "Creating experiment directory "; int idx = line.indexOf(pattern1); if (idx >= 0) { String substr = line.substring(idx + pattern1.length()); idx = substr.indexOf(" "); if (idx > 1) { String expname = substr.substring(0, idx); // test.*.er setActualExpName(expname); } String pattern2 = "(Process ID: "; int n = line.indexOf(pattern2); if (n >= 0) { n += pattern2.length(); long p = 0; int d = 0; while ((d >= 0) && (d <= 9)) { p = p * 10 + d; d = line.charAt(n) - '0'; n++; } if (p > 0) { setProcessPID(p); return; } } } String pattern3 = "Target `"; if (line.startsWith(pattern3)) { String pattern31 = "' not found"; int n = line.indexOf(pattern31); if (n > 0) { setProcessPID((long) -2); setErrorMessage(line); return; } } String pattern4 = "Unable to create directory "; if (line.startsWith(pattern4)) { String pattern41 = " -- File exists"; int n = line.indexOf(pattern41); if (n > 0) { setProcessPID((long) -4); setErrorMessage(line); return; } } String pattern5 = "The HW counter configuration could not be loaded:"; if (line.startsWith(pattern5)) { setProcessPID((long) -3); setErrorMessage(line); return; } } // sleep(shortDelay); // sleep 10 milliseconds } } catch (/*IO*/ Exception e) { // e.printStackTrace(); printException(e, AnLocale.getString("Collector.collect: I/O exception 4")); System.err.println("Collector.collect: cannot read file " + collect_output_file); } } /** * Remove Temporary File * * @param temp_file_name */ protected void removeTempFile(final String temp_file_name) { if (temp_file_name != null) { try { // Remove temporary file File f = new File(temp_file_name); if (f.exists()) { f.delete(); } } catch (/*IO*/ Exception e) { // Ignore it } } } // Output protected void write(final String line) { try { logStreamWriter.write(line); logStreamWriter.flush(); // ?? logStream.flush(); } catch (IOException e) { // don't print "Read end dead" message printException(e, AnLocale.getString("Collector.write: I/O exception 5")); } } // Output with new line protected void writeln(final String line) { write(line + eol); } // Handle pause/resume signal private boolean sendSignal(final int signal, final String cmd) { if (processID < 2) { // Process lost String err = AnLocale.getString( "Error: cannot send signal. Process ID is not correct (" + processID + ")."); AnUtility.showMessage(window.getFrame(), err, JOptionPane.ERROR_MESSAGE); return false; } String result = sendSignal(processID, signal); if (null == result) { return true; } else { return false; } /* ShellCommand sc = new ShellCommand(); sc.setRemoteConnection(window.getAnalyzer().remoteConnection); String exe_cmd = "kill -" + signal + " " + processID; try { sc.run(exe_cmd); } catch (Exception e) { return false; } return true; */ } /** * Gets Current Process Output * * @return String output */ public String getCurrentOutput() { String output = empty_string; if (shellCommand != null) { output = shellCommand.output; } return output; } /** * Write one character to process input and flush * * @param s */ public void writeInputChar(char c) throws Exception { shellCommand.writeInputChar(c); } public boolean isProcRunning() { // terminate button is enabled return (getCollectorState() == COLLECTING_RUNNING); } private static void printException(final Exception e, final String annot_msg) { if (annot_msg != null) { System.err.println(annot_msg + ": " + e.getMessage()); } else { System.err.println(e.getMessage()); } } public String getActualExpName() { final String slash = "/"; if (curr_exp_name.startsWith(slash) || (null == finaldir)) { return curr_exp_name; } return (finaldir + slash + curr_exp_name); } public String getNextExpName() { return Collector.getExpName1(finaldir); } public String getExperimentGroup() { return experimentGroup; } /*------------------------------------- INNER CLASSES ----------------------------------------------------*/ /** * Class ShellCommand executes an external program and supports input/output functions * * <p>Main functions: run a program write to stdin read from stdout read from stderr return exit * status */ class ShellCommand { private BufferedReader processOutput; private BufferedReader processError; private PrintStream processInput; private Runtime rt; protected boolean interrupted; protected Process thisProcess; protected String shArgs; protected String errors; protected String output; protected String remoteConnection; protected String remoteShell; protected String remoteHost; // NM protected static ByteArrayOutputStream lastOutput; /** Creates a new instance of ShellCommand */ public ShellCommand() { processOutput = null; processError = null; thisProcess = null; rt = Runtime.getRuntime(); interrupted = false; remoteConnection = null; shArgs = null; errors = empty_string; output = empty_string; } /** * Set the remote connection * * @param args - connection */ public void setRemoteConnection(String rc, String rs, String rh) { remoteConnection = rc; remoteShell = rs; remoteHost = rh; } /** * Set the arguments * * @param args - arguments */ public void setShellArgs(String args) { shArgs = new String(args); } /** Interrupt and destroy the process */ public void interrupt() { interrupted = true; thisProcess.destroy(); thisProcess = null; } /** Return exit status */ public int exitValue() { if (interrupted) { return (-1); } try { thisProcess.waitFor(); } catch (Exception e) { return (-2); } return (thisProcess.exitValue()); } /** Check if the process is running */ public boolean isRunning() { try { int ev = thisProcess.exitValue(); } catch (IllegalThreadStateException ie) { return (true); } catch (Exception ie) { return (false); } return (false); } /** * Read from a stream * * @param reader - a stream */ private String readStream(BufferedReader reader) throws Exception { String ret = null; try { if (!reader.ready()) { int ev = thisProcess.exitValue(); ret = reader.readLine(); if (ret != null) { ret += eol; } return (ret); } ret = reader.readLine(); if (ret != null) { ret += eol; } } catch (IllegalThreadStateException ie) { return (empty_string); } return (ret); } /** * Gets Current Process Output * * @return String output */ public String getCurrentOutput() { return output; } /** * Read from standard output stream * * @param shouldWait - a flag (if true, wait while read is done) */ public String readOutput(boolean shouldWait) throws Exception { String ret; if (shouldWait) { ret = processOutput.readLine(); } else { ret = readStream(processOutput); } if (ret != null) { output += ret; } return (ret); } /** * Read from standard error stream * * @param shouldWait - a flag (if true, wait while read is done) */ public String readError(boolean shouldWait) throws Exception { String ret; if (shouldWait) { ret = processError.readLine(); } else { ret = readStream(processError); } return (ret); } /** * Write to standard input stream * * @param str - a message */ public void writeInput(String str) throws Exception { processInput.print(str); processInput.flush(); } /** * Write one character to standard input stream * * @param c - a character */ public void writeInputChar(char c) throws Exception { processInput.print(c); processInput.flush(); } /** * Run a program * * @param dirname - working directory * @param cmnd - command line */ public void run(String dirname, String cmnd) throws Exception { if (null != dirname) { cmnd = "cd " + dirname + " && " + cmnd; } run(cmnd); } /** * Run a program * * @param cmnd - command line */ public void run(String cmnd) throws Exception { String[] ss = new String[3]; if (null != remoteConnection) { ss[0] = remoteShell; ss[1] = remoteHost; cmnd = " ' " + cmnd + " '"; } else { ss[0] = "sh"; // NM ss[0] = "/bin/sh"; if (shArgs == null) { ss[1] = new String("-ec"); } else { ss[1] = new String(shArgs); } } // ss[2] = new String(cmnd + " 2>&1"); ss[2] = new String(cmnd); interrupted = false; try { // System.err.println("DEBUG:run rt.exec(): " + ss[0] + " " + ss[1] + " " + ss[2]); // DEBUG // (perf test) thisProcess = rt.exec(ss); InputStream os = thisProcess.getInputStream(); InputStream os_err = thisProcess.getErrorStream(); OutputStream is = thisProcess.getOutputStream(); processOutput = new BufferedReader(new InputStreamReader(os)); processError = new BufferedReader(new InputStreamReader(os_err)); processInput = new PrintStream(is, true); } catch (Exception ee) { String msg = "Command \"" + cmnd + "\" failed:\n" + ee.toString(); throw new Exception(msg); } } /** * Run a program * * @param cmnd - command line */ public void runCmdStr(String dir, String cmnd) throws Exception { String ss; if (null != remoteConnection) { ss = remoteConnection; if (dir != null) { ss += " /bin/sh -ec '( cd " + dir + " && " + cmnd + " )'"; } else { ss += " " + cmnd; } } else { ss = "sh"; // NM ss = "/bin/sh -ec"; if (shArgs == null) { ss += " -ec " + cmnd; } else { ss += " " + shArgs + " " + cmnd; } } interrupted = false; try { // System.err.println("DEBUG:runCmdStr rt.exec(): " + ss); // DEBUG (perf test) thisProcess = rt.exec(ss); InputStream os = thisProcess.getInputStream(); InputStream os_err = thisProcess.getErrorStream(); OutputStream is = thisProcess.getOutputStream(); processOutput = new BufferedReader(new InputStreamReader(os)); processError = new BufferedReader(new InputStreamReader(os_err)); processInput = new PrintStream(is, true); } catch (Exception ee) { String msg = "Command \"" + cmnd + "\" failed:\n" + ee.toString(); throw new Exception(msg); } } } /* End of class ShellCommand */ class StreamThread extends Thread { private ShellCommand sc = null; /* Tasks */ public final int WRITE_STDIN = 0; public final int READ_STDOUT = 1; public final int READ_STDERR = 2; public final int NO_TASK = -1; private int task = NO_TASK; /* Connection */ public final int DISCONNECTED = 0; public final int CONNECTED = 1; private int connect = DISCONNECTED; private long total_time = 0; private boolean tosleep = true; private boolean todie = false; private int shortDelay = 10; // 10 milliseconds private int mediumDelay = 100; // 100 milliseconds private int longDelay = 1000; // 1000 milliseconds (1 second) /** Creates a new instance of StreamThread */ public StreamThread() { long t = System.currentTimeMillis(); } public int setTask(final int TASK, ShellCommand sc) { task = TASK; // Q: check TASK ? this.sc = sc; return (task); } public int checkConnection() { return (connect); } public String writeInput(String request) { if (request == null) { return null; // Nothing to send } String reply = null; request = request + eol; logMessage(request); try { // log.severe("sc.writeInput("+request+");"); // FIXUP (remove) sc.writeInput(request); } catch (Exception e) { reply = "# Exception: " + e; // FIXUP (i18n) reportEvent(reply); } return (reply); } public int readOutput(boolean shouldWait) { String output; int len = 0; try { output = sc.readOutput(shouldWait); len = output.length(); if (len > 0) { reportEvent(output); } } catch (Exception e) { // reply="# Exception: " + e; // Ignore exception } return len; } public int readError(boolean shouldWait) { String output; int len = 0; try { output = sc.readError(shouldWait); len = output.length(); if (len > 0) { reportEvent(output); } } catch (Exception e) { // reply="# Exception: " + e; // Ignore exception } return len; } @Override public void run() { // String output; boolean shouldWait = false; /* Variables for time in milliseconds */ // long time0, time1, time2; // DEBUG (Performance test) // time0 = System.currentTimeMillis(); // time1 = time0; // time2 = time0; while (true) { if (sc != null) { if ( /*sc.isRunning()*/ task != NO_TASK) { connect = 1; if (task == WRITE_STDIN) { // NM writeInput(parent.getCommandToSend()); } int len = 0; if (task == READ_STDOUT) { len = readOutput(shouldWait); } if (task == READ_STDERR) { len = readError(shouldWait); } try { if (len <= 0) { // empty line if (!sc.isRunning()) { break; } } if ((len <= 0) // empty line || (task == WRITE_STDIN)) { // DEBUG (Windows) sleep(shortDelay); // a short delay } } catch (InterruptedException tie50) { // sleep 50 milliseconds } continue; // } else { // break; // stop task } // shouldWait = true; if (task == READ_STDOUT) { /* Try to read last messages */ readOutput(shouldWait); } if (task == READ_STDERR) { /* Try to read last messages */ readError(shouldWait); } } break; } // NM parent.reportProcessExited(); // time2 = System.currentTimeMillis(); // total_time = ((time2-time0)/1000); } private List out = null; // NM1 new Vector(); // private Boolean out_sync = true; // NM1 public void setOut(List out) { this.out = out; } private void reportEvent(String message) { // NM parent.reportEvent(message); if (null != out) { // NM1 // synchronized (out_sync) { // NM1 out.add(message); // } } } private void logMessage(String message) { // NM parent.logMessage(message); } } /* End of StreamThread */ /** * Sends signal to the process specified by process id * * @param pid Process ID * @param sig Signal number * @return result */ public static final String sendSignal(long pid, int sig) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("sendSignal"); anWindow.IPC().send(pid); anWindow.IPC().send(sig); return anWindow.IPC().recvString(); } } /** * Get experimentsDisp name specified by directory name * * @param dir_name * @return result */ public static String getExpName1(final String dir_name) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getExpName1"); anWindow.IPC().send(dir_name); return anWindow.IPC().recvString(); } } /** * A generic method to get Available Collector Options. * * @param collectorOptions - array of arrays of Strings * @return availableCollectorOptions - array of arrays of Strings */ public static Object[] getAvailableCollectorOptions(final Object[] collectorOptions) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getAvailableCollectorOptions"); anWindow.IPC().send(0); anWindow.IPC().send(collectorOptions); return (Object[]) anWindow.IPC().recvObject(); } } /** * A method to get list of running processes. * * @param format - format of output, e.g. "/bin/ps -ef" * @return String - list of processes */ public static String getRunningProcesses(final String format) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getRunningProcesses"); anWindow.IPC().send(format); return anWindow.IPC().recvString(); } } /** * A method to get OS family. * * @return String - OS family, e.g. "Solaris" or "Linux" */ public static String getOSFamily() { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getOSFamily"); return anWindow.IPC().recvString(); } } /** * A generic method to get Collector control value. * * @param control - String * @return value - String */ public static String getCollectorControlValue(final String control) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getCollectorControlValue"); anWindow.IPC().send(0); anWindow.IPC().send(control); return anWindow.IPC().recvString(); } } /** * A generic method to set Collector control value. * * @param control - String * @param value - String * @return result - String */ public static String setCollectorControlValue(final String control, final String value) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { AnUtility.checkIPCOnWrongThread(false); anWindow.IPC().send("setCollectorControlValue"); anWindow.IPC().send(0); anWindow.IPC().send(control); anWindow.IPC().send(value); String s = anWindow.IPC().recvString(); AnUtility.checkIPCOnWrongThread(true); return s; } } /** * A generic method to unset Collector control value (restore the default value). * * @param control - String * @return result - String */ public static String unsetCollectorControlValue(final String control) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { AnUtility.checkIPCOnWrongThread(false); anWindow.IPC().send("unsetCollectorControlValue"); anWindow.IPC().send(0); anWindow.IPC().send(control); String s = anWindow.IPC().recvString(); AnUtility.checkIPCOnWrongThread(true); return s; } } } �������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectUtility.java����������������������������������������0000644�0001750�0001750�00000040154�14517772113�021202� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.collect; import org.gprofng.analyzer.AnEnvironment; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.Insets; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import javax.accessibility.AccessibleContext; import javax.swing.BoundedRangeModel; import javax.swing.BoxLayout; import javax.swing.ComboBoxEditor; import javax.swing.DefaultListCellRenderer; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; public final class CollectUtility { private static final int TEXT_LEFT = 1; // public final static int TEXT_CENTER = 2; public static final int TEXT_RIGHT = 3; public static final Font text_font; public static final Color text_color; private static final Color LABEL_COLOR = Color.black; private static final int sizeLabel = 4; private static final Border labelBorder = new EmptyBorder(0, sizeLabel, 0, sizeLabel); public static final Insets buttonMargin = new Insets(1, 1, 1, 1); static { Font org_font = UIManager.getDefaults().getFont("TextField.font"); text_font = new Font("Monospaced", org_font.getStyle(), org_font.getSize()); if (AnEnvironment.isLFNimbus()) { text_color = AnEnvironment.NIMBUS_TEXT_BACKGROUND; } else { text_color = new Color(UIManager.getDefaults().getColor("TextArea.background").getRGB()); } } protected static final class CLabel extends JLabel { public CLabel(final String text, final int alignment) { super(text, alignment); final float falignment; if (alignment == RIGHT) { falignment = RIGHT_ALIGNMENT; } else if (alignment == LEFT) { falignment = LEFT_ALIGNMENT; } else { falignment = CENTER_ALIGNMENT; } setAlignmentX(falignment); setForeground(LABEL_COLOR); setBorder(labelBorder); } } protected static final class CList extends JPanel { private final boolean resizable; private final JPanel label, value; // Constructor public CList(final boolean resizable) { this.resizable = resizable; label = new JPanel(); label.setLayout(new BoxLayout(label, BoxLayout.Y_AXIS)); value = new JPanel(); value.setLayout(new BoxLayout(value, BoxLayout.Y_AXIS)); if (resizable) { setLayout(new BorderLayout()); add(label, BorderLayout.WEST); add(value, BorderLayout.CENTER); } else { add(label); add(value); } } // Add label public JComponent addLabel(final JComponent item) { return (JComponent) label.add((item != null) ? item : new JPanel()); } // Add value public JComponent addValue(final JComponent item) { return (JComponent) value.add((item != null) ? item : new JPanel()); } // Add label and value public void add(final JComponent litem, final JComponent vitem) { setAlignmentY(addLabel(litem), addValue(vitem)); } // Align labels and values vertically public void setAlignmentY(final JComponent litem, final JComponent vitem) { final Dimension lsize, vsize; Dimension msize; lsize = new Dimension(litem.getPreferredSize()); vsize = new Dimension(vitem.getPreferredSize()); if (lsize.height < vsize.height) { lsize.height = vsize.height; } else { vsize.height = lsize.height; } // Set labels size if (resizable) { msize = litem.getMaximumSize(); msize.height = lsize.height; litem.setMaximumSize(msize); } else { litem.setMaximumSize(new Dimension(lsize)); } litem.setMinimumSize(new Dimension(lsize)); litem.setPreferredSize(new Dimension(lsize)); // Set values size if (resizable) { msize = vitem.getMaximumSize(); msize.height = vsize.height; vitem.setMaximumSize(msize); } else { vitem.setMaximumSize(new Dimension(vsize)); } vitem.setMinimumSize(new Dimension(vsize)); vitem.setPreferredSize(new Dimension(vsize)); } // Align Labels and Values vertically public void setAlignmentY() { final Component[] labels = label.getComponents(); final Component[] values = value.getComponents(); final int size = Math.min(labels.length, values.length); for (int i = 0; i < size; i++) { setAlignmentY((JComponent) labels[i], (JComponent) values[i]); } } // Align items horizontally public void setAlignmentX(final Component[] items) { final int size; int width, max_width; Dimension psize; size = items.length; max_width = 0; for (int i = 0; i < size; i++) { width = items[i].getPreferredSize().width; if (max_width < width) { max_width = width; } } for (int i = 0; i < size; i++) { psize = items[i].getPreferredSize(); psize.width = max_width; ((JComponent) items[i]).setPreferredSize(psize); } } // Align the Values only horizontally, usually the Labels does not need // further alignment public void setAlignmentX() { setAlignmentX(value.getComponents()); } // Clean up @Override public void removeAll() { label.removeAll(); value.removeAll(); } } // General textfield protected static class CText extends JTextField { int text_align; public CText(final String text, final int columns, final int alignment) { super(text, columns); text_align = TEXT_LEFT; setFont(text_font); setBackground(text_color); setEditable(false); setHorizontalAlignment(alignment); setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); setCaret( new javax.swing.text.DefaultCaret() { public void focusGained(final FocusEvent event) { if (getComponent().isEnabled()) { setVisible(true); } setSelectionVisible(true); // Don't use selectAll which will move Caret to the end. if (text_align == TEXT_LEFT) { setDot(getDocument().getLength()); moveDot(0); } else { // Same code as selectAll setDot(0); moveDot(getDocument().getLength()); } } public void focusLost(final FocusEvent event) { super.focusLost(event); setDot(text_align == TEXT_LEFT ? 0 : getDocument().getLength()); } }); } public final void setVisibleAlign(final int text_align, final boolean delay) { final BoundedRangeModel visibility; this.text_align = text_align; if (delay) { setCaretPosition(text_align == TEXT_LEFT ? 0 : getDocument().getLength()); } else { // Don't use setCaretPosition which caused flash visibility = getHorizontalVisibility(); visibility.setValue( text_align == TEXT_LEFT ? visibility.getMinimum() : visibility.getMaximum()); } } } protected static class AnComboBox extends JComboBox implements ActionListener { public static final int COMBO_TEXT = 0; public static final int COMBO_ITEM = 1; private AnComboBox.ComboObj current_obj; private final int width; public AnComboBox(final int width) { current_obj = null; this.width = width; setRenderer(new AnComboBox.AnComboRenderer()); setEditor(new AnComboBox.AnComboEditor()); setEditable(true); // setBorder(new EtchedBorder(EtchedBorder.LOWERED)); setBorder(new LineBorder(new Color(150, 150, 150), 1)); // setBorder(null); } public AnComboBox() { this(14); // default width } // Add item public final void add( final int type, final String header, final String str, final boolean changable) { addItem(new AnComboBox.ComboObj(type, false, header, str, changable)); } public final void setText(final String str) { final AnComboBox.ComboObj obj = (AnComboBox.ComboObj) getEditor().getEditorComponent(); if (obj.getType() == COMBO_TEXT) { obj.setText(str); if (current_obj.changable) { current_obj.setText(str); } } } // Get result public final String getText() { final AnComboBox.ComboObj obj = (AnComboBox.ComboObj) getEditor().getEditorComponent(); if (obj.getType() == COMBO_ITEM) { return null; } return obj.getText(); } // Get header text public final String getHeader() { final AnComboBox.ComboObj obj = (AnComboBox.ComboObj) getEditor().getEditorComponent(); return obj.getHeader(); } // Get editor's editable textfield public final Component getEditorText() { return ((AnComboBox.ComboObj) getEditor().getEditorComponent()).getTextField(); } // Get location of the Editor's textfield public final Point getEditorLocation() { return ((AnComboBox.AnComboEditor) getEditor()).getTextLocation(); } // Enter in the textfield public final void actionPerformed(final ActionEvent event) { final Object src = event.getSource(); if (src instanceof JTextField) { current_obj.setText(((JTextField) src).getText()); } } // Internal data object private final class ComboObj extends JPanel { private final boolean editor, changable; private int type; private String header; private final JLabel label; private final JTextField text; public ComboObj( final int type, final boolean editor, final String header, final String str, final boolean changable) { final BoxLayout layout; this.editor = editor; this.type = type; this.header = header; this.changable = changable; setLayout(layout = new BoxLayout(this, BoxLayout.X_AXIS)); setBorder(new EmptyBorder(0, 1, 0, 0)); label = new CLabel(header, JLabel.LEFT); label.setFont(label.getFont().deriveFont(Font.PLAIN)); final AccessibleContext context = label.getAccessibleContext(); context.setAccessibleName(header); context.setAccessibleDescription(header); text = new JTextField((type == COMBO_TEXT) ? width : 0); text.setFont(text_font); text.setBorder(null); this.add(label); this.add(text); setText(str); layout.layoutContainer(this); } public final int getType() { return type; } public final void setType(final int type) { this.type = type; } public final String getHeader() { return header; } public final void setHeader(final String header) { this.header = header; label.setText(header); } public final String getText() { return text.getText(); } public final void setText(final String str) { text.setText(str); text.setEditable(editor && (type == COMBO_TEXT)); } public final JTextField getTextField() { return text; } public final void selectAll() { text.selectAll(); text.requestFocus(); } public void addActionListener(final ActionListener l) { text.addActionListener(l); } public final void removeActionListener(final ActionListener l) { text.removeActionListener(l); } // Set background @Override public final void setBackground(final Color bg) { super.setBackground(bg); if (text != null) { text.setBackground(bg); } if (label != null) { label.setBackground(bg); } } // Set foreground @Override public final void setForeground(final Color fg) { super.setForeground(fg); if (text != null) { text.setForeground(fg); } if (label != null) { label.setForeground(fg); } } } // Renderer for AnCombo private final class AnComboRenderer extends DefaultListCellRenderer { @Override public final Component getListCellRendererComponent( final JList list, final Object value, final int index, final boolean isSelected, final boolean cellHasFocus) { final AnComboBox.ComboObj obj = (AnComboBox.ComboObj) value; if (isSelected) { obj.setBackground(list.getSelectionBackground()); obj.setForeground(list.getSelectionForeground()); } else { obj.setBackground(list.getBackground()); obj.setForeground(list.getForeground()); } return obj; } } // Editor for AnCombo private final class AnComboEditor implements ComboBoxEditor, FocusListener { private final AnComboBox.ComboObj editor; private final JTextField text; public AnComboEditor() { editor = new AnComboBox.ComboObj(COMBO_TEXT, true, "", "", true); editor.setBorder(null); text = editor.getTextField(); text.addFocusListener(this); } // Return the component @Override public Component getEditorComponent() { return editor; } // Set the item that should be edited. @Override public void setItem(final Object anObject) { final AnComboBox.ComboObj obj = (AnComboBox.ComboObj) anObject; final int type; if (obj != null) { current_obj = obj; type = obj.getType(); if (type == COMBO_TEXT) { text.requestFocus(); } editor.setType(type); editor.setHeader(obj.getHeader()); editor.setText(obj.getText()); } } // Return the edited item @Override public Object getItem() { return editor; } // Get location of the textfield public Point getTextLocation() { return text.getLocationOnScreen(); } // Ask the editor to start editing and to select everything @Override public void selectAll() { editor.selectAll(); } // Add an ActionListener. An action event is generated when the edited // item changes @Override public void addActionListener(final ActionListener l) { editor.addActionListener(l); } // Remove an ActionListener @Override public void removeActionListener(final ActionListener l) { editor.removeActionListener(l); } // Lost focus @Override public void focusLost(final FocusEvent event) { if (event.isTemporary()) { return; } if (current_obj.changable) { current_obj.setText(text.getText()); } else { text.setText(current_obj.getText()); } } // Gain focus @Override public void focusGained(final FocusEvent event) {} } } protected interface Browseable { public void setValue(String path); public String getValue(); } protected static JComponent getItem(final String text) { return new CLabel(text, JLabel.RIGHT); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/CollectPanel3.form�����������������������������������������0000644�0001750�0001750�00000051717�14517772113�020712� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.6" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,2,108,0,0,5,-53"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Container class="javax.swing.JPanel" name="jPanel2"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="12" insetsBottom="0" insetsRight="12" anchor="10" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="jLabel2"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="processesTable"/> </Property> <Property name="text" type="java.lang.String" value="Select the Process to profile"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel1"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jComboBox1"/> </Property> <Property name="text" type="java.lang.String" value="Filter:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="jComboBox1"> <Properties> <Property name="editable" type="boolean" value="true"/> <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> <StringArray count="1"> <StringItem index="0" value=" "/> </StringArray> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="jButton1"> <Properties> <Property name="text" type="java.lang.String" value="Refresh"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JScrollPane" name="jScrollPane2"> <AuxValues> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="4" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <SubComponents> <Component class="javax.swing.JTable" name="processesTable"> <Properties> <Property name="autoCreateRowSorter" type="boolean" value="true"/> <Property name="model" type="javax.swing.table.TableModel" editor="org.netbeans.modules.form.editors2.TableModelEditor"> <Table columnCount="6" rowCount="24"> <Column editable="false" title="User Name" type="java.lang.String"/> <Column editable="false" title="PID" type="java.lang.String"/> <Column editable="false" title="PPID" type="java.lang.String"/> <Column editable="false" title="Start Time" type="java.lang.String"/> <Column editable="false" title="CPU time" type="java.lang.String"/> <Column editable="false" title="Command" type="java.lang.String"/> </Table> </Property> <Property name="toolTipText" type="java.lang.String" value="Select the process to profile"/> <Property name="autoResizeMode" type="int" value="4"/> <Property name="columnModel" type="javax.swing.table.TableColumnModel" editor="org.netbeans.modules.form.editors2.TableColumnModelEditor"> <TableColumnModel selectionModel="1"> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> <Column maxWidth="-1" minWidth="-1" prefWidth="-1" resizable="true"> <Title/> <Editor/> <Renderer/> </Column> </TableColumnModel> </Property> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[32768, 32768]"/> </Property> <Property name="selectionModel" type="javax.swing.ListSelectionModel" editor="org.netbeans.modules.form.editors2.JTableSelectionModelEditor"> <JTableSelectionModel selectionMode="0"/> </Property> <Property name="tableHeader" type="javax.swing.table.JTableHeader" editor="org.netbeans.modules.form.editors2.JTableHeaderEditor"> <TableHeader reorderingAllowed="true" resizingAllowed="true"/> </Property> </Properties> </Component> </SubComponents> </Container> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="jPanel3"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="12" insetsBottom="12" insetsRight="12" anchor="15" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JTextField" name="jTextField1"> <Properties> <Property name="columns" type="int" value="20"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel3"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jTextField1"/> </Property> <Property name="text" type="java.lang.String" value="Target PID:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="jComboBox2"> <Properties> <Property name="editable" type="boolean" value="true"/> <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> <StringArray count="1"> <StringItem index="0" value="ktest.1.er"/> </StringArray> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="1" gridWidth="4" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel4"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jComboBox2"/> </Property> <Property name="text" type="java.lang.String" value="Experiment Name:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="jComboBox3"> <Properties> <Property name="editable" type="boolean" value="true"/> <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> <StringArray count="1"> <StringItem index="0" value=" "/> </StringArray> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="2" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel5"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jComboBox3"/> </Property> <Property name="text" type="java.lang.String" value="Experiment Directory:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="jComboBox4"> <Properties> <Property name="editable" type="boolean" value="true"/> <Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.editors2.ComboBoxModelEditor"> <StringArray count="1"> <StringItem index="0" value=" "/> </StringArray> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="3" gridWidth="3" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel6"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jComboBox4"/> </Property> <Property name="text" type="java.lang.String" value="Experiment Group:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="jTextField2"> <Properties> <Property name="editable" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="3" gridY="0" gridWidth="4" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="jLabel7"> <Properties> <Property name="labelFor" type="java.awt.Component" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="jTextField2"/> </Property> <Property name="text" type="java.lang.String" value="Target Name:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="8" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="jButton2"> <Properties> <Property name="text" type="java.lang.String" value="..."/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="5" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="jButton6"> <Properties> <Property name="text" type="java.lang.String" value="..."/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="5" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="13" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> </SubComponents> </Form> �������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/HWCEntry.java����������������������������������������������0000644�0001750�0001750�00000015616�14517772113�017701� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.collect; import org.gprofng.mpmt.AnLocale; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; public class HWCEntry { private int no; // Just an entry counter private final boolean set; // Is a set ('default', ...) private final String i18n; // some printable string, does not include short_desc text private final String name; // alias name, or raw hwc name private final String intName; // hwc specification private final String metric; // very short description for std ctrs (aliases) private final long val; // default overflow rate private final int timecvt; // 0:not cycles. !=0:cycles that can be converted to time private final int memop; // hwcentry.h enum describing capabilities (like memspace) private final String shortDesc; // one-liner describing counter (or null) private final int[] regList; // which registers support this counter private final boolean supportsAttrs; // supports attributes private final boolean supportsMemspace; // supports memoryspace profiling private final boolean recommended; // Recommended (std) counter private String collectorString; HWCEntry( boolean set, String i18n, String name, String intName, String metric, long val, int timecvt, int memop, String shortDesc, int[] regList, boolean supportsAttrs, boolean supportsMemspace, boolean recommended) { this.set = set; this.i18n = i18n; this.name = name; this.intName = intName; this.metric = metric; this.val = val; this.timecvt = timecvt; this.memop = memop; this.shortDesc = shortDesc; this.regList = regList; this.supportsAttrs = supportsAttrs; this.supportsMemspace = supportsMemspace; this.recommended = recommended; collectorString = null; } public HWCEntry copy() { int[] regListDeepCopy = null; if (regList != null) { regListDeepCopy = new int[regList.length]; for (int i = 0; i < regList.length; i++) { regListDeepCopy[i] = regList[i]; } } HWCEntry copy = new HWCEntry( set, i18n, name, intName, metric, val, timecvt, memop, shortDesc, regListDeepCopy, supportsAttrs, supportsMemspace, recommended); copy.setNo(no); copy.setCollectorString(collectorString); return copy; } public String getI18n() { return i18n; } public String getName() { return name; } public String getIntName() { return intName; } public String getMetric() { return metric; } public long getVal() { return val; } public int getTimecvt() { return timecvt; } public int getMemop() { return memop; } public String getShortDesc() { return shortDesc; } public int[] getRegList() { return regList; } public boolean supportsAttrs() { return supportsAttrs; } public boolean supportsMemspace(Map<String, HWCEntry> hwcNameMap) { if (!isSet() || hwcNameMap == null) { return supportsMemspace; } else { boolean supportsMemspace = false; List<String> setNames = getSetNames(); for (String name : setNames) { HWCEntry entry = hwcNameMap.get(name); if (entry != null) { if (entry.supportsMemspace(hwcNameMap)) { supportsMemspace = true; break; } } } return supportsMemspace; } } public boolean isRecommended() { return recommended; } public boolean supportsTime(Map<String, HWCEntry> hwcNameMap) { if (!isSet() || hwcNameMap == null) { return timecvt != 0; } else { boolean supportsTime = false; List<String> setNames = getSetNames(); for (String name : setNames) { HWCEntry entry = hwcNameMap.get(name); if (entry != null) { if (entry.supportsTime(hwcNameMap)) { supportsTime = true; break; } } } return supportsTime; } } public boolean isRaw() { return !isRecommended(); } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public boolean isSet() { return set; } public List<String> getSetNames() { List<String> list = new ArrayList<String>(); if (isSet()) { // Parse String[] names = getIntName().split(",,"); int index = 0; for (String name : names) { if (name.startsWith("+")) { names[index] = name.substring(1); } index++; } list = Arrays.asList(names); } return list; } @Override public String toString() { return getI18n() + " [" + getCollectorString() + "]"; } /** * @return the string (including attributes, ...) used by collector */ public String getCollectorString() { if (collectorString != null) { return collectorString; } else { return name; } } public void setCollectorString(String collectorString) { this.collectorString = collectorString; } public String getMetricText() { if (isSet()) { return AnLocale.getString("Default Set"); } if (isRecommended()) { return getI18n(); } if (isRaw()) { return getI18n(); } return "???"; } public String getCounterText() { if (isSet()) { return getIntName(); } if (isRecommended()) { String format = "%s [%s]"; return String.format(format, getName(), getIntName()); } if (isRaw()) { return getName(); } return "???"; } public String getDescriptionText(Map<String, HWCEntry> hwcNameMap) { if (isSet()) { return AnLocale.getString("Default set of counters"); } if (isRecommended()) { if (getShortDesc() != null) { return getShortDesc(); } else { HWCEntry mappedEntry = hwcNameMap.get(getIntName()); if (mappedEntry != null && mappedEntry.getShortDesc() != null) { return mappedEntry.getShortDesc(); } else { return getI18n(); } } } if (isRaw()) { return getShortDesc() != null ? getShortDesc() : ""; } return "???"; } } ������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/collect/HWCSelectPanel.form����������������������������������������0000644�0001750�0001750�00000037066�14517772113�021024� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="infoLabel"> <Properties> <Property name="text" type="java.lang.String" value="info..."/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="filterPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="23" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="filterLabel"> <Properties> <Property name="text" type="java.lang.String" value="Filter"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="6" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="checkBoxPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="recommendedIconLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JCheckBox" name="recommendedCheckBox"> <Properties> <Property name="text" type="java.lang.String" value="Recommended"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="recommendedCheckBoxActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="1" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="timeIconLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JCheckBox" name="timeCheckBox"> <Properties> <Property name="text" type="java.lang.String" value="Time"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="timeCheckBoxActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="memoryIconLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JCheckBox" name="memoryCheckBox"> <Properties> <Property name="text" type="java.lang.String" value="Memory"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="memoryCheckBoxActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> <Component class="javax.swing.JLabel" name="includeLabel"> <Properties> <Property name="text" type="java.lang.String" value="Include"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="4" insetsBottom="4" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="includeComboBox"> <Properties> <Property name="editable" type="boolean" value="true"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="4" insetsBottom="4" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="excludeLabel"> <Properties> <Property name="text" type="java.lang.String" value="and exclude"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="8" insetsBottom="4" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="excludeComboBox"> <Properties> <Property name="editable" type="boolean" value="true"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="3" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="4" insetsBottom="4" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="refreshButton"> <Properties> <Property name="text" type="java.lang.String" value="Refresh"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="4" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="8" insetsBottom="4" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="listLabelPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="listLabel"> <Properties> <Property name="text" type="java.lang.String" value="Available Counters:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="maxListLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="0" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="tablePanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="4" gridWidth="3" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Container> </SubComponents> </Form> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/�������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�015121� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/ExclusiveOrInclusivePanel.java�������������������������������0000644�0001750�0001750�00000011430�14517772113�023000� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import org.gprofng.mpmt.AnTable; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.ArrayList; import java.util.List; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.TransferHandler; public class ExclusiveOrInclusivePanel extends JPanel { private MetricPanel metricPanel; private String labelText; private AttributePanel[] attributepanels; public ExclusiveOrInclusivePanel( MetricPanel metricPanel, AnTable anTable, final MetricLabel[] metricLabels, String labelText, ImageIcon imageIcon, String tooltip, int column, int count, HeaderMouseHandler headerMouseHandler) { // System.out.println(txt + " " + index + " " + count); this.metricPanel = metricPanel; this.labelText = labelText; setLayout(new GridBagLayout()); setOpaque(false); setToolTipText(tooltip); addMouseListener(headerMouseHandler); addMouseMotionListener(headerMouseHandler); // What label JLabel whatLabel = new JLabel(labelText); AnUtility.setAccessibleContext(whatLabel.getAccessibleContext(), whatLabel.getText()); whatLabel.setFont(AnTableHeaderPanel.verySmallFont); if (imageIcon != null) { whatLabel.setIcon(imageIcon); } GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(0, 2, 0, 2); gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; add(whatLabel, gridBagConstraints); // Attribute panel JPanel attributePanelOuter = new JPanel(new GridBagLayout()); attributePanelOuter.setOpaque(false); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(attributePanelOuter, gridBagConstraints); attributepanels = new AttributePanel[count]; int gridX = 0; for (int i = 0; i < count; i++) { AttributePanel attributePanel = new AttributePanel( metricPanel, anTable, metricLabels, this, column + i, headerMouseHandler, tooltip); attributepanels[i] = attributePanel; gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX++; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(1, 0, 0, 0); attributePanelOuter.add(attributePanel, gridBagConstraints); } // DnD addMouseMotionListener(new MouseDraggedListener()); } class MouseDraggedListener extends MouseMotionAdapter { @Override public void mouseDragged(MouseEvent e) { JComponent c = (JComponent) e.getSource(); ExclusiveOrInclusivePanel exclusiveOrInclusivePanel = (ExclusiveOrInclusivePanel) c; MetricPanel metricPanel = exclusiveOrInclusivePanel.getMetricPanel(); TransferHandler handler = metricPanel.getTransferHandler(); handler.exportAsDrag(metricPanel, e, TransferHandler.COPY); } } public MetricPanel getMetricPanel() { return metricPanel; } public String getLabelText() { return labelText; } protected AttributePanel findAttributePanel(int x) { int start = 0; for (int i = 0; i < attributepanels.length; i++) { if (x >= start && x <= start + attributepanels[i].getSize().width) { return attributepanels[i]; } start += attributepanels[i].getSize().width; } return null; } List<JMenuItem> getSortByMenuItems() { List<JMenuItem> list = new ArrayList<JMenuItem>(); for (AttributePanel attributepanel : attributepanels) { list.add(attributepanel.getSortByMenuItem()); } return list; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/HeaderMouseHandler.java��������������������������������������0000644�0001750�0001750�00000007310�14517772113�021367� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public final class HeaderMouseHandler extends MouseAdapter { private MetricPanel metricPanel; private AttributePanel mouseOverAttributePanel = null; public HeaderMouseHandler(MetricPanel metricPanel) { this.metricPanel = metricPanel; } @Override public void mouseEntered(MouseEvent e) { // System.out.println("mouseEntered " + e.getComponent()); metricPanel.mouseEntered(e); } @Override public void mouseExited(MouseEvent e) { // System.out.println("mouseExited " + e.getComponent()); metricPanel.mouseExited(e); if (mouseOverAttributePanel != null) { mouseOverAttributePanel.mouseExited(null); mouseOverAttributePanel = null; } } @Override public void mouseClicked(MouseEvent e) { // System.out.println("mouseClicked " + " " + e.getX() + " " + e.getComponent()); if (e.getButton() == MouseEvent.BUTTON3) { metricPanel.showPopup(e); } else { AttributePanel attributePanel = findAttributePanel(e); // System.out.println(attributePanel != null ? attributePanel.column : "-"); if (attributePanel != null) { attributePanel.mouseClicked(null); } } } @Override public void mouseMoved(MouseEvent e) { // System.out.println("mouseMoved " + " " + e.getX() + " " + e.getComponent()); AttributePanel attributePanel = findAttributePanel(e); // System.out.println(attributePanel != null ? attributePanel.column : "-"); if (attributePanel != null) { if (attributePanel != mouseOverAttributePanel) { if (mouseOverAttributePanel != null) { mouseOverAttributePanel.mouseExited(null); mouseOverAttributePanel = null; } } attributePanel.mouseEntered(null); mouseOverAttributePanel = attributePanel; } } private AttributePanel findAttributePanel(MouseEvent e) { int x = e.getX(); AttributePanel attributePanel = null; if (e.getComponent() instanceof AttributePanel) { attributePanel = (AttributePanel) e.getComponent(); } else if (e.getComponent() instanceof ExclusiveOrInclusivePanel) { ExclusiveOrInclusivePanel exclusiveOrInclusivePanel = (ExclusiveOrInclusivePanel) e.getComponent(); attributePanel = exclusiveOrInclusivePanel.findAttributePanel(x); } else if (e.getComponent() instanceof MetricPanel) { ExclusiveOrInclusivePanel exclusiveOrInclusivePanel = metricPanel.getExclusiveAndInclusivePanel().findExclusiveOrInclusivePanel(x); if (exclusiveOrInclusivePanel != null) { // Non Name metrics int offset = metricPanel.getExclusiveAndInclusivePanel().findExclusiveOrInclusivePanelOffset(x); attributePanel = exclusiveOrInclusivePanel.findAttributePanel(offset); } else { // Name metric attributePanel = metricPanel.getExclusiveAndInclusivePanel().findAttributePanel(); } } return attributePanel; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/ExclusiveAndInclusivePanel.java������������������������������0000644�0001750�0001750�00000026662�14517772113�023137� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnTable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; public class ExclusiveAndInclusivePanel extends JPanel { private List<ExclusiveOrInclusivePanel> exclusiveOrInclusivePanelList; private AttributePanel attributePanel; public ExclusiveAndInclusivePanel( MetricPanel metricPanel, AnTable anTable, final MetricLabel[] metricLabels, boolean wrapMetricName, int column, int count, HeaderMouseHandler headerMouseHandler) { // setBackground(AnEnvironment.TABLE_HEADER_BACKGROUND_COLOR); setOpaque(false); setLayout(new GridBagLayout()); // Add Exclusive/Inclusive panels int[][] columnWidth = anTable.getColumnWidth(); int exclusiveCount = 0; Integer exclusiveIndex = null; int exclusiveWidth = 0; ImageIcon exclusiveIcon = null; int inclusiveCount = 0; Integer inclusiveIndex = null; int inclusiveWidth = 0; ImageIcon inclusiveIcon = null; int attributedCount = 0; Integer attributedIndex = null; int attributedWidth = 0; ImageIcon attributedIcon = null; int staticCount = 0; Integer staticIndex = null; int staticWidth = 0; ImageIcon staticIcon = null; int nameCount = 0; exclusiveOrInclusivePanelList = new ArrayList<ExclusiveOrInclusivePanel>(); for (int i = column; i < column + count; i++) { AnMetric anMetric = metricLabels[i].getAnMetric(); if (anMetric.getSubType() == 2 || // Exclusive anMetric.getSubType() == 16) { // Machine model metrics? exclusiveCount++; if (exclusiveIndex == null) { exclusiveIndex = i; } exclusiveWidth += columnWidth[i][0]; exclusiveIcon = metricLabels[i].getIcon(); } else if (anMetric.getSubType() == 4) { // Inclusive inclusiveCount++; if (inclusiveIndex == null) { inclusiveIndex = i; } inclusiveWidth += columnWidth[i][0]; inclusiveIcon = metricLabels[i].getIcon(); } else if (anMetric.getSubType() == 8) { // Attributed // System? (Callers-callees) attributedCount++; if (attributedIndex == null) { attributedIndex = i; } attributedWidth += columnWidth[i][0]; attributedIcon = metricLabels[i].getIcon(); } else if (anMetric.isNameMetric()) { // Name nameCount++; } else if (anMetric.isStatic()) { // Static (Size, ...) staticCount++; if (staticIndex == null) { staticIndex = i; } staticWidth += columnWidth[i][0]; staticIcon = metricLabels[i].getIcon(); } else { System.out.println("ERROR " + anMetric.getSubType()); } } // System.out.println(metricLabels[index].getAnMetric().getUserName() + ": " + count // + " " + exclusiveCount + " " + inclusiveCount + " " + attributedCount); int gridX = 0; if (exclusiveCount > 0) { String name; ImageIcon icon; if (anTable.getAnParent().showOnlyValuesInTables()) { name = AnLocale.getString("VALUES"); icon = null; } else { name = AnLocale.getString("EXCLUSIVE"); icon = exclusiveIcon; } String toolTip = name + ": " + metricLabels[column].getAnMetric().getUserName(); ExclusiveOrInclusivePanel panel = new ExclusiveOrInclusivePanel( metricPanel, anTable, metricLabels, name, icon, toolTip, exclusiveIndex, exclusiveCount, headerMouseHandler); if (inclusiveCount > 0) { if (AnWindow.getInstance().getExperimentGroups().length == 1) { panel.setBorder( BorderFactory.createMatteBorder(0, 0, 0, 1, AnEnvironment.TABLE_VERTICAL_GRID_COLOR)); } else { panel.setBorder( BorderFactory.createMatteBorder( 0, 0, 0, 1, AnEnvironment.TABLE_VERTICAL_GRID_ATTRIBUTE_COMP_COLOR)); } } panel.setPreferredSize(new Dimension(exclusiveWidth, panel.getPreferredSize().height)); panel.setMinimumSize(new Dimension(exclusiveWidth, panel.getPreferredSize().height)); panel.setMaximumSize(new Dimension(exclusiveWidth, panel.getPreferredSize().height)); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; add(panel, gridBagConstraints); exclusiveOrInclusivePanelList.add(panel); } if (inclusiveCount > 0) { String name = AnLocale.getString("INCLUSIVE"); String toolTip = name + ": " + metricLabels[column].getAnMetric().getUserName(); ExclusiveOrInclusivePanel panel = new ExclusiveOrInclusivePanel( metricPanel, anTable, metricLabels, name, inclusiveIcon, toolTip, inclusiveIndex, inclusiveCount, headerMouseHandler); panel.setPreferredSize(new Dimension(inclusiveWidth, panel.getPreferredSize().height)); panel.setMinimumSize(new Dimension(inclusiveWidth, panel.getPreferredSize().height)); panel.setMaximumSize(new Dimension(inclusiveWidth, panel.getPreferredSize().height)); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; add(panel, gridBagConstraints); exclusiveOrInclusivePanelList.add(panel); } if (attributedCount > 0) { String name = AnLocale.getString("ATTRIBUTED"); String toolTip = name + ": " + metricLabels[column].getAnMetric().getUserName(); ExclusiveOrInclusivePanel panel = new ExclusiveOrInclusivePanel( metricPanel, anTable, metricLabels, name, null, toolTip, attributedIndex, attributedCount, headerMouseHandler); panel.setPreferredSize(new Dimension(attributedWidth, panel.getPreferredSize().height)); panel.setMinimumSize(new Dimension(attributedWidth, panel.getPreferredSize().height)); panel.setMaximumSize(new Dimension(attributedWidth, panel.getPreferredSize().height)); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; add(panel, gridBagConstraints); exclusiveOrInclusivePanelList.add(panel); } if (staticCount > 0) { String toolTip = metricLabels[column].getAnMetric().getUserName(); ExclusiveOrInclusivePanel panel = new ExclusiveOrInclusivePanel( metricPanel, anTable, metricLabels, "VALUE", null, toolTip, staticIndex, staticCount, headerMouseHandler); panel.setPreferredSize(new Dimension(staticWidth, panel.getPreferredSize().height)); panel.setMinimumSize(new Dimension(staticWidth, panel.getPreferredSize().height)); panel.setMaximumSize(new Dimension(staticWidth, panel.getPreferredSize().height)); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; add(panel, gridBagConstraints); exclusiveOrInclusivePanelList.add(panel); } if (nameCount > 0) { if (anTable.getType() != AnDisplay.DSP_Source && anTable.getType() != AnDisplay.DSP_SourceV2 && anTable.getType() != AnDisplay.DSP_Disassembly && anTable.getType() != AnDisplay.DSP_DisassemblyV2 && anTable.getType() != AnDisplay.DSP_SourceDisassembly) { if (anTable.getNames()[1] != null) { JLabel label = new JLabel(anTable.getNames()[1]); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(0, 4, 0, 0); add(label, gridBagConstraints); } } attributePanel = new AttributePanel( metricPanel, anTable, metricLabels, null, column, headerMouseHandler, null); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(attributePanel, gridBagConstraints); } } public List<JMenuItem> getSortByMenuItems() { List<JMenuItem> list = new ArrayList<JMenuItem>(); for (ExclusiveOrInclusivePanel exclusiveOrInclusivePanel : exclusiveOrInclusivePanelList) { list.addAll(exclusiveOrInclusivePanel.getSortByMenuItems()); } return list; } protected ExclusiveOrInclusivePanel findExclusiveOrInclusivePanel(int x) { int start = 0; for (int i = 0; i < exclusiveOrInclusivePanelList.size(); i++) { if (x >= start && x <= start + exclusiveOrInclusivePanelList.get(i).getSize().width) { return exclusiveOrInclusivePanelList.get(i); } start += exclusiveOrInclusivePanelList.get(i).getSize().width; } return null; } protected AttributePanel findAttributePanel() { return attributePanel; // Only for Name metric } protected int findExclusiveOrInclusivePanelOffset(int x) { int start = 0; for (int i = 0; i < exclusiveOrInclusivePanelList.size(); i++) { if (x >= start && x <= start + exclusiveOrInclusivePanelList.get(i).getSize().width) { return x - start; } start += exclusiveOrInclusivePanelList.get(i).getSize().width; } return 0; } } ������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/MetricPanel.java���������������������������������������������0000644�0001750�0001750�00000046256�14517772113�020107� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnTable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.TransferHandler; public class MetricPanel extends JPanel implements Transferable { static { DragSource.getDefaultDragSource().addDragSourceListener(new MetricPanelDragSourceListener()); } private AnTableHeaderPanel anTableHeaderPanel; private AnMetric anMetric; private AnTable anTable; private MetricLabel[] metricLabels; private int maxMetricNameLabels = 16; private ExclusiveAndInclusivePanel exclusiveAndInclusivePanel; private JLabel removeIconLabel; private JLabel configureIconLabel; private int column; private int count; private JPanel iconNamePanel; private JLabel[] metricNameLabels = new JLabel[maxMetricNameLabels]; public MetricPanel( AnTableHeaderPanel anTableHeaderPanel, AnMetric anMetric, AnTable anTable, final MetricLabel[] metricLabels, boolean wrapMetricName, final int column, int count, Color backgroundcolor) { this.anTableHeaderPanel = anTableHeaderPanel; this.anMetric = anMetric; this.anTable = anTable; this.metricLabels = metricLabels; this.column = column; this.count = count; String metricName = anMetric.getUserName(); setOpaque(false); setOpaque(true); setBackground(backgroundcolor); setLayout(new GridBagLayout()); setBorder( BorderFactory.createMatteBorder( 0, 0, 0, 1, AnEnvironment.TABLE_VERTICAL_GRID_METRIC_COLOR)); GridBagConstraints gridBagConstraints = new GridBagConstraints(); // Mouse events HeaderMouseHandler headerMouseHandler = new HeaderMouseHandler(this); addMouseMotionListener(headerMouseHandler); addMouseListener(headerMouseHandler); // // Sort metric or not? // boolean sortedByThisMetric = false; // if (anTable.canSort()) { // for (int i = 0; i < count; i++) { // if (metricLabels[index + i].getAnMetric().isSorted()) { // sortedByThisMetric = true; // break; // } // } // } iconNamePanel = new JPanel(new GridBagLayout()); iconNamePanel.setOpaque(false); // if (sortedByThisMetric) { // Color moreBluish = new Color(backgroundcolor.getRed() - 6, // backgroundcolor.getGreen() - 6, backgroundcolor.getBlue()); // iconNamePanel.setOpaque(true); // iconNamePanel.setBackground(moreBluish); // } // Configure icon if (!metricLabels[column].getAnMetric().isNameMetric()) { configureIconLabel = new JLabel(AnUtility.hamburgerBlankIcon); configureIconLabel.setToolTipText(AnLocale.getString("Configure this metric")); AnUtility.setAccessibleContext( configureIconLabel.getAccessibleContext(), configureIconLabel.getToolTipText()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(1, 1, 0, 2); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; iconNamePanel.add(configureIconLabel, gridBagConstraints); configureIconLabel.addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { showPopup(e); } @Override public void mouseEntered(MouseEvent e) { configureIconLabel.setIcon(AnUtility.hamburgerFocusedIcon); removeIconLabel.setIcon(AnUtility.removeIcon); } @Override public void mouseExited(MouseEvent e) { configureIconLabel.setIcon(AnUtility.hamburgerIcon); } }); } // Metric name // Use metricNameLabels[0] as default // metricNameLabels[1-9] are for wrapped metric names if (!metricLabels[column].getAnMetric().isNameMetric()) { metricNameLabels[0] = new JLabel(metricName); AnUtility.setAccessibleContext( metricNameLabels[0].getAccessibleContext(), metricNameLabels[0].getText()); metricNameLabels[0].setHorizontalAlignment(JLabel.CENTER); String ttText = metricName; if (anMetric.getShortDesc() != null) { ttText += " - " + anMetric.getShortDesc(); } setToolTipText(AnLocale.getString("Metric") + ": " + ttText); } else { if (anTable.getType() == AnDisplay.DSP_Source || anTable.getType() == AnDisplay.DSP_SourceV2 || anTable.getType() == AnDisplay.DSP_Disassembly || anTable.getType() == AnDisplay.DSP_DisassemblyV2 || anTable.getType() == AnDisplay.DSP_SourceDisassembly) { String labelText = anTable.getNames()[0]; labelText = labelText.replaceFirst(".*: ", ""); labelText = labelText.replaceFirst(" \\(.*", ""); metricNameLabels[0] = new JLabel(labelText); AnUtility.setAccessibleContext( metricNameLabels[0].getAccessibleContext(), metricNameLabels[0].getText()); } else { metricNameLabels[0] = new JLabel(anTable.getNames()[0]); AnUtility.setAccessibleContext( metricNameLabels[0].getAccessibleContext(), metricNameLabels[0].getText()); } setToolTipText(anTable.getNames()[0]); } metricNameLabels[0].setFont(AnTableHeaderPanel.smallBoldFont); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; if (metricLabels[column].getAnMetric().isNameMetric()) { gridBagConstraints.insets = new Insets(0, 4, 0, 0); } gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; iconNamePanel.add(metricNameLabels[0], gridBagConstraints); for (int i = 1; i < maxMetricNameLabels; i++) { metricNameLabels[i] = new JLabel(wrapMetricName ? "" : ""); AnUtility.setAccessibleContext( metricNameLabels[i].getAccessibleContext(), metricNameLabels[i].getText()); metricNameLabels[i].setFont(AnTableHeaderPanel.smallBoldFont); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = i; iconNamePanel.add(metricNameLabels[i], gridBagConstraints); } // Remove icon if (!metricLabels[column].getAnMetric().isNameMetric()) { removeIconLabel = new JLabel(AnUtility.removeIconBlank); removeIconLabel.setToolTipText(AnLocale.getString("Remove this metric")); AnUtility.setAccessibleContext( removeIconLabel.getAccessibleContext(), removeIconLabel.getToolTipText()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(1, 2, 0, 1); gridBagConstraints.anchor = GridBagConstraints.NORTHEAST; iconNamePanel.add(removeIconLabel, gridBagConstraints); removeIconLabel.addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { AnWindow.getInstance() .getSettings() .getMetricsSetting() .set(this, metricLabels[column].getAnMetric().getComd(), false); } @Override public void mouseEntered(MouseEvent e) { removeIconLabel.setIcon(AnUtility.removeFocusedIcon); configureIconLabel.setIcon(AnUtility.hamburgerIcon); } @Override public void mouseExited(MouseEvent e) { removeIconLabel.setIcon(AnUtility.removeIcon); } }); } gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; add(iconNamePanel, gridBagConstraints); // Add Exclusive/Inclusive panel exclusiveAndInclusivePanel = new ExclusiveAndInclusivePanel( this, anTable, metricLabels, wrapMetricName, column, count, headerMouseHandler); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(2, 0, 0, 0); add(exclusiveAndInclusivePanel, gridBagConstraints); // DnD addMouseMotionListener(new MouseDraggedListener()); setTransferHandler(new DADTransferHandler()); setDropTarget(new DropTarget(this, new MetricPanelDropTargetListener())); } /** * @return the anTableHeaderPanel */ public AnTableHeaderPanel getAnTableHeaderPanel() { return anTableHeaderPanel; } /** * @return the anMetric */ public AnMetric getAnMetric() { return anMetric; } class MouseDraggedListener extends MouseMotionAdapter { // @Override @Override public void mouseDragged(MouseEvent e) { JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); handler.exportAsDrag(c, e, TransferHandler.COPY); } } private static DataFlavor dadDataFlavor = null; public static DataFlavor getDADDataFlavor() throws Exception { if (dadDataFlavor == null) { dadDataFlavor = new DataFlavor( DataFlavor.javaJVMLocalObjectMimeType + ";class=org.gprofng.mpmt.table.MetricPanel"); } return dadDataFlavor; } // @Override @Override public Object getTransferData(DataFlavor flavor) { DataFlavor thisFlavor; try { thisFlavor = getDADDataFlavor(); } catch (Exception ex) { ex.printStackTrace(System.err); return null; } if (thisFlavor != null && flavor.equals(thisFlavor)) { return MetricPanel.this; } return null; } // @Override @Override public DataFlavor[] getTransferDataFlavors() { DataFlavor[] flavors = {null}; try { flavors[0] = getDADDataFlavor(); } catch (Exception ex) { ex.printStackTrace(System.err); return null; } return flavors; } // @Override @Override public boolean isDataFlavorSupported(DataFlavor flavor) { DataFlavor[] flavors = {null}; try { flavors[0] = getDADDataFlavor(); } catch (Exception ex) { ex.printStackTrace(System.err); return false; } for (DataFlavor f : flavors) { if (f.equals(flavor)) { return true; } } return false; } class DADTransferHandler extends TransferHandler { public DADTransferHandler() { super(); } // @Override() @Override public Transferable createTransferable(JComponent c) { if (c instanceof MetricPanel) { Transferable tip = (MetricPanel) c; return tip; } return null; } // @Override() @Override public int getSourceActions(JComponent c) { if (c instanceof MetricPanel) { return TransferHandler.COPY; } return TransferHandler.NONE; } } protected void mouseEntered(MouseEvent e) { if (removeIconLabel != null) { removeIconLabel.setIcon(AnUtility.removeIcon); } if (configureIconLabel != null) { configureIconLabel.setIcon(AnUtility.hamburgerIcon); } } public void mouseExited(MouseEvent e) { if (removeIconLabel != null) { removeIconLabel.setIcon(AnUtility.removeIconBlank); } if (configureIconLabel != null) { configureIconLabel.setIcon(AnUtility.hamburgerBlankIcon); } } protected void showPopup(MouseEvent event) { MetricLabel metricLabel = metricLabels[column]; JPopupMenu popup = new JPopupMenu(); AnWindow.getInstance() .getSettings() .getMetricsSetting() .addMetricsPopupMenus(popup, metricLabel.getAnMetric(), anTable, getSortByMenu()); popup.show(event.getComponent(), event.getX() + 5, event.getY() + 5); } private JMenu getSortByMenu() { JMenu sortByMenuItem = new JMenu(AnLocale.getString("Sort This Metric By")); if (anTable.canSort()) { if (metricLabels[column].getAnMetric().isNameMetric()) { JMenuItem menuItem = new JMenuItem(metricLabels[column].getAnMetric().getUserName()); menuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance() .getSettings() .getMetricsSetting() .setSortMetricByDType(this, column, anTable.getType()); } }); sortByMenuItem.add(menuItem); } else { List<JMenuItem> list = exclusiveAndInclusivePanel.getSortByMenuItems(); for (JMenuItem menuItem : list) { sortByMenuItem.add(menuItem); } } } else { sortByMenuItem.setEnabled(false); } return sortByMenuItem; } private int labelWidth(String text) { AnTableHeaderPanel.testLabel.setText(text); return AnTableHeaderPanel.testLabel.getPreferredSize().width; } protected int splitMetricNameIntoMultipleRows(int maxPanelWidth) { // System.out.println("splitMetricNameIntoMultipleRows: " + maxPanelWidth); int maxLabelWidth = maxPanelWidth - 25; // subtract icon widths and spacing String metricName = metricNameLabels[0].getText(); // metricName = // "cpu_clk_thread_unhalted.ref_xclk~msr_offcore=0~edge=0~umask=0~anythr=0/0"; // metricName = // "cpu_clk_thread_unhalted.ref_xclk~msr_offcore=0~edge=0~umask=0~anythr=0/0 // xxx\\xxxx\\xxxx\\xxxx\\xxxxdsa 1111 222 33333 44444 55555"; // metricName = // "br_inst_exec.all_indirect_jump_non_call_ret~edge=0~inv=0~in_tx=0~system=0~msr_offcore=0/1,on"; String[] split = metricName.split(" |_|\\.|~|-|\\\\"); if (split.length == 1) { // do nothing return 1; } int masterIndex = -1; Character splitCharNextLine = null; for (int i = 0; i < split.length - 1; i++) { masterIndex += split[i].length() + 1; char splitChar = metricName.charAt(masterIndex); // System.out.println(splitChar); if (splitCharNextLine != null) { split[i] = splitCharNextLine + split[i]; splitCharNextLine = null; } if (splitChar != '~') { split[i] = split[i] + splitChar; } else { splitCharNextLine = splitChar; } } int row = 0; int start = 0; while (start < split.length) { int count = 0; StringBuilder sb = new StringBuilder(); while (true) { if ((start + count) >= (split.length)) { break; } if (labelWidth(sb.toString() + split[start + count]) >= maxLabelWidth && count != 0) { break; } if (count > 0 && split[start + count].toString().charAt(0) == '~') { break; } sb.append(split[start + count]); count++; } start = start + count; metricNameLabels[row].setText(sb.toString()); if ((row + 1) >= maxMetricNameLabels) { metricNameLabels[row].setText(metricNameLabels[row].getText() + "..."); row++; break; } row++; } return row; } protected void adjustMetricNameRows(int rows) { for (int i = 1; i <= rows - 1; i++) { if (metricNameLabels[i].getText().isEmpty()) { metricNameLabels[i].setText(" "); } } } /** * @return the iconNamePanel */ public JPanel getIconNamePanel() { return iconNamePanel; } /** * @return the exclusiveAndInclusivePanel */ public ExclusiveAndInclusivePanel getExclusiveAndInclusivePanel() { return exclusiveAndInclusivePanel; } public String dump() { return metricNameLabels[0].getText() + metricNameLabels[1].getText() + metricNameLabels[2].getText(); } static class MetricPanelDragSourceListener implements DragSourceListener { // @Override @Override public void dragDropEnd(DragSourceDropEvent dsde) { // System.out.println("DragSource:dragDropEnd: " + // dsde.getDragSourceContext().getComponent()); if (dsde.getDragSourceContext().getComponent() instanceof MetricPanel) { MetricPanel metricPanel = (MetricPanel) dsde.getDragSourceContext().getComponent(); metricPanel.getAnTableHeaderPanel().setDropPosition(-1); } } // @Override @Override public void dragExit(DragSourceEvent dse) { // System.out.println("DragSource:dragExit: " + dse); if (dse.getDragSourceContext().getComponent() instanceof MetricPanel) { MetricPanel metricPanel = (MetricPanel) dse.getDragSourceContext().getComponent(); metricPanel.getAnTableHeaderPanel().setDropPosition(-1); } } // @Override @Override public void dragEnter(DragSourceDragEvent dsde) { // System.out.println("DragSource:dragEnter: " + dsde.getLocation()); } @Override public void dragOver(DragSourceDragEvent dsde) { // System.out.println("DragSource:dragOver: " + dsde.getLocation()); if (dsde.getDragSourceContext().getComponent() instanceof MetricPanel) { MetricPanel metricPanel = (MetricPanel) dsde.getDragSourceContext().getComponent(); metricPanel.getAnTableHeaderPanel().setDropLocation(dsde.getLocation().x); } } @Override public void dropActionChanged(DragSourceDragEvent dsde) {} } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/AnTableHeaderPanel.java��������������������������������������0000644�0001750�0001750�00000022213�14517772113�021266� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnTable; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Rectangle; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; public class AnTableHeaderPanel extends JPanel { protected static final Font smallFont = new JLabel().getFont().deriveFont((float) new JLabel().getFont().getSize() - 1); protected static final Font verySmallFont = new JLabel().getFont().deriveFont((float) new JLabel().getFont().getSize() - 2); protected static final Font boldFont = new JLabel().getFont().deriveFont(Font.BOLD); protected static final Font smallBoldFont = boldFont.deriveFont((float) boldFont.getSize() - 1); protected static final Font verySmallBoldFont = verySmallFont.deriveFont(Font.BOLD); protected static final JLabel testLabel = new JLabel(); static { testLabel.setFont(boldFont); } private List<MetricPanel> metricPanels = new ArrayList<MetricPanel>(); private List<Integer> startColumns = new ArrayList<Integer>(); private List<Integer> columnCounts = new ArrayList<Integer>(); private List<Integer> panelWidths = new ArrayList<Integer>(); private int dropPosition = -1; public AnTableHeaderPanel(AnTable anTable, MetricLabel[] metricLabels, boolean wrapMetricName) { metricPanels = new ArrayList<MetricPanel>(); startColumns = new ArrayList<Integer>(); columnCounts = new ArrayList<Integer>(); panelWidths = new ArrayList<Integer>(); int[][] columnWidth = anTable.getColumnWidth(); setBackground(AnEnvironment.TABLE_HEADER_BACKGROUND_COLOR_1); setBorder(BorderFactory.createMatteBorder(0, 0, 1, 1, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; int panelCount = 0; int gridX = 0; int startColumn = 0; while (startColumn < metricLabels.length) { int count = 1; while (startColumn + count < metricLabels.length && metricLabels[startColumn + count - 1] .getAnMetric() .getComd() .equals(metricLabels[startColumn + count].getAnMetric().getComd())) { count++; } int panelWidth = 0; for (int i = startColumn; i < startColumn + count; i++) { panelWidth += columnWidth[i][0]; } Color backgroundcolor; if (panelCount % 2 == 0) { backgroundcolor = AnEnvironment.TABLE_HEADER_BACKGROUND_COLOR_1; } else { backgroundcolor = AnEnvironment.TABLE_HEADER_BACKGROUND_COLOR_2; } if (metricLabels[startColumn].getAnMetric().isNameMetric()) { MetricPanel metricPanel = new MetricPanel( this, metricLabels[startColumn].getAnMetric(), anTable, metricLabels, wrapMetricName, startColumn, count, backgroundcolor); // metricPanel.setPreferredSize(new Dimension(panelWidth, // metricPanel.getPreferredSize().height)); gridBagConstraints.gridx = startColumn; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(metricPanel, gridBagConstraints); metricPanels.add(metricPanel); startColumns.add(startColumn); columnCounts.add(count); panelWidths.add(panelWidth); } else { MetricPanel metricPanel = new MetricPanel( this, metricLabels[startColumn].getAnMetric(), anTable, metricLabels, wrapMetricName, startColumn, count, backgroundcolor); // metricPanel.setPreferredSize(new Dimension(panelWidth, // metricPanel.getPreferredSize().height)); gridBagConstraints.gridx = startColumn; add(metricPanel, gridBagConstraints); add(metricPanel, gridBagConstraints); metricPanels.add(metricPanel); startColumns.add(startColumn); columnCounts.add(count); panelWidths.add(panelWidth); } startColumn += count; panelCount++; } // Deal with long metric names if (wrapMetricName) { int noMetricNameRows = 0; for (int i = 0; i < metricPanels.size(); i++) { MetricPanel metricPanel = metricPanels.get(i); JPanel iconNamePanel = metricPanel.getIconNamePanel(); int column = startColumns.get(i); int columnCount = columnCounts.get(i); int actualColumnWidth = 0; for (int n = 0; n < columnCount; n++) { actualColumnWidth += columnWidth[column + n][0]; } boolean nameTooLong = iconNamePanel.getPreferredSize().width >= actualColumnWidth; // System.out.println(column + ":" + columnCount + ": " + // iconNamePanel.getPreferredSize().width + " " + actualColumnWidth + " " + (nameTooLong ? // "*" : "")); if (nameTooLong) { int rows = metricPanel.splitMetricNameIntoMultipleRows(actualColumnWidth); if (rows > noMetricNameRows) { noMetricNameRows = rows; } } } if (noMetricNameRows > 0) { for (int i = 0; i < metricPanels.size(); i++) { MetricPanel metricPanel = metricPanels.get(i); metricPanel.adjustMetricNameRows(noMetricNameRows); } } } // Set width... for (int i = 0; i < metricPanels.size(); i++) { MetricPanel metricPanel = metricPanels.get(i); metricPanel.setPreferredSize( new Dimension(panelWidths.get(i), metricPanel.getPreferredSize().height)); } } public static int getMinimumColumnWidth() { JLabel label = new JLabel(AnLocale.getString("EXCLUSIVE")); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setFont(AnTableHeaderPanel.verySmallFont); return label.getPreferredSize().width + 26; } @Override public void paint(Graphics g) { super.paint(g); if (dropPosition >= 0) { paintDropPosition(g, dropPosition); } } private void paintDropPosition(Graphics g, int dropPosition) { int lineCenter = 0; if (dropPosition == 0) { lineCenter = 0; } else { for (int i = 0; i < dropPosition; i++) { lineCenter += panelWidths.get(i); } lineCenter -= 1; } int h = getHeight(); g.setColor(AnEnvironment.DROP_LINE_COLOR); g.drawLine(lineCenter - 1, 0, lineCenter - 1, h); g.drawLine(lineCenter, 0, lineCenter, h); g.drawLine(lineCenter + 1, 0, lineCenter + 1, h); g.drawLine(lineCenter - 3, 0, lineCenter + 3, 0); g.drawLine(lineCenter - 2, 1, lineCenter + 2, 1); g.drawLine(lineCenter - 2, h - 2, lineCenter + 2, h - 2); g.drawLine(lineCenter - 3, h - 1, lineCenter + 3, h - 1); } public void setDropPosition(int dropPosition) { if (dropPosition != this.dropPosition) { this.dropPosition = dropPosition; repaint(); } } public void setDropLocation(int xOnScreen) { int x = xOnScreen - getLocationOnScreen().x; // Relative to anTableHeaderPanel int dropPosition = 0; if (x < panelWidths.get(0) / 2) { dropPosition = 0; } else { int startX = panelWidths.get(0) / 2; int totalPanelWidth = panelWidths.get(0); dropPosition = 1; for (int panelNo = 1; panelNo < panelWidths.size(); panelNo++) { if (x >= startX && x < totalPanelWidth + panelWidths.get(panelNo) / 2) { break; } startX = totalPanelWidth + panelWidths.get(panelNo) / 2; totalPanelWidth += panelWidths.get(panelNo); dropPosition++; } } setDropPosition(dropPosition); Rectangle visibleRectangle = getVisibleRect(); if (x < visibleRectangle.x + 50) { scrollRectToVisible(new Rectangle(visibleRectangle.x - 50, 1, x, 1)); } else if (x > visibleRectangle.x + visibleRectangle.width - 50) { scrollRectToVisible(new Rectangle(visibleRectangle.x + 50, 1, x, 1)); } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/AnTableScrollPane.java���������������������������������������0000644�0001750�0001750�00000012546�14517772113�021170� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Component; import java.awt.Graphics; import java.awt.Image; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.event.MouseInputAdapter; public abstract class AnTableScrollPane extends AnJScrollPane { private Image addtablecolumnsImage = AnUtility.addColumnIcon.getImage(); private static final String metricsIconToolTip = AnLocale.getString("Click to select colums to display..."); private static int imageXGap = -1; private static final int imageYGap = 2; private boolean hasColumnButton; private int dtype; private JPopupMenu metricsSelectorpopup = null; public AnTableScrollPane(int dtype, boolean hasColumnButton) { this.dtype = dtype; this.hasColumnButton = hasColumnButton; init(); } protected void init() { if (hasColumnButton) { addMouseListener( new MouseInputAdapter() { @Override public void mouseClicked(MouseEvent e) { super.mouseClicked(e); if (!e.isPopupTrigger()) { int startX = e.getX(); int startY = e.getY(); // Handle mouse click over data presentation icon AnWindow anWindow = AnWindow.getInstance(); if (anWindow.getSettingsAction().isEnabled()) { int width = getSize().width; if (startX >= width - (addtablecolumnsImage.getWidth(null) + imageXGap) && startX <= (width - imageXGap) && startY >= imageYGap && startY <= (addtablecolumnsImage.getHeight(null) + imageYGap)) { showMetricsConfigurationPopup( AnTableScrollPane.this, startX + 5, startY + 5, dtype); } } } } }); addMouseMotionListener( new MouseMotionAdapter() { @Override public void mouseMoved(MouseEvent e) { super.mouseMoved(e); int startX = e.getX(); int startY = e.getY(); // Handle tooltip data presentation icon AnWindow anWindow = AnWindow.getInstance(); if (anWindow.getSettingsAction().isEnabled()) { int width = getSize().width; if (startX >= width - (addtablecolumnsImage.getWidth(null) + imageXGap) && startX <= (width - imageXGap) && startY >= imageYGap && startY <= (addtablecolumnsImage.getHeight(null) + imageYGap)) { setToolTipText(metricsIconToolTip); } else { setToolTipText(null); } } } }); } } public void showMetricsConfigurationPopup(Component component, int x, int y, int dtype) { metricsSelectorpopup = getmetricsSelectorPopup(dtype); metricsSelectorpopup.show(component, x, y); } private JPopupMenu getmetricsSelectorPopup(int dtype) { JPopupMenu popup = new JPopupMenu(); AnWindow.getInstance() .getSettings() .getMetricsSetting() .addMetricsPopupSelector(popup, dtype, true); return popup; } @Override public void paint(Graphics g) { super.paint(g); int vsbw = getVerticalScrollBar().getWidth(); // 17 int vsbh = getVerticalScrollBar().getHeight(); // many+ boolean vsbv = getVerticalScrollBar().isVisible(); int hsbw = getHorizontalScrollBar().getWidth(); // many+ int hsbh = getHorizontalScrollBar().getHeight(); // 17 boolean hsbv = getHorizontalScrollBar().isVisible(); g.setColor(AnEnvironment.SCROLLBAR_TRACK_COLOR); g.fillRect(getWidth() - vsbw, 0, vsbw, getHeight() - vsbh - (hsbv ? hsbh : 0)); g.setColor(AnEnvironment.SPLIT_PANE_BORDER_COLOR); if (hsbv) { g.drawLine(getWidth() - vsbw, 0, getWidth() - vsbw, getHeight() - vsbh - hsbh - 1); g.drawLine( getWidth() - vsbw, getHeight() - vsbh - hsbh - 1, getWidth(), getHeight() - vsbh - hsbh - 1); } else { g.drawLine(getWidth() - vsbw, getHeight() - vsbh - 1, getWidth(), getHeight() - vsbh - 1); } if (hasColumnButton && getVerticalScrollBarPolicy() == JScrollPane.VERTICAL_SCROLLBAR_ALWAYS) { g.drawImage( addtablecolumnsImage, getWidth() - (addtablecolumnsImage.getHeight(null) + imageXGap), imageYGap, null); } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/AttributePanel.java������������������������������������������0000644�0001750�0001750�00000030604�14517772113�020615� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnCompDisp; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnTable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.CompareModeSetting.CompareMode; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.TransferHandler; public class AttributePanel extends JPanel { private MetricPanel metricPanel; private AnTable anTable; private ExclusiveOrInclusivePanel exclusiveOrInclusivePanel; private String compareLabelText = null; private JLabel sortIconLabel; private int column; private ImageIcon sortIcon; public AttributePanel( MetricPanel metricPanel, AnTable anTable, final MetricLabel[] metricLabels, ExclusiveOrInclusivePanel exclusiveOrInclusivePanel, int column, HeaderMouseHandler headerMouseHandler, String toolTip) { this.metricPanel = metricPanel; this.anTable = anTable; this.exclusiveOrInclusivePanel = exclusiveOrInclusivePanel; this.column = column; setLayout(new GridBagLayout()); setOpaque(false); JLabel label; GridBagConstraints gridBagConstraints; int gridX2 = 0; addMouseListener(headerMouseHandler); addMouseMotionListener(headerMouseHandler); setToolTipText(toolTip); if (anTable.canSort()) { boolean sortedByThisColumn = false; if (anTable.getSortColumn() == column) { sortedByThisColumn = true; } if (sortedByThisColumn) { setOpaque(true); setBackground(AnEnvironment.TABLE_HEADER_SELECTED_COLOR); } } JPanel attributePanel = new JPanel(new GridBagLayout()); attributePanel.setOpaque(false); MetricLabel metricLabel = metricLabels[column]; if (metricLabel.getClock() != -1.0) { label = new JLabel(AnLocale.getString("sec.")); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setFont(AnTableHeaderPanel.smallFont); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX2++; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; int width = anTable.getColumnWidth()[column][1]; label.setHorizontalAlignment(JLabel.CENTER); label.setPreferredSize(new Dimension(width, label.getPreferredSize().height)); label.setMinimumSize(new Dimension(width, label.getPreferredSize().height)); label.setMaximumSize(new Dimension(width, label.getPreferredSize().height)); attributePanel.add(label, gridBagConstraints); } if (metricLabel.getUnit() != null) { String unitText = metricLabel.getUnit(); if (!metricLabel.getAnMetric().isNameMetric() && unitText.length() == 0) { if (metricLabel.getAnMetric().getAux() != null && !metricLabel.getAnMetric().getAux().equals(metricLabel.getAnMetric().getComd())) { unitText = AnLocale.getString("sec."); } else { unitText = "#"; } } label = new JLabel(unitText); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setFont(AnTableHeaderPanel.smallFont); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX2++; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; int width = anTable.getColumnWidth()[column][2]; label.setHorizontalAlignment(JLabel.CENTER); label.setPreferredSize(new Dimension(width, label.getPreferredSize().height)); label.setMinimumSize(new Dimension(width, label.getPreferredSize().height)); label.setMaximumSize(new Dimension(width, label.getPreferredSize().height)); attributePanel.add(label, gridBagConstraints); } if (metricLabel.getTotal() != -1.0) { label = new JLabel("%"); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setFont(AnTableHeaderPanel.smallFont); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridX2++; gridBagConstraints.gridy = 0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; int width = anTable.getColumnWidth()[column][3]; label.setHorizontalAlignment(JLabel.CENTER); label.setPreferredSize(new Dimension(width, label.getPreferredSize().height)); label.setMinimumSize(new Dimension(width, label.getPreferredSize().height)); label.setMaximumSize(new Dimension(width, label.getPreferredSize().height)); attributePanel.add(label, gridBagConstraints); } gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; add(attributePanel, gridBagConstraints); // Add compare group and border if in compare mode if (!metricLabels[column].getAnMetric().isNameMetric()) { String[][] groups = AnWindow.getInstance().getExperimentGroups(); int numberOfGroups = groups.length; if (numberOfGroups > 1) { int nameColumn = anTable.getNameCol(); int adjColumn = column > nameColumn ? column - 1 : column; int counter = adjColumn % numberOfGroups; if (anTable.getType() == AnDisplay.DSP_SourceV2 || anTable.getType() == AnDisplay.DSP_DisassemblyV2) { // Treat Source view special. Source view has one seperate table per compare group and not // alternating columns. AnDisplay currentAnDisplay = AnWindow.getInstance().getViews().getCurrentViewDisplay(); if (currentAnDisplay instanceof AnCompDisp) { AnCompDisp currentAnCompDisp = (AnCompDisp) currentAnDisplay; counter = currentAnCompDisp.getTableIndex(anTable); } } String compareModeText = ""; if (AnWindow.getInstance().getSettings().getCompareModeSetting().get() == CompareMode.CMP_DELTA || AnWindow.getInstance().getSettings().getCompareModeSetting().get() == CompareMode.CMP_RATIO) { compareModeText = " (" + AnWindow.getInstance().getSettings().getCompareModeSetting().get().toString() + ")"; } if (counter == 0) { compareLabelText = AnLocale.getString("Baseline"); setToolTipText(AnLocale.getString("Comparison Baseline") + ": " + getToolTipText()); } else if (counter > 0) { if (AnWindow.getInstance().isExperimentGroupsSimple()) { compareLabelText = AnLocale.getString("Exp. ") + counter + compareModeText; setToolTipText( AnLocale.getString("Comparison Experiment") + " " + counter + ": " + getToolTipText()); } else { compareLabelText = AnLocale.getString("Group " + counter + compareModeText); setToolTipText( AnLocale.getString("Comparison Group") + " " + counter + ": " + getToolTipText()); } setBorder( BorderFactory.createMatteBorder(0, 1, 0, 0, AnEnvironment.TABLE_VERTICAL_GRID_COLOR)); } else { compareLabelText = ""; } gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; JLabel compareLabel = new JLabel(compareLabelText); AnUtility.setAccessibleContext(compareLabel.getAccessibleContext(), compareLabel.getText()); compareLabel.setFont(AnTableHeaderPanel.verySmallFont); add(compareLabel, gridBagConstraints); } } // Sort icon if (anTable.canSort()) { if (column == anTable.getSortColumn()) { sortIcon = metricLabel.getSortIcon(); } else { sortIcon = AnUtility.smallArrowBlankIcon; } } else { sortIcon = AnUtility.smallArrowBlankIcon; } sortIconLabel = new JLabel(sortIcon); AnUtility.setAccessibleContext( sortIconLabel.getAccessibleContext(), AnLocale.getString("Sort Icon")); if (!metricLabels[column].getAnMetric().isNameMetric()) { gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = GridBagConstraints.SOUTHEAST; gridBagConstraints.insets = new Insets(0, 0, 3, 3); add(sortIconLabel, gridBagConstraints); } else { gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = GridBagConstraints.SOUTHWEST; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(0, 3, 3, 0); add(sortIconLabel, gridBagConstraints); } // DnD addMouseMotionListener(new MouseDraggedListener()); } class MouseDraggedListener extends MouseMotionAdapter { @Override public void mouseDragged(MouseEvent e) { JComponent c = (JComponent) e.getSource(); AttributePanel attributePanel = (AttributePanel) c; MetricPanel metricPanel = attributePanel.getMetricPanel(); TransferHandler handler = metricPanel.getTransferHandler(); handler.exportAsDrag(metricPanel, e, TransferHandler.COPY); } } public MetricPanel getMetricPanel() { return metricPanel; } private void changeSortIcon(ImageIcon newIcon) { if (true || column != anTable.getSortColumn()) { if (sortIcon != newIcon) { sortIcon = newIcon; sortIconLabel.setIcon(sortIcon); } } } public void mouseEntered(MouseEvent e) { // System.out.println("AttributePanel.mouseEntered " + column); if (anTable.canSort()) { if (column == anTable.getSortColumn()) { if (sortIcon == AnUtility.smallArrowDownIcon) { sortIconLabel.setIcon(AnUtility.smallArrowUpFocusedIcon); } else { sortIconLabel.setIcon(AnUtility.smallArrowDownFocusedIcon); } } else { sortIconLabel.setIcon(AnUtility.smallArrowDownFocusedIcon); } } } public void mouseExited(MouseEvent e) { // System.out.println("AttributePanel.mouseExited " + column); if (anTable.canSort()) { if (column == anTable.getSortColumn()) { sortIconLabel.setIcon(sortIcon); } else { sortIconLabel.setIcon(AnUtility.smallArrowBlankIcon); } } } public void mouseClicked(MouseEvent e) { // System.out.println("AttributePanel.mouseClicked " + column); anTable.sortTable(column); } public JMenuItem getSortByMenuItem() { String text = ""; text = exclusiveOrInclusivePanel.getLabelText(); if (compareLabelText != null && compareLabelText.length() > 0) { text += " " + compareLabelText; } JMenuItem menuItem = new JMenuItem(text); menuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance() .getSettings() .getMetricsSetting() .setSortMetricByDType(this, column, anTable.getType()); } }); return menuItem; } } ����������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/MetricPanelDropTargetListener.java���������������������������0000644�0001750�0001750�00000006203�14517772113�023575� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import org.gprofng.mpmt.AnWindow; import java.awt.Component; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DropTargetContext; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; public class MetricPanelDropTargetListener implements DropTargetListener { public MetricPanelDropTargetListener() {} // @Override @Override public void dragEnter(DropTargetDragEvent dtde) {} // @Override @Override public void dragOver(DropTargetDragEvent dtde) {} // @Override @Override public void dropActionChanged(DropTargetDragEvent dtde) {} // @Override @Override public void dragExit(DropTargetEvent dte) {} @Override public void drop(DropTargetDropEvent dtde) { DataFlavor dadPanelFlavor = null; Object transferableObj = null; Component targetComponent = null; Transferable transferable = null; try { dadPanelFlavor = MetricPanel.getDADDataFlavor(); transferable = dtde.getTransferable(); DropTargetContext c = dtde.getDropTargetContext(); targetComponent = c.getComponent(); if (transferable.isDataFlavorSupported(dadPanelFlavor)) { transferableObj = dtde.getTransferable().getTransferData(dadPanelFlavor); } } catch (Exception e) { } if (transferableObj == null) { return; } MetricPanel droppedPanel = (MetricPanel) transferableObj; MetricPanel targetPanel = (MetricPanel) targetComponent; // System.out.println("droppedPanel: " + droppedPanel.dump()); // System.out.println("targetPanel: " + targetPanel.dump()); // System.out.println("location: " + dtde.getLocation()); String metricNameDropping = droppedPanel.getAnMetric().getComd(); String metricNameTarget = targetPanel.getAnMetric().getComd(); boolean before = dtde.getLocation().x < targetPanel.getPreferredSize().getWidth() / 2; // System.out.println("metricNameDropping: " + metricNameDropping); // System.out.println("metricNameTarget: " + metricNameTarget); // System.out.println("targetPanel.getPreferredSize(): " + // targetPanel.getPreferredSize()); // System.out.println("before: " + before); AnWindow.getInstance() .getSettings() .getMetricsSetting() .setMetricOrder(this, metricNameDropping, metricNameTarget, before); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/table/AnJTable.java������������������������������������������������0000644�0001750�0001750�00000006663�14517772113�017322� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.table; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JTable; import javax.swing.JTextPane; import javax.swing.table.TableColumnModel; import javax.swing.table.TableModel; public class AnJTable extends JTable { public AnJTable(TableModel dm, TableColumnModel cm) { super(dm, cm); init(); } private void init() { setupSelectionDragHack(); AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Table")); } private final class AnJTableMouseAdapter extends MouseAdapter { private final MouseListener[] list; private final AnJTable table; public AnJTableMouseAdapter(final MouseListener[] ls, AnJTable t) { list = ls; table = t; } private void editCell(final MouseEvent e) { if (!JTextPane.class.isAssignableFrom(e.getSource().getClass())) { return; } table.editCellAt(table.getSelectedRow(), table.getSelectedColumn()); } private void stopCellEditing(final MouseEvent e) { if (!JTextPane.class.isAssignableFrom(e.getSource().getClass())) { return; } if (table.getCellEditor() != null) { table.getCellEditor().stopCellEditing(); } } @Override public void mousePressed(final MouseEvent e) { for (final MouseListener l : list) { l.mousePressed(e); } if (table.getCellEditor() != null) { table.getCellEditor().stopCellEditing(); } } @Override public void mouseClicked(MouseEvent e) { for (final MouseListener l : list) { l.mouseClicked(e); } } @Override public void mouseReleased(MouseEvent e) { for (final MouseListener l : list) { l.mouseReleased(e); } // xxxx may be enabled if we want some interaction after the cell is selected. // table.editCellAt(table.getSelectedRow(), table.getSelectedColumn()); table.requestFocusInWindow(); } @Override public void mouseEntered(MouseEvent e) { stopCellEditing(e); for (final MouseListener l : list) { l.mouseEntered(e); } } @Override public void mouseExited(MouseEvent e) { stopCellEditing(e); for (final MouseListener l : list) { l.mouseEntered(e); } } } private void setupSelectionDragHack() { // Bracket the other mouse listeners so we may inject our lie final MouseListener[] ls = getMouseListeners(); for (final MouseListener l : ls) { removeMouseListener(l); } this.addMouseListener(new AnJTableMouseAdapter(ls, this)); // this.addMouseMotionListener(new AnJTableMouseMotionAdapter(mls, this)); } } �����������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/�������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�015146� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/compare.png��������������������������������������������������0000644�0001750�0001750�00000001112�14517772113�017177� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���tEXtSoftware�Adobe ImageReadyqÉe<��ìIDATxÚbd@ŒPZˆEø5? üÿÿŸ`4´ñ�3ÎÙ!Ò¤mj_ÁÆÎòëç÷5WOìˆè\r†XQÃÈÂÊÊÊðç÷¯Ef޾±0‰%‹0ÄÄ%„è[º0üúñ!ºØCóÒÞ ʘ…•mš›‹clrR"+ 3XÁÊe‹bRB~|þÄ0÷óeLëâ ÀÂÆÆžYVÅÐ5qÃÑã§À‚WÌcHJËÈâï_>Å24^Äå  ìì LLL §Ï]dØ¿y™‰{Hbrh|f&P|:gíœÑr*N¸¸¹X˜™@4(Ôw¬ž—¤³` 6lðûKs`` # ðýûw ñ7B]"(!…ïa¥ËðäÉÌ0üüâ…ß¿ƒ ˆ¥ƒõ §<ö‰Jÿ¬póæÍ¸ñ÷¯_ ÿ �Ò � Ä©@v&9%%%Œxñ×ÏŸ ÿþýc05Ògøõ3ê ˆŠFÿˆ¤Ìß¿~ò�Sb,¾”Èhí<ÍÑÎ:=!}øò”Ä­ÜåchŽ›ò–a]}š È YÛ¶ïäÙµg?zRføùãûþÏŸB>¿Ü€aÀÏNÄe&ÇŒ:œ™iÿŒ&F"³3Î@0�ÐÌÎ)¨¥‹����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/gear.png�����������������������������������������������������0000644�0001750�0001750�00000001714�14517772113�016477� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��^IDATxÚbüÿÿ?:˜Ì¤2؈�ñôĵÿW1`�Ä3`N cHÓÏL ÿeŒqJï1”Ñdxÿä:þ™%gY™ÿ/agú2,eýÿY0�ˆDÌðgLS¶ ˜©lÂpeß2ƒç×0ˆŠˆ2ˆó³0°üeàäæ6–Ô´1ÖqŠb¸{lÍL z†ŒC�ì‚ ÞŒW|‹çhóñò0ðK«1üб3þe`ø÷‡‰…áçf&FF†Oo1|úü…asoÊÕ‚­ÿu@�Øwß3í<¿g™¶oRËï/ ×Nì`¸yzÃÓ;—¤UôÔM]´,<øE®ŸVó@�±t¸3† q1;<¸zšáïϯ 7NîbX6³kÇw ûÞg¸d甞ʩSNQþx¨X3€Ô q1:€ôUìü¿ €jŽžZÙöÿá‘¥ÿÝÞñq¾Ùÿ† áB@Ì ¢A|8H¤¤¤ä}€�bù÷ŸÁJDXˆAŒû/Ãÿ??î^¿ÄpñÃv ä;¨+ßéI2nWŠƒäAêþÕƒô$ˆéãw† Ïï]exòø)Ãÿß¿¤T \•ôãĉƒäAê@êAú� €Xž|fX¾pÎT6^.­Šæ>mS[†ógÇæ[1þê= Ķ¿ÿ1ĂĿ}yÏ0{b+ÇÏß®½ú°èÊÿ�Ä´áÂwß¶)j›003ýa041dˆÌ¬ˆTÒ1ÛÁÀÂñDƒø q<HH=HÈu�NIÆŒWò*ë´?2HÊ0üeâfà’b`då:û÷wϘÿ}eøðü Ãûÿü “Ú›®Î; I�NÏ>3l<¼g«¶¥¹úm‹nܸ˛“À #ÈÉðäýw†ÉS0hh(3ØÚ˜1?y¬>�6`çm†©¿þže?tä¬ÿ§_L;ø9œ^¼z§ÅÂ"ÈðâÕ{†÷Ÿ\Ûqøê¾c'/{¼ýΰqÿ=†©0�ž™€*¤@ø™CŒ�'C$;3ƒÁÏ¿ >|gX~èØ<PÏ3˜�Ĉ-; ƒ*�âPM¯°eg€��X÷n2„µ)����IEND®B`‚����������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/small_down_focused.png���������������������������������������0000644�0001750�0001750�00000000216�14517772113�021424� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������—SÆk���tEXtSoftware�Adobe ImageReadyqÉe<���0IDATxÚblllüÏ@�0ÕÕÕ1âS�’g‚1p)�›„.€•ÿÿÿ r#º@€�ûD%ÖÙ,Ûú����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/circleGreen.gif����������������������������������������������0000644�0001750�0001750�00000000100�14517772113�017750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � �€�q¯{ÿÿÿ!ù ��,���� � ��Œ©kྞL²¢:~wƒ¾QX”1æ�;����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/compareRatio.png���������������������������������������������0000644�0001750�0001750�00000000364�14517772113�020206� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������¼—���bKGD�ÿ‡Ì¿��� pHYs�� �� �šœ���tIMEß  ³�‹û���tEXtComment�Created with The GIMPïd%n���\IDAT(Ïc`†€Ãï?*Ëï?ƒ+ƒ+\üþÃà, ¿ÿ ì~ÿ4PM4„ëD°&øýg˜„a7 8KÑï?ƒ L” »óò›ˆÃ ~ÿaJðúzP�H %�°Ôw����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/filter.png���������������������������������������������������0000644�0001750�0001750�00000001111�14517772113�017035� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������ísO/���tEXtSoftware�Adobe ImageReadyqÉe<��ëIDATxÚbÌÊ+Úÿÿÿc^ÒÀÉi“ú,Xþþýë0±·.ÊÎÎgÿüùÎ~ÿþ=Ó'ONŸ>Í`ffưtÙ s8#§fæži¨­ÆiÕß>}üÈpéÒEMMM†ÙóƒÅ¹99“˜€Î?{áü™ÐÚ†¦/Ø4ÿþáû·o 7n\gÐÖÖf˜9w!Ãý»w‹@z>ý: ¤èô‰ã[._:W]WÏÀÈȈ‚|ÿÎpùò%†)3f3ܹy£ôÞÝ[+AzþþýÃÀtØ& bCSm½Õ=íp\¿vLÏ]¸Lÿùó§^LXhý—oßÍþú5™ ¦hÐógNoyòøaAAq)ƒÀ¼EK^½|Q·qí*K ·îÕÛw¿}ÿ>ûþÛ©,Èþbïà¸h˘fH8|gøñíë*`Ü^±d¡4ðAà z :xà~@H8Øÿ0�4$~hÁ? ÷²z&t€Š~Ó333ƒ�ˆÇK,ØA6²°° ðq&l‚01|ýúÎ'Ù€OŸ>3¼zõ ÎOMMgĦž¥ý"N.®Xh üÆÂÊãGÆm�0d€”8” ù×@uO°�`�.Œø/gÔŒÄ����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/down.png�����������������������������������������������������0000644�0001750�0001750�00000001000�14517772113�016514� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��’IDATxÚbüÿÿ?Ú<‘ÿ d€�bÿÿ10ø× YóÆ&€�ðhÿ—››H6�¤ €Àü²þÿþN² }�6à/±uåT²Â� €AÈÈÈhLn Ø€Y‰±6ÿ#º6u�÷B\å"‰éñüÿ3~dD棫YÔÇ�@L ƥǿ«æ¶Ä2üxvŽAŠ'ÅðmÑ >²<H=H@�ÁÂ@0Õž3CC’¹->µ�n‡” ÃÌÆ†ôú%`M0°pö†ÏÿVÍ>ø}@� �Ðd;Î u 涤tTC5Ï›9áæ‹¿Us}ŸÔû €àÀ I°áÈPgnKË*ÄñYÓún½ü[µàȰf@�¡�3$Ί=ChHfN"P§ô1Üj^tì'\3�È�t ‚1–l• þœÿßì­ù¢A|8ºZ€�Âj�Ì(s¶ÊZ_Î_ ›f / {H)ñ}g#€��†Möh2 À%����IEND®B`‚gprofng-gui-1.0/org/gprofng/mpmt/icons/add.png������������������������������������������������������0000644�0001750�0001750�00000001505�14517772113�016307� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��×IDATxÚbüÿÿ?¨Í`„0 Àñ^Ót •É€ ¦ÏìªÍ‚q�ˆd�+Oføÿéïs0±SŠþ?xÿïÿº½'þÏX¼öÿú}gÁ|8L‹BÂæG¿N‚é??vK40ìžÓÀ°#ú+ƒ†Ž È¡³ç/bøôáýF øu:@�±€Ÿ­¸ Öx÷çA0}²�Â7îÐÓOßÿÓÏÝaX5wb1L3�ËŸï ¾¯Dñ$Œ’ßÿ20120Èr¿q#« –ß@EQõM`Μú0Ò8ÅÀ?¿ÿ€iK†Ô"áb ³&@,ïúL@ ¾L†3?þ}€‡A$w=ƒ«‹+Ã÷ßÿ~ýÀ/cÎîÂКR¤䶬žÓ÷ €aÞáNFƳ-_~þùÇðùû_†'ï~€ÅØYD¿]døüüÃÌmfò €X`¾Íc01²qM²±wÎ2Ö–‹ýÚþñÛ/†_P/€ÂÌ$ÆÀ/kÎe~?}ÑÑÿˆ)=œõOÛ”à«À *cÀ ÂóŠáãŸç z—8ø^B10üýÏÂpë…0Ãnn ³�ˆ ÙÙÿþ•Ñ¢ÌO!Nfúš1ñåÃ0óÇ·¯`õ�7�”8þüùó Æçø ´õïwŽÇ>Ý…ãß_2||záû·/ õ�Ä„ä…ÿ_>}\}áÌi†7n1ü{sžåëc†·ÿ €)èßî>2?ð0<{û‘áë¿ õ�Ä‚ìÂ×ÏL™ºæ?OÜoþ?Ÿâ·¾:2|yù‹á0A}øôáÙW>†åûÞ®yóüá€�bDJ• o°É¨èKȦspñø02ƒ üÿÿïÕo_¶¼}ñxæ“;W.�Š0C@áÄÂ@ÌŠ%;ƒBö-ÈÁ@½¿� �•¥^ÃUm ����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/panhand.png��������������������������������������������������0000644�0001750�0001750�00000001406�14517772113�017170� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��˜IDATxÚbüÿÿ?.š\8 Heñ9 ž¾znÿt5�Ĉl@pb~>Tƒ:Hˆ½zÞ†{Ÿ0”Öw]bbbÒŠíÉ­?q5H@�1€ �းœl¿˜¬;Ÿ½øÿ÷ß¿ÿá)Eÿbÿß|üúÿýçï`6HüâÕ›ÿêÁô Ìö?~çNî¨Sæäâaxôü5C¯+ò5›þýûÅÞ~üÊ '' TýßÖ?6ë)È%�Ä3�hš:/ÃñÓç¸99<œí˜˜þ5ƒðß¿Áô¯_¿Áì¹Ú¤þüù“@`àËçkbÒ &Ϙ÷èÙó— ß¾ÿdX=wÜ›–L‡³Aücd±Ål€kP¼3‹ÐŸß¿¿|ûòi÷ºÍÛ€þexñö˜áçoì-Ëg1üþó—áïŸ? �6à÷ï_¹Í5ENkMåaeç;uæ’ß1ñ³Wï .ùÃ�@`þþù«ÂÁÎÉðñÓ7†Yým¼?þbør&|ìÄi†ï_¿ì °_>¾[5wñ  ³þ0ppq1ìZ¿¯ @apðÈ1†Ïß- p4ž?¶g3+›Ó¥«væ:Z ž¼`Ànß½ÇpáÒU†Nl &h¾úúéÃâ–öž‹7nÝÁk;ïÚ½ŸáýëuÀ@ÿ@ðtpýü±e_?\ÚÐÒõÿ4αáïß¿]pŸá×Ï[ÿ ä„ôþÆ…ãó¾ÿ²&21§íûa¸ÿÞò{×Ï_é FôÜLSrƶ½lì!Øü´yÍ—o§>¾sõ�ˆ@ŒØ²3È %Š# _ñ+ ¾ @€�.Øë"ñhÒ¶����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/small_right.png����������������������������������������������0000644�0001750�0001750�00000000260�14517772113�020061� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR������ ���ú­æž���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß 4X:���=IDAT×uÁ �0WÒý'p'û¨cZ^„p w/@�™ €qU Ùðõ ‰ˆPoòÃé3ÙvS×$_É ^B„Á����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/addtablecolumns.png������������������������������������������0000644�0001750�0001750�00000000242�14517772113�020715� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������H-Ñ���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß8gÓ8Ï���/IDAT(Ïc`0––¶7--m/>62`Ab;Á†&r]8ª@ŽŽD°‡"��á Ç����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/open.png�����������������������������������������������������0000644�0001750�0001750�00000001514�14517772113�016520� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��ÞIDATxÚbüÿÿ?C~m÷b†T°dbsi,�@, âß¿1ž®N šêª`Áë7o3lß½d A�ˆ%»²ý ˆ!,.ÅðêÃWh(Pî?.SÛ+A4@�±üûû×8)) CAB|<N[çÍ›gËߘ˜À†1,\µ‰aß‘“ Ä�$°ë�ˆåï„—®Ýdpvvf°µµ%ÊéÓ§} –¿ÿ00311¼y÷áÕ›· êêê ß¿‡+º~î˧Q4jè›2H«è0<{öl@� `ºàÂåk 2ÒÒàÀûøñ#\1HsNí†ö2¼xú˜AרŠaþìi ï¾ýeøÿ÷ïA€�bùóèf&†³¯0(**1|þü®”Fx…Ħ4€ Q0`�³Ab7oÞZö÷ @�1ý�4Šáúí{ bââ ?þ„ã÷¯_0�c l˜<ïO†_¿~‚Ù~ÿfxÿêÙë[V\  þ2\¹zADTœá7P„Aà×o /Ü`ðõò`0Våaàæä`øùû+C_s6ÃsG:ž>ùî–h@ÌjÚ† ¿ÿbààa`cc‡?»{•ÁÉÚ˜AOUE@“áÝç_ ¯>ýdxú…›A†ù.ûßÏü×î¿ `:øÇpéú]=+PxÀœøäÞM†Ï†Ê J|Ü üœ—þ¾^Æ`Ä ܇ß$d¹ßü•—‘ò –ß¼’‘—€i†v†k~2¼z÷‰÷÷}†ÿ ï¿»Æð‡]ŠáïwN†›Þ¼ÿÿOð@�±œ¿v£ŸíáËNl åé£ ÂÜ qÆ¿ 2|ÿ Çð˜ðößccØtòË©Ws�ˆUŒŒŒ†@õLè˜Û:úþ·”…•]”ZÿýûÂßþýù¹KJJzBAzÆ€��2qAK¯õ�F����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/removeFocused.png��������������������������������������������0000644�0001750�0001750�00000000373�14517772113�020367� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���¹·7Ù���tEXtSoftware�Adobe ImageReadyqÉe<���IDATxÚblllüÏ@"`OŸ>e$Vƒ´´ô&4±. nGkâ 6A7—"ñ+¡ê üÝ@¼Ä@¶ $ÐeW�ñ1$ M0 èš@ I£%’†zdELXüÊŒÆgCW€®©ˆ«¡ì#HNmÇ¥ÉICÛ¢ùÑ[èm…*†…’_x‚Íy•XüX5E€b™”d`�Ê.¬Ð u„����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/reset.png����������������������������������������������������0000644�0001750�0001750�00000001220�14517772113�016673� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��"IDATxÚbüÿÿ? ø…©L 6b^ þ Ä'xúÆu«×1`�Ä3ÀÛ/°LFI­ÓÚ=€AR^™ƒá×Ï ÏÞe8ºsÓ{·Ê·nZß…n�@�1€ põð JÌ*ü¿íôÝÿ÷Þ|ÿÿùÇßÿßÿÓ >H$RRŒˆ dÈ?òí<4%DyX"ÿþüý¦A|8H¤Ý�Ä"~ÿúe¬¡¦ÊÀËÆÌàì‡áÊ­kæ1€äAêÐå�lÀÏŸ?¹¹¹8þÔR[„a�H$R‡.@,Œ@ ¥¥ýíÓ—/\¼¬ 5Í}¬\2‹(Ïðóû·o õÿ‘¢ €X@E%åkwn\32·Äê`€2�å¾}ÿ~ Y3�Ø _>^¾lÎ4y99%5M&&F†ÿþ3|ùñ‡áñãG @y°:tÈj ¨  Ð gwïÿË6îúáÞ«ÿ·^~Ó >H\PP𿵵õôh ƒAŽ››»V@@à PñW â³³³ïÅé÷ïßÿ;88 @ŒÈ^†(’b> fE�‚z5�ˆk23³®_¿Æ°ÿ~F€�b@w’‹Ñøâ@\r иK�§8 B7 €H2�Ý`øü F´h% �à dˆˆ `�éÝuœqáøa����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hollowArrowDown.png������������������������������������������0000644�0001750�0001750�00000000523�14517772113�020725� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���à‘���sRGB�®Îé���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs��œ��œ”SÝ���tIMEá3 «�|™���tEXtComment�Created with GIMPW���®IDATÓ…½ ƒ0FŸQ*jO€(¨ÉÏŒ€ÄÌ‘}0.ÒcˆDMCqU°Dë8R E¾æIwO§û”ˆ/€™}ŠÈà¤@yÖÈ;ðPJ©ÀŸ¨aBÓ4Ôuý³ìûc IžßÎ]×MÖÚ`­ÅC–]"¾ñ8ç‚Ö:´m´ÖaÇ âñ¥ñ%0,Ë3TU…sn»°ZwR¬>µ]99üšF^×gøßCE‚n¢ì����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/errorWarningNew.png������������������������������������������0000644�0001750�0001750�00000000712�14517772113�020707� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEà;ŸÇ2¦��WIDAT8Ë•’?HaÆŸá’ 5Ø4-­AkÐqC8´ Qk[SDäRM­µD‹TtXƒ‹PµöG²Rïm8ï2¼N}¦ãã~Ï÷|ïó*êÚZ@¾ñMP´«yDdY.zɈHFÄ#Fñâ4ûÃ4³J 5 'y¢ÇkL+ù/‘ÖdÙøËRF=´¶Þ·‡ÈÈ#ÛÄG'º»‚ ä °³f£uÂ'g'�ˆ‰=W%MÊ¥¸äú¦ž÷AHA±zʤo(À§ññÕ�Eà”Øî„Þ�úL€½3”c |`f×È¿A2‘³n¼ Âm«[ÐWžе©ÀÔ!¥àùþ÷\ßÉ6î&˜ŸVÒ‡Ð%àÚ´å^£Àê"D‡ð„=÷ R…J­uµŽæ-�]ðûëA¤µ3ƒÇW˜‹[{0Øßþrý�ÈGyÝ23Ío����IEND®B`‚������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/exe_elf.png��������������������������������������������������0000644�0001750�0001750�00000001741�14517772113�017170� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��sIDATxÚbüÿÿ?:˜—*¤2؈�ñô¤ÙïV1`�Ä2`v² TƒHñï¿ÿ㊗[IªZ0<¿}‚aCoä1VfÆ…P5'@jR羿2� €X@Ä÷_ÿóœcš“Å” .ï[0óÁ…Ý ¬,¬ ÿ¾¾ÓœüV ®VºN ¯î7Ø»¤–¨-¤ €ÀüþË`%"«Î ($ÌàÕÈð3¨‚•™áÿ_!Ie†È¦½ ìœ ÿ~}bø÷[¬æ€�ðàõŸõgw/Ôt®aøûóÃíS[nÛÍðôîie†<Î]`Åí¦¹ ¢Þ‚Õà � ƶPÞ0 ‰<¼¼–©«î\<̰|fËŽ;¯þî;tã×%; 6½cÁ?ºn½dPëgxÏË u‡á8Ð*W}Z@ 5~<Go_ýÿñÅíÿ¿?;óaµóÿhKNÿ„€˜D‹41ü¿úfßÿwߟþ±{W†ÿéE�@�1ýûÿßJZNžA‡…áߟ ÷n\`¸ôø÷v ä; þ ¢ÿþd`øöç#Ãݧ®•Ügh¹´’á®ä/p8�ÓÇoÿ.Ü»|ŒáÅ“ ÿÿdúÙE›M9®ÿ€ øýŒ¯¿=Èpµò&ÃÞ_ ÆÕŒu�Äòôý¿å:*ùy J›f0h;0œ?s,6ÏëPïa ¶ý«2àÜÀ‹¯¶3\­»Ì Q¥Û@LÎý\ðæó¿-ö lì &V é5‘JZæ;˜Ù¿‚h Ï~þýŠ‚UŠt„3Ô Яm9­¼~|ÌÀÂ-Ê ¡®Á`bnÏÀÈÊôÖ†âZ†ßÿ¿Ã]ÞÜ ñ–¡îñ6†©�Nï¾þ;uñä~m-mm†«V3\ºxŽ!¯°‚AL€áÕ‡Ÿ ÿ€aÀÊÉÖPÜÄ öŽ¡îÙ†© � °w^þ3oÑr6vFó·_þoäftþúý›³”8Ã×ç÷îg`àåãbpŽ«`úÀP÷ê D3H/@�3###;- ûg¶jÌ1\Œ‘ì, ?ÿ0\Ø,õÇ�¤Xà#C݇£Í �@ŒØ²3Ð@1 %ÒÄ àùˆï#k€��ÐNw¦È*;����IEND®B`‚�������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/back_filter.png����������������������������������������������0000644�0001750�0001750�00000001422�14517772113�020022� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��¤IDATxÚbL*¨Ýÿÿ?ƒ1/iàä¼ M�Äò÷ï?‡ÝupQv68ûÇÏ_ _¿~aøðþÃ÷ïß>}úÄpñâE333†…Ë×™ƒÔ�óÅS‡·<zÿ7ÍÂ̈áÛŸ Ÿ¾|cøüå;ÃG âù ¤š¿}ûÎpûÖM=}=†É Ö3üøÃÀ°wßáG�Äôÿÿÿ³WÎ ­hèúÂÈ� �cÿúñƒá÷_ ÷ïÝaÐÖÖf˜4o-ÃÃ;7‹@z>|ý> €˜@ŠÏ?¼åÆå“q¥õí ŒŒŒ(ø×ÏŸ ·oß`PQQa虵œáÁ­+¥Oî^] Òó÷ß_€�bº�b###‡ž™•ºŽÙê íµðp¸u혞¶x#˜þÿïg½„ÀúOß~™ûùg2@�Á €bíê“..¥0ajO3XìÆ• 3—nbû~p•!ÿƒ0ô¨� &dа nÿû÷Ðù "n2èòÜ ›ðˆáÏßÿ Æ &tîÛ}ÿÏ LŒ`üåáCæc a-Ç~<9ÉðëÏ0 c†@Wüþ 6€‰áé…- Oöõ0DT¯cøvwïW×~ýþ¡¡l€�bÁ–ÄþþýËÀÂÌİvCjÝb†ï÷÷ÅÏ™‘ÿú’Ð~ÿc� &¬�]À 4@Áµ’arm4\dH<¥Ù�„Ý€ÿ˜^д‰`àÔ‰e˜2©¢áÙ†ŸH€Ø�„Õ€@/|øôhÃO%#/†SÕúúzÀr €ƒ €PÒ ˜Øº/âà⎅†ê¯Ï߯Wýsô¢‚SºZ€�Âj�0AÉ�)q˜ƒ€ø5b%tµ��›¬GàXgµ5����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/previousview.png���������������������������������������������0000644�0001750�0001750�00000001232�14517772113�020323� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������Í£õ9���tEXtSoftware�Adobe ImageReadyqÉe<��<IDATxÚ”’KHTQÇÿçÌ\µnj“ÞyfjÚ¢QJ„ œ’¬h!”´H²ìÐrJ"1&"-\Õ"Â’E¸+Ipd(Å4ÌÆ1M6ιsçzoçJ­ʾÃÿ<àÿûÎwë Ûmzœ -L]ô_fë-*0uäöÞ«ïqk*ZŒ,ô’ÜÝæ½Ѹ§ œB[…;-d¾A]z)VWs{­¦M–¦¿¡P‡ð$\§^Þ˜Ýî©iÅáNÌ`IŠ€°6ºàסaòÛœßFëõìGœGk=.#E`EþJ(>//âñ›g˜ðH:×vÚr•¶;r ¼×êÚPæ(aÙ§@A,!â¡ÿ)^|”;Ñûj7³ˆé u˜³ÍóÎvc•,!®,³B(dxz:ž]êŽõª]jŸÑ71HƒÚŠR™Ð^ŒõÕäò™°›¨¬pwà”ë<æÄy×¶™¼¬j:ŸÒBkÞ±…OæåYÿÜŒÌnßa/ÐÓAÆ2Nºá´ír‡FN+•ñ¬¤_{iøuªòQ—G´ðæï†þàÛ*v~ZóðUšF±¹MÕ J‰}“ö IóL¹\©æÊ虢Rkùºc(¶Ø`$Êó¡¼µ †4PRý‚éÔ¸6´’+Нƒ£ûcÉ8J·Ú @Ä£þ¾´ST™Ôü©ê“]ä}Á‰Ý&!ƒïÞ?'ëøàºGàÜôµ’’…›øÈ`*Ñ'?�,ÔâbÀ����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/forward.png��������������������������������������������������0000644�0001750�0001750�00000001167�14517772113�017227� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<�� IDATxÚbüÿÿ?Êláÿ h bê[F$ñ %�@ –fýÿõî.ƒøÈâ ˆÃAbè €˜@†üý÷Ÿá÷»;p â#‹‡4±W,N Gw�@�Á øûõ5#�âÿ|~ž!´v;Ø©‚(†�Ø€?ÿþýø�Ç >ºøÏgg«׃ÄVÌIF@þügø÷ë3ƒø påñïÚåS«áâ?žœ`ˆª\’_1#^�l@� øý÷ÿßßáĉ»¿N»òôwí’mp¹ï3ÄV-©Y19†/ € �müÿŽÁ| �†ò»©{¿M»úìOíÂY}pùOO1$Õ€ ù¿ € ^ø‹š ù¡Ü^J"LÍéõKPÔL­‹f¸öìO=@�±À]€`üÖ`î µ¸ uÃ` ÂÀŒ©} ·_þ­ZxôçL€�bÙÈÈȈá ½¸´sX3L~òĆ;¯þV-9þkЋïn�3336~¿<—ëéî`¸ûú_Õò“Í 1€�‚À„Ã�˜x[k Ã= æUg~Ã5ƒ�@� �«ge…� ˜xs}=Ãý7ÿªÖ i€�beˆ"7vŒÜØ·ë'#LüÁÛUëÏýÁÐ �6�@ÆXréY$ñ{Ø4ƒ�@€�ãp“/f”Í����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/save.png�����������������������������������������������������0000644�0001750�0001750�00000001073�14517772113�016515� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��ÍIDATxÚœ“ÍKA‡›Nvó±ÅÒƒUKJ©`NšäÒ&-“BIK)½ô¨Wo‚xðcŽJ¡·B¥—–ÒC‹ö¢ jAü¸TÁ@/ I6û‘uÞ‘@ eÕ¼ïa÷y~¼;;£„&^.˜Æÿ­%Eá--ÌÀ6šxUÊ_Éúü}jä&¦ç«`ð<lî¡svŠRþ1jk˾r:;…õ„oÅA.ó8G£ÕÑlÃåÆúOAÌ™`m¹2 e˜h·;à"qõÇ߀ÜÓçh«™½�†eÃ0Mp‘þ¨Pö †XE8ä2.šmwaYŽœà×·O¾“Ï^K6(r™çq! S±{ø[~‹bÉ!—y®+_CQTÞ}„ëX¾7‚šdi‘ËÀ/˜–%_r ”¾ é ° HŽˆ ûêŽÙe€w^�‡ªªÐôœl¯àôxŠø§LßO$1’ÊÃj5è—ÐIäÐuzü6ꎻɌœföí³é¿~®nb®REL°-ˆÉ…@}#óõÃ{Äb1ÜI<Àðý1 ÝE¹““õW¹øD2Ä’CnoGÒLm]ëþÙΈ^SúïÉ5¯rÚ¹��/CÔˆí}æí����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/apply_mtrs.png�����������������������������������������������0000644�0001750�0001750�00000001171�14517772113�017750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<�� IDATxÚbüÿÿ? ø…©L 6b^ þ Ä'xúÆu«×1`�Ä3ÀÛ/°LFI­ÓÚ=€AR^™ƒá×Ï ÏÞe8ºsÓ{·Ê·nZß…n�@�1€ põð JÌ*ü¿íôÝÿ÷Þ|ÿÿùÇßÿßÿÓ >H$RRŒˆdÈ?òí<¦M˜Èðêõ KÄDE‚ÃCæõ5ä¹(^ °¿ý2ÖPSkn®)d`ddD1 ¦¹$R‡n8@� øùó'77XÀ@_[X1€äAêÐň hãÏïß¾}úò,ðã÷?  y:F4ç 0 þ+*)_»s㚉(Я¡Q©¶ƒÄò ß¾¿ö9Þ� €À^øòùóòes¦™T6u00ýû‹aÀ?&f†öº °:t9€�b€(*((4ÃÙÝûÿ²»þ_¸÷êÿ­—_Á4ˆüommý=Á``ãææ®8Tü¤Dƒøìììûòÿ¿ÿþßÁÁÅ€�bDö0|D”ó13ƒüó êÕ�PŒfff1\¿~aÿþýàÀ t'!¹ˆ/Äe —� » €p€ÃP!tC�ˆ$Ð †Ï€�bD‹V¢�0¬@†èØ��7Èp¯‹ŽJ����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/more_icon.png������������������������������������������������0000644�0001750�0001750�00000001265�14517772113�017534� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���tEXtSoftware�Adobe ImageReadyqÉe<��WIDATxÚ|SË«ÒQýù&ßO¼x5¸âBÝ.„+­Š þw[H´,js!%ȤàBТ he¹6E„$ð…¢¨øÄ÷£™ƒ?±|œÇÌùfÎwfÛíG"‘¸‰ÓCÄ]„Á!~"RˆëP(ôëÐ_pH€—áôÊï÷ß°Ùl Óé@(B§Óz½étzŠöçˆ×H´ÞàE ®?»Ýî ǃŽáp™LòùüÜÞC’©hg»Â‹@�;˜L&ÐívÙZ¯×ƒB¡�•JäƒYçr¹·hzÀa´3\| ƒBŽã¡ÙlB$d2É.©Õj l V«*•Ê­T*õUˆ—C>Ÿ£·ò„ét ›Í†Ö¼V¼ÝårÑ6DO87Ìq<C¿ß‡ÙlÆD[¯™NP«Õ˜]&“F£‰D&“‰Lwˆà” «Õ Úí6KûßÇ÷ëX,‹¤R)mOˆ€£HDÀãƒ÷¥ŒpHˆ 4t”–R©„h4 óùÆ>r8fÂQTòY.—0 Èô›¾¡â·Ie±X ¤ýEâ50›Í`·ÛYT>ƒV«E¦ïô  …‚”柰X,þ"‰DìŒ"“æl6KìïùJ|áp8žy½Þ}ÐOôz=–V«e?À!V"”J¥7X‰ùJ|Y.—Ï0Ê%± M(õCñ¨”ѪÕê<zz¬™.qzçt:ÕÔr¹œeCÏ£†*‹c´?ÁÈ×G»qGr‚Óý];ŸîÚ¹Jb#>âåÒ¡ÿ�6¯DwµŽ•©����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/forward_filter.png�������������������������������������������0000644�0001750�0001750�00000001432�14517772113�020567� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��¬IDATxÚbL*¨Ýÿÿ?ƒ1/iàäü‰Í�Äò÷ï?‡ÝupQv68ûÇÏ_ _¿~aøðþÃ÷ïß>}úÄpñâE333†…Ë×™ƒÔ�óÅS‡·<zÿ7ÍÂ̈áÛŸ Ÿ¾|cøüå;ÃG âù ¤š¿}ûÎpûÖM=}=†É Ö3üøÃÀ`kçü €˜†<gfa¼zñúC/W6FF°íŒPøíËg†Ÿß0ܽ{‹ACCƒaâÜ5 îÝ.zòàÆ^!‰¥�ÄR|þøá-7.ŸŒ+­og`ddDÁ¿~þd¸}ûƒŠŠ CϬå n])}r÷êJž¿ÿþ2�3Ô»ž?~ø€‰™ñâ™ËwÃ<]ìšÀøéãû <<< æ®føÿï?ÏQCÇúæ^?ýq F´å°võI—R˜0µ§™á@½2FПøiýïñy>Æg÷®Å šü†¿?·ÿýûgÐú?ÿ3DM~ –X–+ fÿÉ•eb{¾¿ª{Û—]@á�Ä„nÃÑ}»ïÿùó‡‰ èÿ?ÿ~<9 Æ0vXË1 I–¶¹É*@å_ˆ Kùýl�ïßÿ~½ºÁPö·»{"ª×ø+¦Çñ‡6þþýËÀÂÌÄðã÷?†¿__‚1ˆ½`b˜ýýþ>†ØÊ… ±�„Ý�  ˜¡ÀÈN­[ çO®f¸ôøw@�±`5àß?f ~"�bÿxvÌž2©—áΫ¿UKŽÿš@X øô‡O_Á0v__ý×ÿªVœú5È}@ŒØ 0¶q[ÄÁÅkÁ°CîÁ›UkÏýkñˆGV•bqr÷`šA� À�LD±gƒÈç����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/goforward.png������������������������������������������������0000644�0001750�0001750�00000001235�14517772113�017551� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������Í£õ9���tEXtSoftware�Adobe ImageReadyqÉe<��?IDATxÚŒRmH“Q~ÞûîCmN7× ¥›eŠD4ÂÀ5V‚IX4T¢ˆú}‘ÕÄ(£1ð‡D¨9J$.ŒEJ},¨2Ý`9uß«wï{»a;ðÀ¹çœçœ{Ïs¹µ7‰€…ážÿ¼ôÙ˜®‹Œ ¸Ñ÷Ë(óo1hþK*¾Nèløu'èŧhI—’²XÇjBE€BB$ÀÑÚØšû°­xû]íò¡ö_$>¯;P_fÔç*8D…¨•*4˜ SékÞz§Oʉ;éøŸ¤zN˜ÜLD4º- 2!!€ ]%LUf,D‚»ý•ž]¬y4þ’~Θ3xE³žŸÏ¾=ß™ø!¢Jo@RZ!"77¢z]MùÌÜûæT]”&&¨“[1µ¨±^u˜X´¥…'zuƒÊ–A8j¹áDm¶N£‹%²ßŒ‚³|uZ¯†MFsç¾VÜwP‘fHv÷0¬Î!,Å–/…nKó™IêÓü M~Ñ…3Mí0lг…!# ‹°:†0õáÓXjŽö'F$+8UßcªÛoiÝs1É´�ì©°O:1èGÌ—ìŽ÷KwXЛ&¤‡pk,<}}m_C.Ö] ß‹ÞQ;<_æ %«0C]¬.´rå²´¸`â ¢ˆ>‡£Soò‰W“ÃÒ–ðe’[nÿ´Çu™–ž+¢9Gx—­,œ·êßË9Î7)[x§|/igGmúÊÈÒÊÙÿ`�ë幫 W����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/class.png����������������������������������������������������0000644�0001750�0001750�00000001333�14517772113�016663� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa��� pHYs�� �� �šœ���gAMA��±Ž|ûQ“��� cHRM��z%��€ƒ��ùÿ��€é��u0��ê`��:˜��o’_ÅF��QIDATxÚbüÿÿ?CÇ´%ÿp€ÿþ1011Áh¿Š¬˜ÍÈò�ÄSì‡Õ€?~0\¾z!ØË‘aõ–½›Ú¦,ò«Ê‰ƒ@L0^}øŠ¿xû‘áÇ¯ß ¯l ) ÑM-“øÂ � ˆÿ2012âÄ?þaxûé;›š˜0üùý{Ì�€�{áï? LŒ(Nÿþh'Ã}‰ LVÓ¾ýaXµv=Š<###30üþØÿ@ €áo÷1¼Û–È`WxŽá˾L%žç †z:`lb¨ÇðéÃ6f@þþa`†4 ß_Ãà”0•áû5`úýž<q 0c`a8D� Ì� Í ÖAœ÷/ŒáCW6CpX>ÃñùëÄX“~íÙÀÀoíÂÀ&&ÉÀT r>H-@� øóèf&†ß¿~2Ôå§0|þèÇpq¿.ÞµûL]b´®íßËðìÐNÙð$°z� h�]�4à×ï 7^~gxúƒC;’éŸ(ƒ–„ÃõË`úùÅ3`u‘ � ¨þ2°±03üøþáýw¨$+Ãýl '÷îa0WSa8yë—ªXH= � Ìl¬Ì`,ŸÑ —äe`Ðdãa8°nƒœ‘ƒ_0X² �šþ1°¶bb#1�¤�ˆ–YX˜ˆÿ¼�@ÐÌô—¡ ¼ž�@Œ ì L–Ƥjê; ¢ �W@÷k6ð����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/fileResolved.png���������������������������������������������0000644�0001750�0001750�00000001275�14517772113�020206� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEÞ./•üM+��JIDAT8Ë¥’OHÓqÆ?sjË™1d¥Lô¤BÇ ?'É !ebâ(áé`ž:„¿!402­Ã<˜2‚Œ¬“yht ƒòÃÚ4Ÿ.¿ÙòP_xy_Þ÷û>ïó¾ß×"‰£HG”â¼ …ê€u ø ”�¥@È¿�à�ª½^ï'�$! Ã0ê$Y$Y%•²V3WˆyÒõaÒõafêÃ4Ž6;ìû¹RÀøØýtòsØïL9‡›ž_ÛÏr¿¸à‘Õ¤ºÈÜÍ´§ç»ßO&ÂÕË=k¤vœ­©G®28X [lÎox×=ób9\³Ô³j]Û]"§ —GΓK3UÈ H�;ccc“ÉÕhfâõÒyâ}_ù–ý�À‘»ìm0•zL® Í® 3® òG=’Tf.Öázä ¢ÔnB±Œ¡XÆ+ˆ.=jP% N?äÍË/ÃZÏÅU5€úg=iI5ý³ž•ª´ž‹kn{HsÛCª@ícît ¸ÿ=œ>Ë„Ýò+™]”Ó‡L{äô¡dvQÑ-¿¢[~9}¨mÔ=žL&m†a4�8:ˆTö¢éM¯¦7½ZÍ.¨²­fb•½èNؽ’L&í’,†a\ÌX€ÚŠ6žÀý,Ø À¹²[,ïL�pop”3ÖFšN^ow8oÍ)òz½©ƒKjË[‰Tt¡W·´¢ •·jóëjËZˆØ;Ðø÷›²w ²–ÿ±¹‰oC6÷ÿ‹%ñ§ŽÁƒ����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/godown.png���������������������������������������������������0000644�0001750�0001750�00000000731�14517772113�017054� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR������ ��� G×\���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� ÒÝ~ü���tIMEÝ f§Rå��fIDAT(Ïm’=/CaÇ4 âØ•­õr㈡&ªé 1]Óí "‰zH#¹è eÒ{wÒÄ`pƒÒŠÆà.mª÷INòäÿüçœçä¨ôq¯­Ü•‚¬™¨óøRûQ)•*BKó7Á±8¾¦võ§eNÖ%µå¿Ï°¸¶\M×1Al¼ $04ª®Ï’>ˆ¢ï=ÃÓnÅ››…ì¥)F‘‡7WDÊy1BHò(ó®þë1BHöÒ>KW™ß÷ájo\­xS£!ä*cÊgÉA}�r–-úˆÛWc´CᾞÝVC"&Ýþ. JïNå9˖䦆>?X7ÙØÒ9ýÓU@ßœSβ%µ¥¡ÏôTÁÕ[‚áZ@½œº*9Ë–ô¶†é$¶qGßT=  ¯Žç’X–-™ÞI¿ ^_¼a�˶Åßå ü�|±Æ–¯úŽp����IEND®B`‚���������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/races.png����������������������������������������������������0000644�0001750�0001750�00000001437�14517772113�016660� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��±IDATxÚbüÿÿ?Êlá8†B 6�â @Ü1õí"$€K @�1.LŒT]¨ïžÍ ¥aÃðìÆ†‹;§2|x~;>næ;°!‹Ò…pª ¦¯?þ•jZ1ñ°2|»·Lƒø q˜íøÔ�˯?ÿtDxY~½¾w®/?HÆÇ§ €˜>|ý{ëÑ­ ÌÌLp âƒÄaŠñ© –GoÿÎ?rüx; ;ƒ¬š:Ãã[7Îm?Ï ½ñ›ÚFÆÿ ¤øûy„ ^€�bÊ ‡›±fKð3E³13¨ ýy!pà©DpM r$0¬miaøà ýâç[‰_þßzññßÒ•§~O †¸¸¸¨˜¨èÃ@5šÕµ“þ?/*úÝÛûÿ÷ïßÁĉä@j@jAz@zˆéçÏŸ5?j¦‡ë‚7n4&'3¼:ïýë× ?=c$’©©éé š‡ÞmP”=ËðáÓ'†?_¿2|½~ŒAlHîÔK = ½�Ätâ3OOÏ Ø’@âß·o ÿþü+ú|æ ˜þ÷ý;„þý›áÔ�^€�bùøñóT..ŽjS¢Ÿ?¸€ÉûË¿ Ï,€"ÿ¿Á.�ªz£úÛ·S ü¦&f™œ\I,Ÿ>©ê_¸À¦¬Ìð h€öuH¹ª©ÉÀ4`ÖÝ»  þðñÝþþíǼÓgNM FPfbddäªf. àjòáCw“¥%J4ÖñŒ€@éÉv¹ø=PïG€�€ €†q9 «¼EÍw„…ãö½}»¨þ²8@�a�3×hÂ×Ñ5ƒ�@€�Ķ‚ðÀ¡����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hollowArrowUp.png��������������������������������������������0000644�0001750�0001750�00000000477�14517772113�020412� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���à‘���sRGB�®Îé���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs��œ��œ”SÝ���tIMEá3¢¶0²���tEXtComment�Created with GIMPW���šIDATÓ…± Ã0Eß¹t‘>K×$…dy • ‚Á3h�Çn“F i•"RbL ¯ùŸÏãà$„ À 8 0ó¦)ørÆÔŸ›"])yY®SU¢÷ãm/e!c°ÖÒuÞq+}¥�J©,N�✋mÛ¢µfÏ0 ô}ˆHäÂÚ¤×/i+I¹×)ï;§~q9pxPºæ����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/removeBlank.png����������������������������������������������0000644�0001750�0001750�00000000202�14517772113�020015� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���¹·7Ù���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß&9ZØL���IDAT(Ïc`£``��|�‚dX����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hamburgerBlank.png�������������������������������������������0000644�0001750�0001750�00000000202�14517772113�020474� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���¹·7Ù���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß&9ZØL���IDAT(Ïc`£``��|�‚dX����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/compareAbsolute.png������������������������������������������0000644�0001750�0001750�00000000425�14517772113�020704� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������¼—���bKGD�ÿ‡Ì¿��� pHYs�� �� �šœ���tIMEß T¸¦ü���tEXtComment�Created with The GIMPïd%n���}IDAT(Ïc`v€Ãï?C€ß¿ÿ ápqG¿ÿ~ÿüá|¿ÿ…~ÿÌ졚 |GŸÁ‰Ãƒ,ÁÀÀà„ÂGâ¤2¤!IDûýg¨Ç¦Ð�Í< ˆŠ`€ßùM¬(Úå>£¨€yá">~ÿýþ3¸ •È�Žf,Üþ)´á����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/expgroup.png�������������������������������������������������0000644�0001750�0001750�00000001657�14517772113�017440� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��AIDATxÚbüÿÿ? ¤—5OR™ ˜`úÌ®Ú,,â �Ä�2�†SŠþ?xÿïÿº½'þÏX¼öÿú}gÁ|8²:d @L0ƒàÓ‡÷kfÏ_Ä ©©Ë`çæÏ ¦¥Ï�âƒÄAòØ�@(¦\|^õÿëϾþß}ã;'Ô€$äp¹� €XÐÌ{üçÏ_0ã÷ß¿ L@;ùÙÿ2¤•6=†Ö0 &dÑð´’\%%e0ûÏï? o_¿føü›!<µœÁÜÔ„A^JœÁÇ7áïß¿ð€ ° BSФ€T®ž^fXhÃ÷ßÿ~ýùÃðîý[Nvv†ÅS›b³k Àì/Ÿ?‚ò�ĘǤ뢣cÒuuu~þùÇðõÇ_†ï_¿2¼{õœá#+Ão käy2Ü~Ë�f322³FgUX-=@,¿ÿαwpJ—g;é'Ðöß~1<}táɽ ®Ž¶ úŠì Üœ@¹¯ -e1 ·.óŸ½ùÚO —_� 0в\ôþ1ˆŠð2ˆð¼bøøç9ÿ÷ ç<f01tg�üGáÙ»ï ?~þb8ùB”A™™ÁJ…%ìàõ�ˆ ’ ›E™Ÿ2ügPb`gúÍðùÛ†“×0´ù21A fý¶ŒÁHô/Ãç?| ÷¿þcþÏ�´< €€.øó ¨ŸdÇß— ?þ~g`ùtèW6†¿?Þ ff`ÿËÍð÷ëK†xêø%˜þ|bø÷÷?@�1‹H)¨Ê ü0`eúÏ Æò¨é ÃëÏœ î^c¸øI“AOêßï{ ÿ¿¼a`zsh++Ã‡ï¬ Wo?e¸òè×€�bfeçxrõñ_!-V cÞ¾û´é?ÃÛ?n^¿Îðð‡8ƒ$û7†wŸ™½üžaëu~† ÇÞîyøèy'@�Ò7›ŒŠŽ°„l:##“È;ÿþýcøþåã ff–œ<|VLÀ¬ðšsýü¾ãë§÷ónœ=´ €@‰”‘Ø@áÄÂ@ÌŠ”8Aáóˆ…`YJ¿â×@½_� �Ë�”ÃÜ ¶‡����IEND®B`‚���������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/compareDelta.png���������������������������������������������0000644�0001750�0001750�00000000362�14517772113�020157� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������¼—���bKGD�ÿ‡Ì¿��� pHYs�� �� �šœ���tIMEß/7ì~ÿ���tEXtComment�Created with The GIMPïd%n���ZIDAT(Ïc`²ÀOÆï1ª•– Çñ(ôûO¤B|&2bš¶‰Ñáƒè¦_È YÒ ~ÿ7A41\Ýô ¦"Æ‚ÛâMŒ8Ý—Âp!.ÏX2œD‘ �vŸÉŠ»h����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/find_prev.png������������������������������������������������0000644�0001750�0001750�00000001405�14517772113�017532� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��—IDATxÚbüÿÿ? ø…©L 6b^ þ Ä'xúÆu«×1`�Ä3ÀÛ/°LPB¾SÅÄ_L†…•áÏïŸ _=a¸sæ�ÃûË·nZß…n�@� póô”TXkåÍ`¬­Â #+ÄÀÁÊÌðã÷_†+ß1œ½z‡áØ–¥ ïŸ?Þµ}+ŠK�ˆ Düøñ#_ÛÂ…Á\WÁ@A˜…™‘áÏ¿`ĉƒäAêÐ]�@`~ÿúe¬ª¡É (ÆÃðûÏ_ Ƀԡ�@, âçϟܼ¼<`ßÿa +<Hº8@�11ÁÏïß¾}ýúáó? —7w1¬NçÓ?~ÿc8H¤¤Ù�€�bâE%åkî\7aººˆáÙ®V†Ü_&Gð0€Ôjx•2<xý•(Ïðíû÷kÿ‘ã�ì…/Ÿ?/?»¢Ñ„ý<CþÜë ?žœdÈœyab²&ÃÛÏ¿~*2l^:¬Ý �ŽÆjWÆn6†ê‚)û~½º —dÓf˜ãÄpþ·>ÃÞ3´´´Ž9‚â€�Ç #Cu~ï†ï÷÷1üýúŽA|¸ÃE†÷ïß3ìÙ³‡ÁÑÑÅ �‰FAõWÍY Ý--(ÎñAâ?øÕÞ¹-œœœ ššZ(†�4Lô€Ø¸Ð–áÿ›½5p âƒÄ¡òâ@\Äÿ33³þ;88€Ã €˜ †\⳿~£ÿ$• šÄåÓ§Oƒ» €‘c%ÉMî(ë‡ÇV0þ_Ù3sv=2E uFF! •Ä �„b�PRHñ#©ÿ ”¿…uC@Þb�0�‰6ø~8»£����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hamburgerFocused.png�����������������������������������������0000644�0001750�0001750�00000000243�14517772113�021042� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���¹·7Ù���tEXtSoftware�Adobe ImageReadyqÉe<���EIDATxÚblllüÏ@"`OŸ>e$Vƒ´´ô&$þ^ þï…)DÖô‹€%¿PœžÄ:qÔy”8ˤ$#€��Ø(´O6r����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hot.png������������������������������������������������������0000644�0001750�0001750�00000000461�14517772113�016351� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���Kpl_���tEXtSoftware�Adobe ImageReadyqÉe<���ÓIDATxÚbüÿÿ?`dÔÓÿÿ_F—bBR¤ÄPž 3€Å`€¸(602ž’kàŠŽ�qÐ&¸ rQ 6b! N{ º Å 6H *R# ÒÀ Ä9@ü¤àŸâkM j˜NbdT’'/00ðÿ…ÚÎ Ä ”9PÛM„§3AŠß�³#…ˆ ÉAÕ€ý�sŸ4?HÃü‰JçäJ´P j3D„P ÄPvCØ`9¨:FRc À�Ð{VÙu9����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/color.png����������������������������������������������������0000644�0001750�0001750�00000001640�14517772113�016675� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��2IDATxÚbüÿÿ?:î•t�R‘@ìÚ ÄË×??€® €Ñ ì’HV“6žcªæÆ -o»úðÃé[»n==›²¾ìÅ\dõ�„b€_«˜ƒšŒÑ~ë>Aa†¯>ŹYø>½˰åè†[OÎ9nª~w @�1!›öëûß8-%K†?\ž~½Ëðáçk0±Ab 9d=�Ä‚Ìùûç¿›€¨ëï1Âåóï÷ 9dq€�‚{ayRŒÃMÖÇ[U9¸þ(r0üÒäbxËÎÃðæ>Ãûg¬ @¥ï>]ùÆÍ¢ï½¤µì €�°86<Y\U}Ž¢‰)ƒ”–6ØÀg×®2\<sžá. /ƒ²•ƒº¢<Xüæý‡ ç®Þ`¸ûèIÊÊÎò¹��A�¾ÿ×Ñ@#$®4MN� �ùø�ýü��ô �ý� �ñ�óü���ëíîN–©³ÁˆéË÷oq Ú: "¬Ààxý‚áÓ0~ù胴 ?ƒ°¬ó+—>ýüÆÏ>ýføÅ.È ¦¢Êðíë·8€�bùó㇛Œ˜ÃÛ×(öæÝy>An.n†Ÿ¯Ÿ3üùˆî¯¿ÿ2ð‰Ê0üøùÛ €X¾ÿÎøÿ%ÐfNNþýÊðëË7†¿À0úùã0ŽQÜÇo¾ÿøÁ@,ï>>vûòåu5¿3|yýŠáí÷Ÿ ™9XÐ ¸ë&ç³<';;ÃÿI>f M?Á˜hÀÕ—¯î¾zÍðZL“៰Ãï `üâùS†ë§1<»{½ ��A�¾ÿÕðóâ öôüøôó?ýöö� �øõô�ÙÛÚ�ÌÖÖ�½ìù�ì$� �÷÷÷�ÝÕÏ�×ËÀ�ÙÍÃêκ¡œEœ…ù‚¤9ØÜ9™˜,ANüþïßñ»ß~½À«ÀÀ.*oÍÈÊÿÿûÇñß_íü|çÔ: Þ7�O‰@Cx”óA½ ÊIï l q ¾Ï @€�Úë^Lòþ3^����IEND®B`‚������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/base2.png����������������������������������������������������0000644�0001750�0001750�00000000401�14517772113�016545� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEà 9äwÐÙ���ŽIDAT8ËÍ’!Q D_7?›,áj @¬ C‚@๠çà „ìÿƒù ÝŒªétò:p^͉* YìN÷òu¿ÆjM‘À ”�rï×Ó}=Ñü†ˆrÑ„ 6ÛÞÍà~»È�ŽË™>ƒÜm2fP¿�€ü•A×6á&þI‹n\�‹|ÏÃK¤šåy¸����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/delete.png���������������������������������������������������0000644�0001750�0001750�00000001411�14517772113�017015� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��›IDATxÚbüÿÿ?2H/ocR>}úÝøïß¿Zc³¥|S^zâ4�@Œ0€§©L&&& F†ÇŸ18Ûåö>Ï #'‰¬oúÌΪ, €ÀDgU€57653°132°±02<þ”áÇï? ¾|gx÷ñ3ƒ¼´,ÃçÏŸ¾~ýư~íj°!K§udØ�Ïð”ÿѱ Üœ â¢Â ¢‚¼ Ü\ _¿ý`xýþ3ÃË×oÞ}øÀðãÇ Ø7†ÿ2;rˆá÷ïßÜ�Är…û*v®˜óñVVVF†Ÿ?¾­¹pdg@�]ÀÈÈ(ïÿÀÙͦ?þ`øþí;Ã×ï_~ýø7�dÉÝÛ7v¬]¨�Ôû €˜ âø…Å,ÍÍÔÕäNüÉìÇ`miÄ ,$ÈàêîÆ ª®ÆÀÍËà )£À�R Ò"�f�Ã_ ¿þ\óŸ‘áñ³g ¿±013<ù’“ƒ‹èÿ/ ÿb µ0�@€~yä…ÿþ Ò ÿ¡þfcHij€ÕÂ�@�¡º�¤ªé?BÙ™‰…•ÌfãàDq@�Á øõ,a(X{ ì) wþ �@H.ø÷ÿïý®éÿ¿ÿPïýóÁÞag©…�@,H.`\ò‡áÇOf†O2^ ý>}cx'íÅ0ÿ>7Ã×/À”(!Àðê³0Š �ˆÉ "Ì ÜÂB \J ¼Üœ@o½!öÖ篼À4ñ ˜€þ0¼Er@�Á øøáýšã3KCˆ�?¿]c<7S£e ¼ê'$€��À“+*¯˜~����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/sample.png���������������������������������������������������0000644�0001750�0001750�00000000714�14517772113�017041� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��^IDATxÚbüÿÿ?CYˤ' Ò ¨àiWMž ˆO €X@¬ÿJ'{¢ÈÎÝÚ×€O €Àüý÷áÍ3TãAbÈìw/±ËÄ€¿>@S�Cfý„] € üùÃðý š‚?PØ?¿a— °€œ`½( vÝC�’ÿùÕ€?P�n�ÃÃ{XÀØ!º¨l¿ ‘ ¨¿Þ¾F3à7*È<@�A ø ä|úˆªà7’ ~c±à7Ä�€�‚p.ÝUAå&TÅ@ � x¼úöoœKwE•/]¦Ÿ~¾ÃÏ¿`€�‚&¤¿ ßÿ|FK(QØ~¾Æ*@ð„ôãÏW¼ éëïXåæ…WkŸ‹!+øÿïß+$ç¾ZÓð«<@�1‚²3##£ÍŠ–]å.á‘0�UÄ÷V_}Η����IEND®B`‚����������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/func_item.png������������������������������������������������0000644�0001750�0001750�00000000533�14517772113�017530� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<���íIDATxÚbøÿÿ?>ÜÑÑñŸ<@�11�ÿþÅ+@ øóç^y€�b9#¾aæ] [‰tp €XÀÎüóG©&7‘dÝ-“ç+؀߿2<ýø‹d@ú�bÀÏŸ Ÿü%Ý� >€�ðëç†/¿H7�¤ €àüùÇ@–�õÂ...2¼ðƒ €ÀÑh”ö„‰™YšTþýýû €À022ê�ùìØyxxœÙ±c‡ 3~¡¼Ž7/�Åy €ðïþè ‚^�5|ò��+MÜ»ò[úÆ����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hwc.png������������������������������������������������������0000644�0001750�0001750�00000001233�14517772113�016336� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��-IDATxÚbüÿÿ?Cpx”3C&ñt > Äþ@Ê�«x#[CÕ­©[»rÙ^€�bÉþýû7/"<ÌOC]¡©¥-S_O/SUU™AUE¬ûöÛ¡·oß ½xéC]MÛ·‚W¬\Å ”Ú @`üÄÄÄΜ=ÇàÏ )%ÅðõëW†{÷€ àááe°±±fPVR«QRRëÉ#»zx¯âäâ ±·³ckúýû7ß?ÀlVVV0ûÝÛ· bøþíÛšÝ;¶† 0 þ»zz?±´´`¸ú÷ÃÝ;wðe>Ú½{÷>é ˆ ¬¶2Ò2 g>œe¨ ªÂkÀôí³ddÀz@|€�bÿ×çååfàýÇÃpñËU ÿ±jÅ/H-HH €Àüû÷åÏŸ( ñZ €X€¶1º¸{1üý÷A…E…áñãÇx5ƒÔ€ÔþûûäRF€�‚¹�,i)aÁ@p10¼yû® € üs€ „ ""×@LÈ.�Sc#0ÆÇFÖ@p/ÀÂ}í¦-`ZNZ '›É�€�b„ê߇Ÿ¿|‘gcccPVT@$,lf Z° €À)QßÈdŬ™3"˜˜˜ä‰  í¿ÿ¾¤ €AqŒ q ¸(³3~ñk Þ—��‚ ÚóÏ!����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/oldexperiment.png��������������������������������������������0000644�0001750�0001750�00000001353�14517772113�020437� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��}IDATxÚbüÿÿ?:(--¤2Aìß¿3üýû—aòäÉŒ X�@�±`ü÷ï_f}}=ÃÅ‹^¾|ÉÀÈÈȰ}ûöÿžžž†�6>|ø°fΜ9 jjj òòò lll Ø4ƒ�@�1€¼€Ž@.77÷ÿ‰'þ¯^½ú?L<((¨]-@�1á0ôÑŸ?^½zŶd ßtµ�„Õ€ôôô\eee111†+V€ DvvöüÄÄDdµ�Ĉ ÉÉÉR@ªFOO/3""—/_fxýú5C\\Ø%III€Ô„yóæm�ñn@||<?Ý“®¯¯Ï�òÂÏŸ?Þ¿ÏðüùsPÀ2�åÀ†$$$ªõ[¸páG€�‚{¨!ÇÖÖ6]BBÆgøþý;Ó'OÀ.€iž?þ;z €X Èâàà�Ü—/_>~üÈðøñc°Íeee`ÍÝÝÝÿAQ  õ@¡V€�‚»�˜Ú$a’ ƒ899~üø×Üßßÿ$ X`B«‰²¾ÁØ¿~ý{>íííà@*,,d|÷îÃýû÷ÁÃÔÜ€OŸ>­zóæ ÃÇÞ¾}ËðíÛ7)))°AMMM`C€É›d8X=H €à± ¡¡a,))Y‚È" ƒ@á� ÐÎÎN°wÏ^¿~=íÆgn�0𪨨c!‹‹Ëȃä3¬[·¬9 à0zîØ±cPïo€�BIH C€”(‹�1+Zò> UJl¯AšA|€��FL9‡~3{����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/blank.png����������������������������������������������������0000644�0001750�0001750�00000000300�14517772113�016636� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���sBIT|dˆ��� pHYs�� �� ÒÝ~ü���tEXtCreation Time�04/11/08a•”���tEXtSoftware�Adobe FireworksO³N���IDAT8cüÿÿ?%€‰"Ý£Œ0jÀ 2��cš¶<4º����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/warningNew.png�����������������������������������������������0000644�0001750�0001750�00000000515�14517772113�017676� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���sBIT|dˆ��IDAT8¥‘!OÃ@†Ÿk #$˜©  ~š_CRC1 I³8fÅ�ÿAHp“$H–lm_éèz×+„'9óåÞç¾ï>#‰*Ã]£<ƒ…ÅŸZ’ÊЄ¤¹s¶ƒ¤#n¡’4Ai‚êw%Õ…EL2²¸[ÇU’ô»Ëó=£zG–`Fµé«>t?œ¢f‹›tÍœ(ø“ äu0Ü>øFðoޏ¼öŒàÚ[|ü2 –5[`€ b<©/FV°Q``tÂÓćŸÀ½3Xâüļ€Ál¬»_mH0Í`šû¢AUô/Áo°QQ–:†ík Ïï°½ÆÀZ¯]ð~Š{|£?<����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/tab.png������������������������������������������������������0000644�0001750�0001750�00000000665�14517772113�016333� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������AÄ”���sRGB�®Îé��� pHYs��œ��œ”SÝ���tIMEÜ ); Èi���tEXtComment�Created with GIMPW��"IDAT(Ïu‘±n1Dß®×Gàr 4DBâÿ?†ž’‚ê* Bðy7Åq DÊ–VòŒŸgÅ#ÂU=T �á9ˆ@¨Âí6Ð4†\¿nì÷{Îç3¥TâOŒÄtÜgÞß;Öë5Ûí–¶`ú¾g¹\Ò¶‹öG''ÑÁP "ãƒ}ß3›}`¦#ÙñxdµZ±Ùlh_ߨ�¡?vÅŸH³%Ürý¤ÖŠ™âÎfft]Ǽ]@"D‘{›åz¹\0347ˆØ"`e(ìv;J)¨*Ž ! ‚üíî>7MCJi\–þþ@†ˆøN§)%j³fAÈÃ¥;áDæîäœi²Ñu-&a“i¨NJ:mÿ¡³‰ìY·â¼d¥”JΉo¿Tw¹ì2N����IEND®B`‚���������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/percent.png��������������������������������������������������0000644�0001750�0001750�00000000676�14517772113�017227� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���rëä|���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß'I2 ��KIDAT(Ͻ’!KCa†ŸïSƒã¢0"cedAvÁp4ÈXÁ¦‹AMþa`[ CÛŠ\wV¨Í‹aX bÆÂöYî`Ì%ƒ'žó>¼ç¼ø¯2"²˜J¥îÛíö|&“ùÃpUUßYÊ€¨jÀ7±Xl¦V«Çgë!`"À�ò}ßN$är¹`%MU}^ÏOÕjõ«Óé”*•Ê;ÐRÕžˆ$àlô& ì�ÉB¡pçœK»Ñì8SÕÏ_AŒKGD6Œ1'Fc]D–Œ1Uç\ÎZûØï÷·íÀ.œsûQë&NÏÕëu²Ùì<pmÇ·ªú*"ÓÀr±Xœò<R©ä¾qñMà@U;@+‚^·Û%‚o 99âRŽ#ñ ¶Â0¼Êçó Æ˜W`ïOoô/%r–p4ÓÆ����IEND®B`‚������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/small_down.png�����������������������������������������������0000644�0001750�0001750�00000000224�14517772113�017713� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������—SÆk���tEXtSoftware�Adobe ImageReadyqÉe<���6IDATxÚb466þÏ@�01#5ŒL0.`âÿ„m&&&pΙ3gAŠ1Èèb��²L" kM˜—����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/circleOrange.gif���������������������������������������������0000644�0001750�0001750�00000000131�14517772113�020127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � �€�ÑÃ’ÿÿÿ!þCreated with The GIMP�!ù ��,���� � ��Œ©kྞL²¢:~wƒ¾QX”1æ�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/compareHamburger.png�����������������������������������������0000644�0001750�0001750�00000000327�14517772113�021043� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������µú7ê���bKGD�ÿ‡Ì¿��� pHYs�� �� �šœ���tIMEß0 ÆìÝÊ���tEXtComment�Created with The GIMPïd%n���?IDAT(Ͻλ€ Eѳ´kb$´k€ ¸#3Š7}_–pŒ{±Û7{"v¨#?~(pFn˜kxõá.:š~“Ç����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/find_next.png������������������������������������������������0000644�0001750�0001750�00000001350�14517772113�017533� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��zIDATxÚbüÿÿ? ø…©L 6b^ þ Ä'xúÆu«×1`�Ä3ÀÛ/°LPB¾SÅÄ_L†…•áÏïŸ _=a¸sæ�ÃûË·nZß…n�@� póô”TXkåÍ`¬­Â #+ÄÀÁÊÌðã÷_†+ß1œ½z‡áØ–¥ ïŸ?Þµ}+ŠK�ˆ Düøñ#_ÛÂ…Á\WÁ@A˜…™‘áÏ¿`ĉƒäAêÐ]�@`~ÿúe¬ª¡É (ÆÃðûÏ_ Ƀԡ�@, âçϟܼ¼<`ßÿa +<Hº8@�±0––ö·¯_¿qmëførsB“ºƒSáj†_þ1�å~~ÿö ¤þ?RÔ ˆ£¨¤|íÑë&l×·1䮸7`r0˜¼þÊ�”gøöýû5dÍ �@`/|ùüyù楳M|¹€úä$\ò׆‡o¾1<zü„(V‡î€�Pâ'Uò÷ÅV`€5½º—ñ÷ç 3ü3b¸rö>ƒ––V/P¸Ù�€�§ƒz7Æÿe“6€~<;—ä2Ó]y M»¾ÿÎàééɰÿ~F˜€�GãõW UÍY(ša†ÄO<d˜ ä¶prr2hjj18::Âà € a"¨ÃPYhËðÿÍÞ8ñAâ y â2 þŸ™™õßÁÁž�6�fˆ¯Ce¶Ä âƒÄ‘Ô¡@p`†xª1T¦™2üÑÈš±" ð €Ñ¢•˜N@ÎUâû@¹÷X³0##È= À�O¬2¼çŠü����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hollowArrowRight.png�����������������������������������������0000644�0001750�0001750�00000000443�14517772113�021074� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���à‘���sRGB�®Îé���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs��œ��œ”SÝ���tIMEá2A¢<���tEXtComment�Created with GIMPW���~IDATÓ}ϱ Ã0 À÷©¤Þ‹Ô 4­ ñ4DMì <�SÙp Å_‘ÄO´Öš@ïë£÷õŽsHšsîQJɼ÷;<gÚAŒ#8A—(çŒZ+.;©ê°Óþª¾ñ'$i¥,Ëë¹çùö9¢/°Z7'uו����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/zoom_in.png��������������������������������������������������0000644�0001750�0001750�00000001233�14517772113�017227� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��-IDATxÚbüÿÿ? ø…©L 6b^ þ Ä'xúÆu«×1`�Ä3ÀÛ/°LFI­ÓÚ=€AR^™ƒá×Ï ÏÞe8ºsÓ{·Ê·nZß…n�@�1€ põð JÌ*ü¿íôÝÿ÷Þ|ÿÿùÇßÿßÿÓ >H$RRŒˆ dÈ?òí<4%DyX"ÿì½cÀ4ˆɃԡ;� €X@Äï_¿Œ5ÔTxÙ˜~ÿù —„±Aâ y:t�lÀÏŸ?¹¹¹8þä”—ôJÓ›VÏe�Ƀԡ�@,Œ@ ¥¥ýíÓ—/\¼¬ -µE`‰šæ>8ûûÏ¿ @y†Ÿß¿}©ÿu�Äâ(*)_»s㚉¹%ƒ¶Ž6Ütûã·ß @y†oß¿_CÖ �Ä/Ÿ?/_6gÃËçO¾ÿúÇÀÌÄİeí0 âƒÄAò uè^� ¨¢‚‚B3œÝ½ÿ/Û¸ëÿ…{¯þßzùLƒø qAAÁÿÖÖÖÿÑ£ € 9nnîZ3@Å_A@4ˆÏÎξ§ß¿ÿïàà€b@�1"{ >¢@J ˆù€˜ˆAñø ˆÿ±·dff1\¿~aÿþýŒ =�Ä€î$$1¢ñ…€8ä !p—�Npʇn@�‘d�º!Àðù@ŒhÑJ�†ÈU À�â¶~‹hIR����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/caller.png���������������������������������������������������0000644�0001750�0001750�00000001104�14517772113�017014� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��ÖIDATxÚbüÿÿ?%� €X`ŒØÜši@*ˆ§/žÜ’o˜yH)áÐ €@.�áèìªÿ¿ÿüý¢ab ZÜýÿú‹¯X1H €à.ø÷ïÃ÷ŸÀ42øôá-ÙÇ_°Z’ þ1ºß¾~:½£V›ÿþþ} @hüÇ0àù@ŠÄNII93gÎ$éŸ�7àïß¿ þþÓÈ`NåŒË?~„ó{³:ÏÀØüüü �DЀW¯^1c ƒÞÞ^€�"hÀׯ_îÝ»‡Õ�@�!ð‡`0222Ìœ9«<<< �Äâž K@p�Å@ÉsúΕ³³Z–wèÂÑÓÓóÌöíÛQ €X€2WÍŸÊPÑØ 6@^Vš¡£¾œ!,1dhz ºd9 "@�1Ù{µ;Æÿööóÿ w^€i$J‰mÉMÿ^ûŠƒä�ˆåÜÁm}†¶ ‘IY}Ý šáÓ»×çïè#&ˆd 0 DõmÜ‹øE*>½ÓqñÈÎ> øk¢Ú¨Êÿ_¾|Áˆ�ÄËÎ C€”?‚i†ŠëÀ ø `�@9“ÈŽµ����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/attributed.png�����������������������������������������������0000644�0001750�0001750�00000000672�14517772113�017732� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß&|ÉÒ��GIDAT8Ë¥’¿K‚q‡Ÿ“—hŒ†@šBH ÄÁŠhH(ÞÍ%¡(§©©–¨%›ZZQ²5‰P¢—ȈÀ¥%h‹¦‚úÞkéUß$µ¼éûƒÏÝçž;QUz Ã=¬®ï°1ýÙU¶þ”x¬¬m E€kF†ÛŠŸ_><wßrz‹`(B*±ðç®1ÆÂ“ñÏ ¿„Ûªµj¥þš^Ú—lÑ@kÕŠ\œäUDêýZ–%…BAá°Å ™\‰w£ÜĉðA¢;ƽ|�`¨­øõéÍ ‘ÃèT¡ã8æ3s&�‹æ¬ï̾q�n¯l*§G|C�Ó4Õ¶íæ) ™\I’ñ˜ö÷ìnf»‚èŸ 4 ž ¶?<ÞyÜW/QÇù?DUEDpT‰ŽÆZ*t„èîAÓÆ‰ªÖ-5Cl^a÷ÿ ‘új5ìV·����IEND®B`‚����������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/connect.png��������������������������������������������������0000644�0001750�0001750�00000000632�14517772113�017210� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR������ ���v4A���tEXtSoftware�Adobe ImageReadyqÉe<��<IDATxÚbd€‚ÄüJ{ ÕÄf ¸Á) .›?±ý Šh|nù‹M;÷ÿÿôéÅPø y:˜ãïßâŠÒ /^Àå~ÿþƒÂɃÔaÑü—áýû÷(®Á%×–’ÿÄPWQdøòå †Bt1:˜–Ä`¸Ä¯_¿04£‹™ë¨€1XóçÏŸqíß¿ðɳÌ^±‘‘‘‘ÁPO›ÁXS§ÿ`àìõ» ._ƒhÞ½n©:˜ÅsÓÎDEá? ÍÜÜÜ(bç/_eصf‰:,´oAþcàççǰ] ¤¦‡§¿^^¸vSÜÕÞ)ž3ˆŠŠÂù»«ƒña ]sÛ^¡n ÿEà’À°øÿÿ?\3ýæó‡w¥—O^€¢@žGv ðˆA6q� �í@­^!ÙÈ����IEND®B`‚������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/nextview.png�������������������������������������������������0000644�0001750�0001750�00000001235�14517772113�017430� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������Í£õ9���tEXtSoftware�Adobe ImageReadyqÉe<��?IDATxÚŒRmH“Q~ÞûîCmN7× ¥›eŠD4ÂÀ5V‚IX4T¢ˆú}‘ÕÄ(£1ð‡D¨9J$.ŒEJ},¨2Ý`9uß«wï{»a;ðÀ¹çœçœ{Ïs¹µ7‰€…ážÿ¼ôÙ˜®‹Œ ¸Ñ÷Ë(óo1hþK*¾Nèløu'èŧhI—’²XÇjBE€BB$ÀÑÚØšû°­xû]íò¡ö_$>¯;P_fÔç*8D…¨•*4˜ SékÞz§Oʉ;éøŸ¤zN˜ÜLD4º- 2!!€ ]%LUf,D‚»ý•ž]¬y4þ’~Θ3xE³žŸÏ¾=ß™ø!¢Jo@RZ!"77¢z]MùÌÜûæT]”&&¨“[1µ¨±^u˜X´¥…'zuƒÊ–A8j¹áDm¶N£‹%²ßŒ‚³|uZ¯†MFsç¾VÜwP‘fHv÷0¬Î!,Å–/…nKó™IêÓü M~Ñ…3Mí0lг…!# ‹°:†0õáÓXjŽö'F$+8UßcªÛoiÝs1É´�ì©°O:1èGÌ—ìŽ÷KwXЛ&¤‡pk,<}}m_C.Ö] ß‹ÞQ;<_æ %«0C]¬.´rå²´¸`â ¢ˆ>‡£Soò‰W“ÃÒ–ðe’[nÿ´Çu™–ž+¢9Gx—­,œ·êßË9Î7)[x§|/igGmúÊÈÒÊÙÿ`�ë幫 W����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/gobackward.png�����������������������������������������������0000644�0001750�0001750�00000001232�14517772113�017660� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������Í£õ9���tEXtSoftware�Adobe ImageReadyqÉe<��<IDATxÚ”’KHTQÇÿçÌ\µnj“ÞyfjÚ¢QJ„ œ’¬h!”´H²ìÐrJ"1&"-\Õ"Â’E¸+Ipd(Å4ÌÆ1M6ιsçzoçJ­ʾÃÿ<àÿûÎwë Ûmzœ -L]ô_fë-*0uäöÞ«ïqk*ZŒ,ô’ÜÝæ½Ѹ§ œB[…;-d¾A]z)VWs{­¦M–¦¿¡P‡ð$\§^Þ˜Ýî©iÅáNÌ`IŠ€°6ºàסaòÛœßFëõìGœGk=.#E`EþJ(>//âñ›g˜ðH:×vÚr•¶;r ¼×êÚPæ(aÙ§@A,!â¡ÿ)^|”;Ñûj7³ˆé u˜³ÍóÎvc•,!®,³B(dxz:ž]êŽõª]jŸÑ71HƒÚŠR™Ð^ŒõÕäò™°›¨¬pwà”ë<æÄy×¶™¼¬j:ŸÒBkÞ±…OæåYÿÜŒÌnßa/ÐÓAÆ2Nºá´ír‡FN+•ñ¬¤_{iøuªòQ—G´ðæï†þàÛ*v~ZóðUšF±¹MÕ J‰}“ö IóL¹\©æÊ虢Rkùºc(¶Ø`$Êó¡¼µ †4PRý‚éÔ¸6´’+Нƒ£ûcÉ8J·Ú @Ä£þ¾´ST™Ôü©ê“]ä}Á‰Ý&!ƒïÞ?'ëøàºGàÜôµ’’…›øÈ`*Ñ'?�,ÔâbÀ����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/compareReverse.png�������������������������������������������0000644�0001750�0001750�00000000440�14517772113�020536� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������µú7ê���bKGD�ÿ‡Ì¿��� pHYs�� �� �šœ���tIMEß-[ù‡Š���tEXtComment�Created with The GIMPïd%n���ˆIDAT(ϵÑ1‚@…á_b¬à.$xmy ÒÏ$X[Ž�§†j)\#¦Ó×ìLæËÎ& ˆ2yeŸ.Z |(@¹K¸�WÅ À/ ”Ô@ý]²}âڻa•�Ô+¥ê @Å ¸SY A@N³Ç÷ᵜ˜Üh�àIÇ9ðÃ/¿nîÔ*7£n ����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/badexperiment.png��������������������������������������������0000644�0001750�0001750�00000001431�14517772113�020404� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��«IDATxÚbüÿÿ?:H/kž¤20Áô™]µYÈ�Ä�2�§7üðþßÿu{OüŸ±xíÿõû΂ù qtµ�Ä„n#|úð~Íìù‹45uìÜüÔ´ô@|8HY=@�auÈÅçUÿ¿þìëÿÝ7¾ƒqbA HB]-@�±0`ÿüù füþû— h§,÷{°8ºB€�Âj@xZI®’’2˜ýç÷0mbbÉZ$\ dö « FäXM)’R5ºzz™a¡a ßÿc¸÷ú'XŽÿÿ{Æ×'f¬=;ÈmY=§ïH €à&äñÙÑÑ1麺º ?ÿücøüý/Ów?~_8Áð)3�Å•_ø¼Ê?¾ß@p/üþý;ÇÞÁ)]^œÌÿ ´ýã·_ _Ïe<´‚Á¾µ•ßÛ,÷qëV†+.lëgd´ x4-ËE/ƒÏ+yÖ« ÎëÞä3ij2¼;s†]]ŒAlØ/†ƒ�wÁß¿%A´(óS†ÿ J ìL¿‚ ?€b_gxûþ=ÇcÇXYÞ>~ÌÀûå X €X`‰ÇÁ?îÉ âsü}ÉðãïwŽÇ¾ƒ jþýîÃÍ– áÿÁlP$ƒä�ˆ š˜þùôqõ…3§nܸÅðïÍy–¯Þþ3�ÛòÿçOÎß¿´{{tzûÀlH €à±  a`,")_çob­„í#[2<_}–!Y^%æ>|ÈpâÇ4€�‚�ô›ŒŠŽ°„l:##“$l€ éöå³Úo#p˜[O00, ”„2Ž@, ĬHêááËB@|äs€��j.R­•$K}����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/fileUnResolved.png�������������������������������������������0000644�0001750�0001750�00000065344�14517772113�020520� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���sBIT|dˆ��� pHYs�� ð�� ðB¬4˜���%tEXtSoftware�Macromedia Fireworks MX 2004‡v¬Ï��%prVWxœíÙÍMÄ0†á‰Ù@ÂÆWŽ41P ‰°bif:  @.*àÂfœ]J@ÒûÈžüÏgE¹åõûåCv²«M©%†W/Õ£Z5+Á½X +".bæf¦1Ú<î¨jq+®Ç;M|mÔ:EƒC‹õØ›hÅ\[€µ'ã ÚzÓÚ¾%‚LT½ªµªÕUk¤ÅÙÈ‹QD«hÔX���������€êlI’–1õŠŸdIÛNù}œ}ÌKŠ÷?,s§üui9ïŸrJ'›!÷úþ"~ÌcJ¹Sþv>ÍsÇ^ßÿ´Í³Ìy;uÊ—iú-�����������ü±+¹‘;¹•û˜{y’G¹ŽúÛ}\ý†öÿ:}]¼mž/ß7½W ôð¾€z¤›���HmkBFúÞÊþ�������������������������������������������������������������������)¤3¡��UmkTSxœí][sÛÆ’ÆæÄÇ‘,Ëvr*û°/ªÚÚÚ§øàNðQEI1%1$eËyq‘ aóD–|tK¼,þ÷íî€À`p%Ò6¬DCbp|ÝýõeÐá«Æí´ÕÝ™LµY÷·£É´62¬¡=ÎNÛ;ÞT½eÍ›ƒ¦7ÕìÙþAŸÚînÏ›êÎKÜu{'xtcNâÑ¿Y§Ý¾6:ðkg»5UÖ”¡â*2VÎáÓD9›BÏ:ôœC¦ü½å/ØãlÖmá¢m6½ÉÔ;³Fó€®txW‚6fÞ.íÔkQ_oŸšF›66^Q³sÄO°Û¢ïÝ>íÔjзV—š#¶±×™Lëö¬Ñg}vö~]ä5Û8Ê#•:kk“©ާiÔ´`£Î›Y.dþS†Œ²¥lÃÖkøþ |:ƒv \AÏè!1Óv_˜=á˜í)—€Ë'åô]+ãTlL†Í8UŠëF°QS°q†¡FG3<Ï€Áã0x3ëu~‡« g½o;Ç€š5€ üC>�_p�w” P® €T ”.¼gL81¡©[ihr )hZš‚¦ k¡mK ìu¬§ÇÚ0¤?pHdÅå€>ã€ö�LtqKé§Ø6Ê´Z)–šg.Ön ·¤ÝŠÚmF1ŒÚÐ{^ÆnEtréÚ—Î>l¿$c,NV+à% `£Þ6ÏbØÜѺG<B>¥7 ¡t÷QŒB=$Ó0ÒW”´…£ô\ŠR“´i®0ÝÚV'}á8mJqâöW£¥3Rš&Y !‹!dÝÉÞö¡(·Êç/ÒãkÑXÔb0Y ¦ƒiÀ`’Gšy ®j4ÀýK58cá·àt¡Ñõ©!¸k–Œ‹TÊ Q4*ƒFeШh684Û —àáðûAâ�ýÀÊçÑP¤!|l“Dý™�9f @”Û… ÝÑ÷ë !!d2„L†É>k$ãÃÛ t6ÁÐÏ›û ^’ݰÄ/I© ¦©Õ9”ú0-y¡,”>—S¯çs“ƒ¹ wF%˜÷A¹á³`µ¨”áó…r‘^ áf«¹ÃQM5‹Û­¥2$‰I/-{ŽZ®îäÆÒpxmh£ÂØ¥tmÄ s\†ÜxAa…šVè%É.dEú;è Øèµœš V‚7HË‘ñÐ>z¶V•N’óªTƒ·¥ŒÑW¨ß€×&¸W3Ób˜iC4¿Zª2ÔÜ4bC3ʶEr !ÜlîDÉï8Ñb+Kh]è¡§š¥V_¬].CïÂ= 0ú@¹Ž  ‚²©ÎùM¤üô8_°KMw¥–)~Í-‘Ék¥Ž‘12sûÎòJÖð+§ÜÕäGòq´XE2ÐÌ`—°&1˜È‰¢=ænF©½P»�ž>ÇFÜBÓ1+½É=•ñ“¡sõâ Än–ΠcæÃNçö,ZCÅóJn‡bëìÉGÁp=3G æ™%4Îw Ün ÆÅ›-ZkÏ~Ñ7°(Øÿ–>t%½@Œ^ã3ù†2¹Y45£¡dM6²ºÃ½.%%9±5t¶6ÃÖfØÚ [F€øaè Øb,ÓÝ©j6Ž}šÑt•?Š(i. ó0r$I7Ñ· Ί¤¤¤€>ݰ¶2ý-ƒèã ž(d›gÁIA\Nõ®zi24/JgYP=P‹V ðbE§:×MŽ©ÍAµÍ$õ æ:}0½”I[´§éúX«“†/Ò-å+—yà-¢­š5ÎS’‘‡B ŠíØ|ïÈÄÓ”tìGÌû|±ÓV9k.êbsÀŠ¯×ˆ/Oȧhû”§|àùÊrÞ—ÒÅ ·1ªKfÑNÌ’¥i 9ñ¼E–Á½‚—**¢@”l•béÀ•V÷ô”nY—ÈOîMÑÂÄ6ON|ÕÓœqÏ¿s<%KÔ47QbÖìÄ ìÔ2:Ð,à Á]øÞ×IF1g¡åˆ«q+ÍPpøt‡¹[òÛäO\ƒþÁÄ–¢àL _„0Äø§ê{4Ï3à³é>b Íôr@Š)UJAÆ0Puª« ‰Þˆ'+,ÒÏj€5¬ÇÕaÀº|¹–ËuÑ㇮ÿ!¾ð¨|ðãðN—‡AÝ®™÷ây£LO‚ ûà7F¹àrÅ�ýÔêtBücòøÇdØ.ÞZƒZBš¡(Ešœ8LŠÞeŠŸÞõ�Þk :q)ÊUžøÇ/ýûSRÚ`|×))ΖÀQ®EWàj)àÚf1p}à4/Ë @=›)~’3ø¤U>þ­•äß\×½0“Âá4‡ú5eôëÃ)ò„ÅçA-> mtjŠ%>]h¯Ë©™G 5OJÉO9ÐoÈÞǼ B <Ke˜º#­Q螥±X*˜`~éÃþ;%˜†,Á¤%I‹>‹ÁX$’÷¸Ý{Q»÷ îʃ]† ‹§Âþ+ÈÌÅÀüª˜oÉŒ0 Äôù–<PF?% œù¶;2¥«¸ƒšÜ¼nDI¥ÿ¡{âW•™½°Ù/{t¹ÿ¹P> Î×wŸ+N âÃ2„5ËdÛQ=PS[ ¯*ƒ—;ʬ—ð-=ºB^ç¦N­A-ƒÌæ˜‰Š™ Úc%¼'Ý™2b¦¥ ¦¡æ÷=¤äq¬†fv™(ðäB™µšðb öyÈ‘˜÷ÁÞu}Åd)A>LçaÒ¿ÁÅÈɧ#k•P,`ãÌ™‡’ªó<àø¥ÈâößÞbÛ)›ò—™h5nÜ5®ïÒ Û}æó‹éé[Â3ÝùDx®y Ï<ϽpEJW‰ !’Ôù$EœIåÌè$âF8öb•¸døüe-Œ9eà ÍH6äb‘t(;2kYEX°sø ™2ºŽ<¬óIÏUÔí¹2výÒoc®„~)8a=Ù �vNŽü†’?ˆÄ¡4”f‰YÈZžµxyjLF4ŒŒÂö& Ôó%•º#©”ì3—]§õ9NàìQôg:bR“où¢™–m¸®ÔÁhc™æi ÙFÁ| …X÷Ç–£ˆ°Ùe+rZþ²o vñ‰E?@ÌzÌoßOOöãéItOƒää‚"™Ê'Ú;]ç·Ú:ÍLé*;L5C:§)O$éó½x ˜…àfÁ¿(OÞ¢D¦0†´ ÀzÙ�G3;’.ýð2†Ê9tr·&™Ó¦0ÚàðkîñYµ2ä¡Å²Z–~æRxMå —žÑ¹¢'£q.TÝ¢ø”\ú "é$[•W±lÅÈ”ªñB}!dð4ÜàO@Ka/ܳ€ '’@’´Bu$'ZF*èî_‘Ó-±,ZÝ—Ï5ÝݧÑb·Py -…ø^-OTŒ§¤ ã#ß jôñÌ(odp Û¯I¯³žø\Dd`å¯{ Ö³Cz팧/(.ðu00üû×ÁØš)u':ÇäIÃQù´°úÈ•³,ª_0Ÿ]âa}¸|ÌÔn°f1JƂҬÕnÞN[á§p=A v“Ð#JAD/ øHB9IìáBh1Z,8h±[oí’ku›´K·ËúöYsŠÍ¬Î娀øјö C ÷œ$ö”’ΆÍ^0¢07xň»£ëÐû®‚`Ìå3¢¨¡®òþë*Z{¯ø£vòø¼×Á—°´Ø+VTú7 ui~ÿ ö½Å>õîçÑJžÂï­ðŠ/ÉšPí÷†î_”[—£W¥pO9¹LnF%·"rÛärë2.Ü-VOÞ ÒÛ d$Ûç$Ç>å$:`T-"ÑõÀq.�“™pøá…æ ü¾“”¾r’3™äÌJrel‘Iàš K/ÁåûœäØçNìªi•H‹ˆt[ èí^ó•ߟ'ñ·Ÿ$l/'.‹‰Ëª¤UFZ "ÝгèOBüí' ÛËI«Æ¤U«¤UFZ-BdàáKe¾ý$a{9i9LZN%­"ÒzÊ¥µËŸEýDüNžrùÈö8ÉÜ£œ,ëL–õJ–Edù˜Ë²A3ÒWÁ<µ<vX¸µœœ\&'·’S9­ÉÚ {ýŽ˜Ï{Ä„|ÞSNf#&³Q%³2^í -’ǼÚ|ûIÂörÒ3i+i•I¶;órtã¯Ña¸ï$¥¯œä<&9/2°@ÆÊPi’(>PµÜŸo÷ÕFì?Éè/7HWz±mj!D[M=ò͈|3#ßúxÖÙl Ø•š¦«i)€Ö9@¡ç¡o-çÙ6Î,„º^êŽß먎Šwî5-¿×¶Ù=‡{íù¡žW:kV®èeCHÖ࿸D¾¼á/[ºô”Fƒf€3m„]V>žºªõœ6’ï<Ë‚æYš=ZãŠûÆA2òÝœúÒš ÿO¶Œeîë"Ë‚wÃÛ£—:Ý’ÏÉ  ºQ½H²`SÇŸ$ ZCc¨%X°mÇ©anÁ£1þHA@ÖpÔœ´ÒÃ_–< ÔàŸRÂw~ÌöEqÅ×Ã1.ŸX$RyÜdÔ—Îü´‰öä'§#ZÕ±/K ž‡â5 VN¹o),a‹j3ÈÖwRLq3ðÏ•Éí¾.²,€_�‡ Íòg/烂ú ’îäAw´³.™ ó‚/´,¨79ÔØ3Ä’%­eŠƒ,¥U5ÑÀç.Ì¿>¨%¹PN;…â‡ÖRÕÄåb¶•þ²ìùD^.è˜ÒH¡fÚš`�F`�ÑãZϽ¶«5yº1öFCwår†°l_³KOÐDZñøY6ª«†sß’kÃzM&)¹66=ÓJPr{0vU-IÉã'ÖÄå²Ñ•þ²s=\“~A¤\+Çüï³b½®¬zRŽ/•Íγ,üªZPK›×ײ�òK^i£ÊW1ÈsžEw[ÍÛén+4¯9&˜h3G~ßÒ+'ýy±q°Œ~ \Ïv;½Ûisg½"ÛU<zh³œåŠ?1ᡤ¹óöúžg@°…Ž}9ö^Âs 4ù1ÿ£L•õÚŠ?ª¢+¿Àg¶à'Ü6¢¿DçÀ¶ô¨ôcÑž5ø­A~›E®º6¿G¥¯|FßůøŠÙs=´çz„àZùÀ÷ýGÙûihoñÒ%«DÇÔK8fÎ ¶H/g ç¡¥þ„1=¥¿µ÷ž¬ÙÿÛTçtÜUp„9bƒ^¯u¥ü‘¸¿x…ù«¹šüå&Z!âãô7’†ˆÕü¨`„¡ý áÎ×`4g;Œ3¤ð,´ç!-ʼæŽcBQ‡”&ÅžRˆèôÜüùQ•ÿü=®9ÑënÒ³õòÚZÁ(vü¯†~ ŰÜ'RI?ƒúÏð„ÎpÆ©I6þÐÑ‘=zqDw!;24r»]þ@KÀòdsY÷׈éòŸ ‰¡ò/fåüØG0Z Q®bŒÐ ©]“ýôHó®5ã…ÿt*ßó2QcÅ#ׂ#E»÷ü_@⋤0&GqÉ¥q ×8Ýe/ú:yA ÛÂÌvû±CùUž„w+ĹDÑ%عKk¸ÞWì\±ó½³³U±sÅÎ;ç`çµ€oèzhsCW }ß mW ]1tÅкçæï©ºbè{gh‘k+†®ºbhCÿgh¾?-®RØŸ­8»âìûæl½â슳+ÎÎÁÙ뜳'Ûû®ñ¬§â芣͊£+Ž®8º@å#ÄÑCW }ï mT ]1tÅÐCK4ù›\y§Uì¼ì\­¼«Øùkgç¹v.‚¿•w;¯;W+ï*v®Ø9;{+ï*†^†®VÞU ]1t†þvVÞU ½ ]­¼«ºbè< ]­¼«8{58»ZyWqvÅÙy8û[\yWqô*ptµò®â芣‹T>¾•wC¯CW+ï*†®zÎÐMØ õ?$ÏཉŒ¡çhã]d¯‡eëð[]1ágçsÂÖéZ,êà@ÈÀ×#Gg­³ïË^<gSà†ð¾I:WK¹“8G€€õ ºçëÓVDWŠêž¿®ˆ{•oN×lauqºæÖ5ŒFô/XÛ6¹¶…ýŽþÀõ ëºà7¾úuƆ 1ɱ¨Xwür#Qñ>–‰V«Œ¿ÄHTl»ŠD“ùycΧÀÐ!´ïÀÐ]¸Â„ýºZŒ5+†®ºbèªV°X†~:çSe”ÊÑÏ"RÜ¢ûbZã,”·­Gžúóû–©uúÓ<pä- ÇÈÊ:ü¨Sã6ÜïÆ×‡¸Ý£œùzV˜SmY²ùNœ-ÊËIš~?zh>€Êõ¦ŒnDδ¼z•Å£�ü?F 5ø1aÿòZX´^eIx°ªWÅ#T™¶DuoÆ8ßqC÷¶žiÝÏ€Ñewp;Wþ)r…òbšøî+~ô;é\ó<`™xLâ WÈsÔÆ6`O°dŒóP»$ÖÁhæOø~ 6ñfHƒ·ðwA›0@¯ ¥w«R¤Œç©ƒmh›ÀþœuxL¶S§8o6åÄbèûÑ‹bò,¦+k¡úì~• ›Ðƒ2¼¤ˆççæwðý½2LÔ…è1øø£Gý ð´bžjDwxóJOCûç¿Êô#Æá·x~M`”¤»'æ#iw??*ÿÝ'_)éîÓ¯"Þ}øüÑ»žp÷ïÿ˜%E¡IˆGÊÆ·)A!ëŠÏ¤Hä¹Ú“ñëˆ9”‘¡Âþð¢|t"ŽóF“ï©ô«mJ±È¾Òz ñÚJð6Æ"&ô{ÄÚ,–Ñ`¬V¬öáPœ±ò6F;#ø_%ÖÞ–qk1v~ý7”÷m…ÏU1tÅÐCW ýE0´0´¹r įÅXú…²OëúŸ³aeî†®Ž¸b|.©×AÞ7tÙZjü¼yŽ|N5Òâ™ÜqFûºþ½ º!¯T®F.7 r9}år¹<ºR4ƒÛ¡³Ü’|“´ü'ÉâB™PÖx5ÛëÀEö:ýÛéi{ÿpé[ÖÌæÛtËb[ñÃL`"òJ =çÆœÛzÞ'>S.ô¬«¡íã@Û•Óv™nÓŸnŒéõò<zf“júuîáY[âáÔ¥z¸(~Ű_Ÿo^6®³®\H_Mª„º4k2 YìºP¹FýDfºiÖÖ̤%ÎÊæ1úŸh¶eñ9ˆÍâ³½k¡Mô°£Äèï¾æ-dòŠÊüœŸR~ÎëˆþÄ[<Ú†£?a ze¬m̀ߨòí.´&­‰ [EóùV=Ü$²1Í’Ê:èœÏƒ²Õñ¼Y’ðhe‰Jòðu>[¡ù$•$¶·Ü_Žcýïƒ9%†ýüûêà­AŸG™©dT¾ï_¥ŒjŽ]:ÆÏ•=8î†2’ ÍÏmù{$İÿ Ì7|„Ÿÿ^R…=ÄûùH~„»I:šüc¯D<Í—Õ _6VNºÙRK—ú†ò»‚ï­ø˜)íû‘Ås؇]?¬;ñ|ø;@TÌÁeGþÚr‰ ¾CÔ€:_ݤDï:Ù7®üÂÑ¿P,iS,4„vLÑ͈ü¡A>î!4 Y‚é’ߤûöóÜåHÿÉy^? k@tÎÿ;À?*Ã$;R’žS(ªÈÑ¡HÅ& ÿBû³¬Â$¾÷(þÅØÆ…½ë”ÙÙ”/;´Ç ëÞ¤K3Kºœ«Ñr–£ ?þÇP” ~J<zQ|0"oÐÊ“"]®è&à‹4yß#]Q,f’ðÈ'¸¤ iÒLׄµ`ï-BáR²Žz5".}…#.ŠQÜóµD—´Zø<x¢ò„ÖÃû=[Á Á‡´ÄŸÈÖæ£xG3Wô|ç"bº´óËlÝlõç”ã¯s®N/ªmæ k[–ÖäÑ<qëªØ¼KØb‹«vYVËž ˆgµµ¥JAD0êÑ­+ȹ¸ÖT§ÿ-^U­ST\‹Y¿JuYø'c)ÖuŽh¶çÉ|)lSÔ¾5ïIàÛçt—8¿r왳~’yÃÛ`FoEçòÆ$O•Ö©¢ä’¤ Š}\žão‹ž ñ×Óc4¦< c¢‡Ñ‚$YŠöÈž(‹® ÷Ÿ*ß'ô/¾ò'È¢«´ÿ¾;vLö3dšpDÖ3dÉ}ªB\'R=EÆV¿TO‘}=O‘9‚ö-÷éïžØ‘³°ÿæ¯#:?Æö=Ãùõ1qñ§yãï ©¸¸â⯋ó?IùO´%qñ4ûŽÃU'ìÙÉÏðÙäãjÌÝ N­5÷éÚ8ʇ¬Så©Ù:ÄcÊHXõÀ¡J~¸z`Óꃪõø›}Ç–­sy˜N:¢åeöX f–õuÉ©Nsµ!§44ËËh<å%‹]¾2ÙŒhÛÃTÝã(Feò­ö™ðúPÆ0áŸÐ§#߇¥òÃ|uÊ)“H¢F³U5šµÂß6E¬U´B&q ñßaD2ël÷o§ödêÁ?þÍZ웪²o@r?PÝ—½ï%8 ,Ç‹å '‰=Ýæñp çí7&Øì¶¨éN¦:|ëO¦Ú¬ÕmÒ.Ý.ëÛgÍ)6³þiãvÊ.üÜ(£ès¸W·Ó7ØÇQgû¼í÷~‡óÁ]ôà.úÍÉ´æLOE�ú§­Åœh¶{Ú¹¶ûx ;í.66ÝIg›@náÐ;Ø'ëôùW�B›mwÚ¬éQ³½Ãš&5=8Ëölâ{xNuökç·ÉÔ¶Ǿ³¦ƒ˜íµ°ùµ‡û  Ýe_ûxº_{ µݡÓõÚø­Ý;Á¦Éšv ?zK£i÷zxûýC<`¿ß¿òßç7& û“ZZÍ7;mÑpNi¬ýîá‰Íis›£Cóv ¿&S{FÇ5ªÐ@ÛÂýAC¬5`£ýí6¿ó†v9<‚]š00°¥ö[€»½ýTúÕÞÇI—Ý#_;ØPØ;Rq5=«Ðp—Ãjštã;mÔú]<ÛÎ+ܾÛ>e9Ü»ž·hE<k¢ëãIm4®6W'ª5uÃAªéoƒbà¿×p¯Ùeá’ÿHq@® '4µÈ°µôag_DãY¾ÿlÍ/Æ.¤åÂ'v¡Ù^·y;Ý;>EpöŽßRÓƒo† í[Ö2ºÑTü#š@ï{MºØ^óc"ü¾íÃ%öš¯ñBÇ=¢ãÞ6©Áÿµ,æ{,´þ���¾mkBSxœ]ŽÍ‚0„{ó5|ÀðãQÊ_ÃV ÔÞÀØ„«&MÌfßÝЃ{ù&;;›‘uj°hø„>uÀ5zÔ/¸ŠLcFT ¥ÑjòV£c{™ìAZÚ”^‡ ƒpè ¦u9ZûÒ€å ن؛=Ø“m™O²M6Äs—äµ[ä YìNÅ\fÁ_µsgûzUN wRímÂÄ#%ì+%² c½ŸVÆãðÕC°‹~:LB¢L Ò:‘\õ:¡m�� µmkBTúÎÊþ�Wº��������������������������������������������������������������������xœí‘Û8 FSHI!)$¤’FRHn›wóî HÉY¯Ûx3žÕꇤ¢�úùs†a†a†a†axI¾ÿþÛïÇÿ»'UŽ{—áÙùðáÃo¿¯_¿þª÷Ú¾gýW9ª Ãû¼Ïâöð–þ¹»¶ŽÕo'®GW {>~üØÖÕJþîÿlúôé×ßoß¾ýüòåËú¢öµ¯ò)*/Îåç‘Ný\®ÚϱÚoù“v[iZ_Õ±aÏJÎþ/:ùþüù×6õOÿ-¹” 92b?çTþÈ™×þlôkÎ%?·Úåöìä_2òø¯èäÏ1äBµ ‘sµ÷YäÇ5à>¾:†>�Êc=1ìÙÉÿ¬þOùwï èyä^«- ×Ú¶,ýÌXÉßz�èû•žuÃÐsMù#×’U]ë>H_÷˜ÀyøY’Çvº!Û‰õŒå_mÄi ÿRuâþs´]ÍXœm§_gû)YYÞ)úmæ]×y,—²¬mÚ z†1Éêša†a†axEÇß“G°×§ÿóo/ïYòÝú\êkº6õ®x„ËèíjÏægHð–ö¾»–÷óüÏØñ|†yž÷u¾Ä.½•üÿ†þó\þô³aÏæŽM&ýwéÛÃäké#Ïú$?Î]ùMço¤Œ\ýȾ,Û/íßÚ¥—ò·âQÛ@Êß~6s?)}‰Î,¹ l¾ìçœô ØgX #ìvçQç´“ög·Ú ÷Bž™òîìÙ™^Êßuô¨ã®ÿuh½à¾m?Ž}{]ŒÐ.~È}Ðv_÷ÿJ;ëxçoÌgJöëôY]’Þ³ë@¶é.ì«)™áoqC–ü¿“?}ß>@ÇûXŸÀÎߘò'-ü�äÓÉÿ(½W‘?Ïöú›²±¼‹ôÅÛçúÞéô‰Û ºÅºvþÆ”¿ÏëäOœÊ™ôRþœ×ùÃþvì[K?[A}¥?-ýwöíåµÔmÑÕ‘ý}<GÈcåK„•¿1}ˆ¼§uåñxæLzÞ¦UþÃ0 Ã0 ÃPc[ì›ü<>¿g\=ö€c¿¶}ñ³M¾‹ ½ÃüÃgggÓêüàÖ èÇ„çÜÀô-B^ëók_g?Ìò ¯F?œ£³« ÿ•Ý×v0||ØŽÐØ=ǧH¿PÆîÛgçsì·ã/ÇhØ‘ñI ÇtýÜ~×{‘òçún^§}¶ïZæøºyDžë—óÏì·ó5èˆéÿçXÉ¥ÿWvðô¥§O)í"û±c0ÎËvYà“ØÅ ÿçZòï|~à¹_%/Ï,Îôp\€ËɹyΰçZò/ÐÉé;/x†ÖáÎsõü_é·9?ÿ«PÌܯ5Ý»\í[½ãy|ÞÙÃçõÄ8ÔÏÝøŸg�äû¿ËʱL{ä? Ã0 Ã0 ç_àk3¾Àç†>´’ãøŸÛÜÆøzä«Éø_ƒüÇøü\Sþã |<®)ÿb|ÅÊç7¾Àa†a†axn.µ•të†a?lÄ÷^Cã•ßvk­¬Ø½#®àýÜ~eûî)ÿ´3<3^×Û¶¹Âkð¬dlùcÁ&·jK+›œåo"eòú<.ãÊž`›Áê^(3zÌòÏöèu ŸÁ¦lÛ+6»úßv´î›<™†×ï‡ ¾k7]ÿ/lÓc[`ýOÚöùÐn}½×çòš„«ï ‘GÊß뎱š×Äzt¸^vßä2)?;WmÆrõ5üoäcö³ŸþIzì?ú¾˜‘Oî÷zx÷Œ{¹&ØÇ!û…e¹z.þ©ü»ýüÓÔÅ"ѯÑí¤ô ¹Ý1üÖóäÁñGg×ÿí{+Ò·’×lûw<ý=}GݽìÚFƨ^ú)õ¶ìzIpäG¿•ü ¯ãKì�¬ÖœÎ{Í{ÙÉßeÈï ûšG•‘12éÇÛ­¯Ïq¯§™iumf—“>¿.¿ÕþÝ}¬®Íëòœ®~žaì? Ã0 Ã0 °š[u´¿›+ð7øSvq¬ÃïìæÖ­öyÎ…ç ½?Þ‚‘}¶¡åœXùçwíŶ‘ÚvÌ?ßå°ß©ð÷DðÿùZÛ“ð-q/–?ß³ñ=¿ê<ËÌ~¶Œ›‡#ýßÙæ­ÿÙæ»>¶ÓÙFkÿŒÛ"qþøz°r­¿Qèo 9ÆÄr¦,øˆî­§nÍY[;í§oæ:)@¸-`×§-Ø7‹ü({α߯›SÒí§Ýú»@¯ÂµåßõŸKäï9èîüÖ ¿É¸“>:ŸnÁ3éç _[ÿ_*ëmt°cmìÃC>äq¤ÿSþ´L“øÇ<²?ç<n¢Ñ¯n!ÿÂ>=÷çÝ<ò¼6Ç;ùãÇ«ôsü÷èþÜa†a†a†{àxËŒ™\ÅÞŠÝûêpxç¶?0׋¼#ÿ5žßàøzæÇÑ™ƒc¿]¦³²¡x^úêl‡ò¼ •ÐÇ(×fù±ÿ:~Ÿ¦ËÓÙ£^l iÅnç59¯³©žWÇÏ~·\;Û?vþnŽ—í»öç’6eÌr¥ßÑý¿óUbS~vù§þ£^¹÷U O7O(é|;+ùSÏéGôü4|?Øfí´ÿÐ÷¶*?ÇrŽ—÷W~Ï2ÏoÅNþ–ÙŸÊ¥ÿSþ9ÿ×~dŽa«ç˜çòîÖ‡ÜÉßmH‹6öìmÀXÿ[ÿÝJþ…ý~Îs.ãÚyœÑÿmƒ4Ù¶OÜíï|Bÿ­düžò÷ø/çøÙ˜þÁb5þÛÉ¿ÈyþÝøïUä? Ã0 Ã0 Ã0 Ã0 Ã0 Ã0 Ã0¼.ÄP—~þ*ÖÎ1@G\⟿äÜKÊðÞßrKXÿ˜µs2â±(ߥò纎Jëì·º8”ŽŒ'>â’X@â–¼ÎQ¬ûQýb£àÚqôŽòwx‰ ìb÷)“¿ëî¸_ÊK|•‘vÎ ÞÜ1çŽÕM¼6keŸe-2Ç›ïú5ùŸ9—ó?K^ŽEº¤~‰9òϱQï±®Y®×F¹8–ëN?å~;:=J<—ïÛßþ¡-ìt�ñºÄ’yNAÞÇég»þCþŽ \áûNýâXÊKê—s)'é^Kÿg\~âç2}›6í}Ô³¿·áï)¹Ün]O»ûrÞ^Ì÷³j‡~†"·î{pæ¹âù29w€6”Õ/Ð.Ÿz-ví:û+ýÇÿ£ó²M{ÞW—ýûJY¹¯Z÷­Êêµ¢`%·Œ íÒ¤l9…¼ç•íž¶™Õ¯Ï#OÏUz+èÁUÿ?;îýùsŽçÜdš~vñàN·›‡Dç7*.Yç«+v:Óye;ôø8Ë}¦~éÿÝ|…·²+ÑޅNþ9£àÝÀ}•{BÆž#t¯é˜×xîãÕ­sXÉ¿k¯ŒS¬Ví›ü/Õç»uJ=oê Gý¿ð<‹Õ»L'ÿ£²óL¬ò:äD]²6Üj¬f™ògL˜ëz/¯+ؽ[{Ž™ßºrðÝCôM®Y×q¦~áè[»{y‹¼£®òÍy cÈzA¿§Þô»ô‘Þ;Óîwï„«±€Ç9—¬zÉszW¿”ûH®œóìóV‡ax3ÿ� ‚ú à¿%£��×mkBTúÎÊþ�’��������������������������������������������������������������������xœí‘) …ˆq ĉ8âDÈ^éê>×»gI@ÏÏþX¯jjg»iЃž——Á`0 ƒÁ`0 ƒÁà?üúõëåçÏŸ|â:÷ªçâs¥¬�eø÷ÁÿQéùŠþ3|ÿþýåÓ§O|â:÷2|ùòåßÏ.¾}ûö;ï°7eôûGFÔû´ž•žOõ¿6Ñþ®ö_õQúv•¦“×íßù]Tò¬ä]½^¥Ë®gí¼{>pjç«zëìåkßu¹´o{šyªþ¯yeõŽûŸ?þ÷{è-Òýøñã÷½x†º¨/ D:½é3Dþž&òˆ¼¹e«^H×õyê i#/OGôzüϪÿÇ߯_¿þ~î :ûsMeÑò#M”Ï3YŸ#=÷2û» QžÛ›ÇßЙ¦‰ïŒ[\s=Eó8´}E>¤GÈ©éTîø  Ú²Ê×Tªg-Ÿñ}×þú̬üVfÖÿé¼Ìþêo¨SVwìzV}Ñ.âƒ/Ð>¨~<Vrvº@>Ê!?÷UýùÏËßÿï1¸Åþè<ú#õîä¥þ•ý}âÀ¶Ø=þF[ þ÷~†¬ôQÚ‹Bó¡N™.ð·.+푹^edÔç½üLo+[\Å-ö§k»ïä döW‡ïÍú(}Ýýê6îqÝý$¾#³?zÐ6–éBÓ©ÍiÈïöÇ?òLüåÍ7®!ã3ìO_Q}Пuõïêoßš™é[ú=ž¥tk¥È‹ûøMÀÿ‘Æï!'}/õƇdºÐr2ùÉ_ÇCú‡ÿﲨü:—©ôéº ƒÁ`0 :8÷—ÝÍòoÁ=¸„+8-ó4}ÅÛžÂcåÄ¥XÏdq{bUþêÙŸÖq˜Â©Î®è¸âmï!«Æ¶«g*ΪòU\z·ü[ù´GAåÖ=^§+ruñü{µëLVåÕüþ çU¥?)ÿV>­Ò“ó†Î)úçx…|œYé¬ÒÆ»giôãœ\ÅyiÜ^cæUúÓòoáÓ*=£ À³Âó!óÊþÄíT•³ÓY¥µ?rfògþÿÊšûWœ—sÖʽVÙnùÔõ*ŸVÙîXù#å=ÿÌFÈÜýªÏ«’—+[¡«àFô~ÅyH«\L—~·ü[ù´ÎOÒ‡£Œhô5žÝµ¿ŽžöT§ö¿êoà”w¯|Sf®ûÜÁÓŸ”+ŸÖé)³·Î;´ìÌFå³´;:x ûëØÉÇ÷â)/ˆOSÎ y²ëUú“òoáÓ2ÞÎeÊ)Ve3'w®”ç‘gGg™Ž=ïJþ®^ƒÁ`0 ƒÁ ľˆùœ‚u k˜U,ªKsÛþçØ‘5€nYæ®,÷çbXw{ ⬿wÖ&Ýúõ™û3®Q×”øN¬ðQev× ]¨¯Æ·ºö¯gcH¯úËžçîi½÷Š{î—ôÌA¦3žéôIó8†Çh³òwòÊdÌÒu×wËÈô¸ƒUI÷äWçq”ƒð8­îÕ×çI£>+—£ñ@åì”p™ôQÅŸáóÈGcþZ—ªüò\ƪÌêú޼ÄUƬìß·]ÌÒù/ø:íÿèÊÏ3dç;É«:gB9ÈRÈôï|GW~•—î×w«2«ë;òfz<AǑߊgìì_éçlùú§ËyÐýŽÏÒþžÅâ³ò=¯³„U™Õõy3=ž ÿ•[ô6_íû¹Úÿ3]Uý_ËîìïôªÿkÞ]ÿ¯æ]ÿײ«2«ë;òÞjÿ€Ž->†áŸt|éø+—i5þ«Ünÿ€žá«ÎŸgºZÍY|<õ1NyŬ|E7þkúªÌêú޼÷°?õ®Öÿz/k›Ü×>ä<šÏÿ=Α}NŸÍå»Î…ùžü>åuåWy­d¬Ê¬®¯Òdz ƒÁ`0 *èÜ\?W8ÀG£’Ë×ÏâY»ûÌÕ:‚ýÒÏDg«öc¾g<‹ Ìö2+²¸€îÙÕýÿ'ëWµ±6½žqnØŸ{žrèuç"w¸<ÒTkôÎ.™ô\ r¤•¾nåOàûïÕ>Uì˜~c‡#T?£ñ+®ëžyöï{¼QùÂ,,^qF/XÅûv8º.Ö©gá×3}íȸâOPùì ~n%ãhUÞG4§çø(_û…sn|W}Tg&x^cëô“,Fíý…¶Çù°ÃÑ­¸ò«ôµ+㊠<ÁÊÿ#+}/ãUw8BÎRh_ÏÊïäÑ|»33!m–r\7U9Œmêß({ÅÑp™¾veÜåwÐé[û¬úx¯ëG¨ïµÌú¿Žß]ÿß±?g;õ,çnßÒ½Úow8º]®³Òוþ¯Ïßb÷ÿÈîã?úÇOVé¼=ù¸ZÙ_óÎÆÿû£#¿veü?áèv¹ÎN_WÆÿ³Žªõ¿rÞYL€ëÚo;Žù°ŸÎ1³g²9pV^•Gµ~>™[_áèv¸NO·S÷Ÿ3 ƒÁ`0¼ÀçèÚïQ¸’·¾[ãï¾×ØÀ veO\k^8�Ö”¨v<ëZbzº¯²Û\ŽáOìp¥Ž¯b¾n$~ð}¬¾Çoèz•3ñј mKã è«ãvUÆÎþ]^»i´NºÞå¸WAö»#´÷xŽë”«é‘æjßÊtÄõì q ³:£¿ÏE=Ð z%Ö…ßqù)CcñÕYµEÅÑí¤q™´®ÊyRGý-¡+u (K\ûh¬PÓ'¥Ü*^Ø¡²¿^¯ì¯ñqÚ=m=y|KóòøvÅ«eü‰Û\ý˜rÈŠ4µŸÇ=Ž›ñ{Wê¸úÝ1Òûû;=Ý·åòxÚëpû;o@>ú›”ȘéT\ÔŽý+C±“=*ï™É«|˜¿GðJO¸CÊåW]ù–xŽ1.³™ïµ 9_EŸÐ±©â ½ýVýqÇþõÊã)vÒ(ç¨ã Ê‘}Ïì¿[Gåñùw¨œŸîǺÛôã{-âƒoô½ÜSdו_ËžïÎ׃Êþø2åÔ;iT&Ÿw*ßÎwú‡·™“:Ôº§ÇÇg×­¶“SþO¡ãsÌìÞjÝêºï%Z[~_˯déÖ®·¤ñ²+œÖñô¹Ìw]Ùÿ7 ƒÁ`0ø» ë]ÏÜkÙíIŒu¾+e§L]«ïÎÖ‚ïoA^ç°î;=GR¡³?œ�év쯱Ö;<÷ôy‚· o$Nî1ç´ˆ=:ߥPîVãžuŸ£<´Ç <&«ü¿ê3K«yC©¸/ù4–£rÇ)i=µþ*/|ÎŽ^]ËQ¹NÐ1qŽG¹¥w>ù{å•á <FªõóóÎÁVþŸr²2½nÙÞloÿØØ§Ç|±m¶o›¶'âqbì­í¢Ó‹Ëîr`eìêef±ÿè6 0¨lz’ŸsAÞ_²¼«°îÒx7±Öì·£*îU}î­R®%ó+½¸¿C®¬ü¿Û_ç ·ÚŸ~I\ýQö×~±küy©Ï#_·ÿjo~DyUåÀ®^ªúž`5ÿ£žpŒºåûk¹î‡oµ?:¤ÕË®ýÉCǵ¹îwÙÉ®üŸËë>?ÓKvÏå:A¶þó}E:·ÈÎ_«n+{ÑþuÿÃ=ì¯ó¿êÜr ³›÷qÍ“¾Ì³]>>ÿËdÑ}+½øüÏå|L¼…õâàõ0öÿ»1üþ`0 î…lý·Še€·ô®ùŽg:…®×ºñ¶Šž`W×÷,3ËOã?«½‘]—¾\9ûPø×î~Í[°£kOÿûWùiìGc~Æ)ãÄ-<žw¦¼.ý3qÌ}•ãž'vªuðw$V±’¬n“Ñváò(²r²ºÂÿ¸®5Žï2©½ˆS;W¸‹ÊÿkŒ_ÏKÑÏ”ó­8B/ÝÁhùèEÏÕ —'‹9êw?K;Òx:òxðº<–ì|@¶Ûc³ÄϽ®‡§ùVúàyâÆ»c÷ÿ@Û–ŽSwÍ8B•òq®Ãîÿ]û£=é2ôlBÓe6V}eö÷¹ˆž­«òRý(·ØéÃËáÞ VþßeÊöZT¡ë„4Ýûïad¢­e2Þ’ý+nñYöÏæøBõ—ºŸTq„®Sü×ÿ»þß”é<›Ãïø­[&Ï=üfÿŽ[|†ÿ÷õ÷s°zîPç)GèåèÙÁª}{Z×…Î3«³™n7ÅjþpûWó¿Îwfåtöï¸E¿wÏùß[ǽ×;ƒ÷…±ÿ`l? ƒÁ`0 ƒÁ`0 ƒÁ`ð÷á{ÑÙûô‘Á~ÿ¬ö½³ÇÒßi`oLöy„>uo©Ãßi\q‰ìKó|}ÿï�Òû7žÉSvu9ÍG÷íñ©ì¯¿c¾#öÙé>·,Ïjoð­òw{õÕ†ú‡Öݲ‡Lûù=«mWèêòÈ2u_¤ö¬ÿ8د–åéŸjož?»Ú²kÞËDúøßß±¡öm¼†ýýwÔ>ôÃì#® }©ÛË×õ·E:¬ìOÛ¡O;<ÿ¬ÿsüy—›î¡Ô}›Ú›¾k‰}~úŒî±Õ|µM’†ï'8CTþ®¡¬o+¨[Wžú‚ÌöŒ½ø†U™ä©ïïQ™õýr'ö÷½î\ç­'ç’tœTY¸ÏwôŠÌz.Dó¥=¨ÜW|ÓÉ~q=_¡¾�yª¾M»ÜñçÙÙÍÇ÷–¯äÇkþt§ïbS=2æû|¥Ò±Ïy´NÚ_}O¯îe×ù”摽ÛöàýðtLàœS6Ÿq`CÿíÌjfý´3–#Ëéܰ³?zÕ1 ÿéíHí¯þ]÷š“ç‰ýõ\"íWËÌÞ]åó¬ÊþüO;¾2'@¾ìã@~tGÎü:º«üªç{åÝuÊþê7m1‹è™Q]ßPWVç2ûS®Žåz]Ï¥zŸÒsý‘ÉÛ×3ÐÅ]vç‘îªÜÝxwÒžôÝ:Ú—>ÚyŠÁ`ð¡ñˆ$j¢ëw½��­mkBTúÎÊþ�“��������������������������������������������������������������������xœíÖ±Jqà#KË{ƒ+Å×H§Æ"a#A| l‚V‚X]×"ØAD‰©ba3™¹;ô –…ËW|ìÎoš,Û"¢ðß\·¶“" SeÃù\ù`ž±˜v/²Þ—ñ8âõ5.[ÛLõœÎ™×¾ïéNLªÞ§Çˆ‡ûˆ—¿³9ŸÓ9ó‰þÙÆç¬÷gU|}5óçùí=óÚ÷}#ÝùõndÅ£ªyüãÍh–×¾ïéÎð,ë-qw1:—sæµïûFº'UﯛˆÓã©é<¯üDÿ‹ìp?ëý½÷%âû·8ÊoþVÎGUyΙ׾ïéÎêzk‡»Yñ×ü×ûØÚJÖ½ùi6W^û¾o¤;KYï ­µ÷½åù\ù’ÿ?���������������������������������������������������������Ò?Ð õP;ÕÏ��ymkBTúÎÊþ�¢6��������������������������������������������������������������������xœíš‰më0]HI!)$¤’FRˆ?6øc<lHÙ±døš tâ±ËC"µß+¥”RJ)¥”RJý×÷÷÷þëëkJ…߃²—Lûé_SUŸÝn7åóósÿúúús~Ëu§UÖ-U¾yy9Øcëô¯­ôÿûûû/Ju¬z?£ÿiûÏàÿ™>>>~Ú�sm£®+ŒvÁu…Õ‘øνYšuÌ8³´ú³uNÒ?¤WP>Ê1Js¤ŠWiVÿçü‘ý_uKðEÿ‰Ï¸ˆ/rœÌù£Âˆ_âšgK•W]×±ž™ÍEYòclÊó,[¦ŸTœYH»T¾Ïàÿ¶›ùÿíííðŽˆ}x¦÷ÇL#}A› ¼ÒâœöGüžVË7¼—‘^÷}>“iÒžº²-çøèþŸiæÿì;}žLJø°ìXí&ÇTÊP÷3ýTÞ#¯ôߨgÿ®ðJÖùl eäý'ï=ŠÖø?…͘oéçùn€í±aöëì›ô½|7ù>šý?ÇôU–%Ë;«ï¢­ü/ñmöµžN/èãI޵Ù÷fóQÖƒüz{Èñ<ÓdÌé6éd™nù;è¯ÚÊÿ¥²Q¾–mû{{÷5í$ýÀûiѦxæÿg<Æ$ò"Í^¾%=êü¯”RJ)¥žS—ÚçÍtïe/ùÖ”ë —°a};kú÷Ô_µöyµ?¬9ÔšÉlÍzÒÿ}m#¿óGßüKk!¬›ôók(Ë9êGüã1»¿”Þèz–×,­Q¿&îlÍiV濊ý²Üû#_Ö<òœöÂ3¹Îžm$÷^9g —{9&°w³&¼Û:Ë™ë‰uõfÖšúºR…÷:Ö½L+mWÇôW^£§Äz%÷I—½î¥2Ÿ£î—lo£þÏZ¶f?¾k4öW¼ÜÇ-è#¬ó­ ?V/ì—c^ÿ·!÷!{u̵ʴU¦ÙóÙ·ÿAœÑý‘ÿGe>G}þ?Åÿöþv✽Žø3ÿÉX~j½úœ—{øzT§ôA·O^ÏòʰÑ>÷³?syÊ|®¶ðßG)ŸP¦</1Ö1~2–ў׆ŸR/Â7ø�Ó¾sm÷srò˜ÿù"ó(õûÝÿ³2Ÿ«cþϹ;ô~’u-õñ)}ƒ¿ˆË<¶Uø1»g¶äý:çaÆpâbç´5{ø3÷(•ƒkñ!m'mÊžÙÈÿ£2Ÿó.È~[Ö)}GßκbÑXEÜL¯ç×ýÙûÁšp–ê•aÔƒ¹¤û7çòÑ7Ï÷çFyõ0Ú@ß‹L?󞕹÷µKhi½@=¾ô¿RJ)¥”RJ)¥”RJ]M;‘;䇗ŽjÙ;Žœ��SmkBTúÎÊþ�¥…��������������������������������������������������������������������xœíÖáiƒ`†Qqqqq±¼ ·¦!ÿŠ çC›OûëMlÎS’$I’$I’$I’$I’$I’$IÑqç¾ïOç9˵w÷¿ºO÷o]×sÇsš¦ÇÏìý,÷Ô½u˲<^Ç0 ¾‡tï²c•}³av­Íû=µÕ7¿þî_¶ë{V9ëŸåz}ûÆÙ¿º^ÓýËs¾ï_ÿ×çy~Ú?×ìÿ}eÛzî×ïÛ¶ýúÌ÷ç¿ý¿¯ú×÷«÷@®ÕwûœEÕŸ×k’$I’$I’$Iú÷�����������������������������������������ø@? ù¬¸RÚ*f��*mkBTúÎÊþ�Ôð�������������������������������������������������������������������xœí}+¸ì(Öö’H,‰Ä"‘H$‰Ä"#‘X$‰ŒŒŒ,™QûœîžžéùÔÿÔˆZsé>U{× °.ï».Tæç}6ž�Ú³‘-Æ×F`‡£Ãp]Åk�ß…~Ãóbà ¶ О$Áwݓٱ„ÁñÍ|süñCo�•›ÝA+Õq3¶¾lOàx@á(é0ða¹¯+?÷  ÜT,¤_¯7¸s\ÛÞϘ^Bl1)üCó•Ò+ÔkÛ(îFyN"8õ–dPCÌ_9ÈÒ>O0&l«4¸Im+þîënwîÛGrŰø™à<Qªƒq Ñ +¯—²…H“} ú¡®Áe¡·q¹®~~‚[).£5cƒ‰6,Öú¸ÅÀÁ‚mžuO øï¨9p\øÓý<//?¼ü·¸NÄ:ž“M›p)¶ öÄœ-Õ2pÀ'‡uKq`¾´Í_·àÚæÀÕ/¸™û6ü4<~�… ´77SêÇáNÝÕBQ×áÖíó맨”uMà÷{Žû5È%.B¦NÉŠ k: k›NÀ¼m9Øüç*§uUÅ|2¨†Ù%;Ñ¸]Fáa×’)Ï ªRE%HWc0MgÆ>»ø)/tih“f˜õÕ Ñ¸X†>ÊʨËEËÅòã)–Ô<,é6ös4ÅáÀÖ5›zàbð?¤¢Jðàö\<OM%O#(7ä6à:§= ªêýÓ‹YA£÷ƒH ¶«L s6›ÎMƒXêÈùBcX&ǘJ½te».Êöü¨Ï 3.je(”Ï?Ô<?-1é$pO=�ýxŒ ÿÚý ]<Jt¡·Vg›š`|I,<丕}àFóQj]Ðo%[PaÑýˆ6ýXY¿Í<áª?¨Yoh�€Fžü067á­6JFñ—G[ð…wv)šÏ7?,ä@wŽ nMàǦÝmÌÊk>?õèÉLÚjï³=€ÝÚ%wƒZˆizFTxô„$¯kPö8›E·mòø jAO™ñÔ×úÞ€«ž>~þ’†åÜàØ†‘ºéB9úµâ † Ö¤8U­«KCÃv´jbëL èåçC¼ï€y¯¡ ç;¤mj P.Ô —øãïDkñÂêwþ¡UÿE€3ôܨÁ”‘•’8xëUÀ…JÊü¹s£‰ž\„³èÉŸŽ+;}s­FãQ(KI­î÷¦XÝ›„ƨ ¹1 Ëúþ+Kú¨èdXŒ];JÄ£Žïcˆx$§DÑ×·Þž¢X`i× ì¨ëÑ@lÌûrn°m$¨Æ^×9΄ïzBGÏž Q=Ænfäk„Dêö¬e; <¨ýøaÓü>,µâ¢ž›jÆïk‡0BŸ[p(õâ$¿�º‡Ç ‘ÛöÌpý4 nËËq`”XÆ“ù úvϵöèÙ.xõHnŒûorŸJ¾€Ï5¬ñÁàÿHàu©‰ñê뇗 fà§ í××a앆‰[Z:><ÇM@J£9óý¬â$Óq]¡�}=H… kÐþ3ÆÊºã¯ù鲺t¿Q“=‚, 7ÆÇµß»ýìêçs Ä>ã¢3ø¶ïÞÜ6[¦Ñg•¨— RLت¨ù­?·( &wÝ.7C#~B{‚]¯Ó ×â—UÔW² 7™Ò1jk~‚e”cG»¿rËÇùÐãDØ.=ôËK´ÜîëÅ@ÝWÝDZMû0å€ãûíèä¼0Î\Úòxó®vÏqßNZ¢ >#Æ ƒ„ŒàBE— ™¥)•‚º&yØA}tå?Bûê Yìm(ÂWIpáɱò€ñ ¸|½2—+èýà\2·ö íÞ)lÜ8·ÖtlÁ@Z.B½€£ï•eñ…‹ƒRSßôƃm>d˜Iéþlþôò'N a†dÄ¢G3¹%†¼#«)?è¼Ï$sß _5=²íYÇBR#-k"qGP-Ðeþ"çf­ÁÂá%Ö©-Ï“37êÐäÌÈ8ÔM9™ÏŠŠ,¬èä_*n;H‚ÁúÆEBƱ†Öcl¿~øÎî±ç Ë[ƒŽ/saŸg¸IE2å,zÒ1Út:’kLÆÓçÎÁ¡ÍíÈ™壋G)æÔ{7ÊoðËÅnd¨ø¤è·ðá•{@rõP˜>ÆkÂwŒk×½¾¡ #¸kXfy‘ÖEÇ÷šÈA©ÍBÂ9ÂuM°ÛÞ4P=¹_Ól’ÆgW®Ø‡ÝN•Õ#–_n™‡Gï¤pp ,Z…ÿUu›6È“÷ÃV¦›Ó°¸å0EK‘7*|·ý]¯{ü75F\éÔ¶»úzQØ z!á‚Ç uH€>îÿó¦upš²ÚöõTÙ£»o3P)ˆø´[à^Õ6ãÖÚóã` -šd&á*=¶%ÄÀÊfY’<¿^’ƒØ·`_6¨ßÈ|h¸Ìë3Ø¡>€„2 Pºúqÿ×7ÏŽ³ ýÕü,Ns¾j»F™=BµŠü` ¨í³•C§òöiŽU’)Ré@LÅßÒ®„‹ÿ‰·Ç§mb<2FH“Rq°²ùF½åãø÷Xºi䎲õOm¬GAýÝ·ôÒ}:¶*¾Ëu ÄfØ:@Ê«RH™.òÙ6Âñ¼±Ã6Žjå§cæGOpO- ú­6HÒýúÜÊKÉJæÛUÀÎì:ºJǃ¾ŠýÉv<gzŽãŒèñ ñÿ1F*qm™-;“ Iò�7 ?ÞâOì(Yr ÙdeÇ ÏÉFÊ å™ ÒúÑ¥ÿ–rÅØH–ËÁaìÇÇÛ¡è¥>Æ�,¡•¸¯3ÿ‹DìZ‹¹EñÊÆ®ÒqqðìØ7p?¸ƒÈŒÞK¬÷Å%ȧ$;â¼?ýQ¬r6³pP7`¼a™†¸é^=„„ýÉRç¶_†õ™³)m£„Ç>ÀD3#£ ¼_' çIþÂÉ­uÍ‹CÁÊ-Rne㯄³²Ïóss•ÀîLÏÌ<È­/µàR)|Lt_1»éòÁ<uõ}E DÈzlÂñ$HÓ+ïN_2ì¿scÛ¯-òrH‘V. ³¥ˆôÿÎÔÖ'€‘…(} ào ²í:]謧Û6§Fhlw±†¼@ŒÒzÆ{6ºP_™? ¶ EëÒÝÐh³¢öß¹£ƒÃv¢æK« /ûBé"MÒþ²h;À×ññúçб¡o¿ë)gRm Ã$¬5¿, ”Eƒxü(?ª:¶gÀUëµ…F¼4ž™êÀ èàóµß¹ÃE4Œ!–³q?lä˜õA®õˆŸYv´îs:mRª(Gÿ°ZßyÚGq„+w0)NzûöçáuˆYô-Å&•§èÀ"¢Y ='I†ý΃8ð·è{»™mˆL/~„¹ƒÂ!þÇûÿ.ãBï®àØÑÌA=¨žøç¼±Y™Ë |zôð:f‰#¬oh¹2XjøÇ¼I|1ÖØi3A(|ù§vf1Å¥Ö NK€ˆšLÀÍ«Ú.ŸëÓë?ÒrÙ]ÃqBS ^#oòþ.l€%zââ‹ ¯Ä÷YÒã~iˆä”ƒP®�ˆqëu&7(„ùU;B¡’l zFëx׎³¢‹M›÷Ëò ,|Pf VõÖ ök‚‘'›NºôbÌ”/¡$EN•¹ª HA×iÞûQ =‚u-/TæQAD9“£¨ÒgÕìWíðà%YZï®\€ŸÚaÔ¥¤ã5O­jr¨ËÑñ©øu"9ãÖBØzpƒÌ¬Övl¥­l= ƒɸYìèÇyŸܾ5tý…¦Ò ×mEƒzž+üªïM±¾‹>¨L¿kÇ=‹rr 4ùìê§ü/gýšEÀrþÀ~P†¦nBß[ ®\g[{¡«‡’g£ãYÛvRŸW'†‡ {Fe°m1ïÞŒ{ Ýw¾LÿÕ;7¨&$‘çþxúcÚøÃÐ0Ÿ ŽžnÝö‰óí&úÚuÅ@5sCèCÕ±mœñ8Hƒãefñï¹Æt ’Î<PJZÿôް@ƒïùÈÜÿè¡»4K|®#`}aŸkRNâÿ '—~IU!ÂkòW€LŒ›Z×õD˜NK•Á¥÷Ì¡Uã £œÏÄ÷ýÝ;´šgÌïL~a(]å¯Þ!Bjvè(ÑfòÇõ£¿¹ô\·óBå}’AuH÷R¡¤ Î�Õgë÷˜îMî ¨<7‡ O‹·:ÈíÊ[÷m6uívöŽÝÇ;3Žæµ=Èüîwé§wŒnèû¯ÿøú—¤¤3pKþÎM¢¤¶¥ƒ¨«{ó.�t ®"¡óntš?àëdiñ°bÌC6³ó=°ÊE ³ ­Õ…,€¥Ñ®OÈ ²œõ0¹hþv‡ËG’;=ºïõMV%¥ö÷›Êªˆrü§�ÀäÂ4H 8räÙÔKì€ÉxºíAô:Ê2 ÚeÀ.©¬×ÝŸ0N<gëäƒø™'ˆ¦ÊîÍ6£é‡%ÁÃGÌ1ÖÖ·m}î¡^j®níÒ½ÓSý0 Cz‹ÇíLX†3ýœÈUƒö„M;^âþ^~Xc°½Ž€aèvGHu"áç 1ŠókN×KýT‚?,ˆÙçrƒ=îÜŽ†X}6CBW6Û»�Fߨ\î3–m{4!]9ÿá»­×ÜJ4néØ5JÓs„w‚Ü^ ªDŸ÷h¨‚ôŒzö‚»¶£ßý8ÿ•àPë”]—zðóº1¶x¥â~�üµJ8#c¾%Ͼ®·cF{dó—Ýߺ½o÷ˆ@wÅ0‰QsP¯ã¹š_ÌÎ ?3yB2Ä{|¾ÿ5³§¸‡}Ë>x{q(a¿²ÛÑ‚a¡?€ŽÐþQ“%ò§ÌlÁ¬ö4ô‚¤Ï‚xmWI׆€Gí¯¦CèÒôì1ê’Ûk×QÖýŒ3iJhÜ,Çÿ€úãú‰KºšRˆ÷ÅÄð¢ÄÂÈöÈO`úÈç…ʲ»†<!ó[ž¸NwÙô¶aÄÜø¶¢Z€ŽÀx‰\RtvšÒ^ZJíÝa\(ÊÈZ™PE–ëÿî 1ŠšÞ£¡hŽà÷ìy0÷S�L!ÈyÍQPÌží#R@Ó±&4¯aŸ9'2ɞċà¶I¬EÇ8XÉøIrÕÄ 4¨–*yžýbϋ˼Ó/#‰ x°ÝÑÜ;Æ2R~�ª‹õâÖáO7Ïí¢hï“Õ˜UŽó^§kô »š¥ã§(ä¾ ,¥ˆŸ2‡ü×)ÏC÷:(Ù;—Q3>½þ4á)ú%ˆùÔb6îB8ý\ ³�pµõšÉì«e<êºíS鹂ØìÚ+ÓjsðÄpŒ„¸ß%<&t{3?Œ£¬|N)p7b™Ôîãé?Ôa¤iäDµWl’¡½ðˆX—ŸÀZÚ>;uø)¤ko)#WáÈÍSšn®cR½xô”{[ÀsXv1¤¬95‰_¬¬0KéõÁжՙ7Ú>ž�Tp¡5‡‹¸Ù´¤l3¥Sü"ØêLXê…ç«[á5mö¡ø º¿Q�="u}ö‘ÆpϘ*xböÕ‰ºîã—ã#iM+³ù@»Z! þ·Ï®~jàÒY”ݬ‘¡´Ò$?5Š• mtêuˆ] ‡%Ž@Ž÷Ý…:4h8Ûƒ¸˜¡»tuì3À;ú ΑO¤1A/r‹¿¾™ ÆÏR*5ÀÇûÿËìiÜ&j#Y2:º$Z(a­dæ@ß>'z ž„×L¬¯³¬Û뇶©½6ZÑÀ8|`Æ6Ý"åŒX1ß_€z' îF-©÷»Ñû?°úX^ò A:?1¢;ØÌh/KžVB'õ üvOnÏFSò‚¼É õƤê°ïÌÞQ{=kh7™ÀMå¯ÀwXQùpü\vïÍ“ÎO/ÿ¶.ÅöÚñ¹ ôN3·ÍHKRðÉlŠK–"›qò”‰^Wܳh¼1wtùã  h@§¬Ñ3ðe6þN|–’¶Á©‹I;yîó?8t[ƒ[é!‘ ú¥µ$,ήL­·e–"z¦å%IÞ†AêkÜÌRäl!3uú8àÚyßë?_žWÅé½)ƒAbCÒõéõOù!rz¿„a¢¤5S±ÍnÖ—£³ˆ#Â<ý43yÜ6"ª ÒRýêÑô߃C‚Qå¿&>¸[¼# B�HÍǽß{v¡eà×kOÃ×TÉlq(UHð͵h »Ý”8º,@t°µöÈÃÕ‚LÛ{p´•ü‰/Ø*ËL"d_y ïŸk,4î GÌ–ýÑbD>,ÁÏ.ok"ýD;†|7–[.µDÖCíAœŸä#‰iÇæélÿü¯‰ÏŸ¡IÖ¬ÐòâóÞD¿q½]+ÞeE •ò–_«-- ™ƒ¦ Ú°c©›³èç€^ø¿¥Lô˜q±1~ëCßC“ÿ”øžC“9¡ŽgNäóýÿû“õHÈ8Bkhêç«JÁŽ#Z¤-`úVo§™MËa 9r$�îÕºZ-¼hókhò ?C“$· û^–ñtÄ÷¿9d(‘8PÝ…]Ú¶š£×w[¢wléÏ;µŒd•Ôn—׆ôoÎK«èdù H¦Þ„(Dú¯…¯Ÿ¡InüIÌ Mïãü_(�ù¼ðœ’îð5)6H/öõÌYÍ1‡¸ ±QRæŒk,nËÖûXH½­ʉð‘ƒÊË?>ÿšdf“ç&6³üü½^EJ–m‹ªétÞÈ{¥C—µ›½ÌC¬c`½îÙ0Ê…v5ÃÂx<äƒó\9Y·Ýÿcáû×Ðä}1Ú06"×´!ÖóŸë9êdl:'– û1H"Á<HN¶&] Ä5Ïö6¶9Ç!Ií1;"ÉøîYxAÏ×K-—yõm|hš d ¢"]ðÏ×ÿÛë¹U¹.ak«gbbw24¬¦ý˜ƒÀj-¹ QªÌÂ�Od–-ÖÖÁ:NŠ dG§—Ë¥MÙþ¥ñåø÷¡I VøG=³Wø!r6é›wÑH3ó±»ûÒp"ñ×Û‹ ¹¡‚£#g6*x¥9ð®„ïk{H®<W¨öíÜBQßOç¿MVù…{KhõŸ^<ÌF‰W <äµLÀ†Çý:w$|°oY€œ-Q]<Ê«ÍÚ!á!åž¹ûðFÏq@}3f¡Rø%»˜oÄ¿MŽ£Ðr¯Dõòñþ+ËN|ìYÍYü™Ž6ýj—r1Ñ1k4øúi'XÉüfƒ\:Üe®Þ¼÷ Ü~¹P9šåÒ1íß³ ö†&7Ž8Q¡apeõÇñï†èöˆ5 9os¦MÚy— õK-ÑÛuФu9æÜBdx7H‡V™¾ÖØ&¦_¨¯!Cò£lgL ÿ04‰±·yS÷¥}|þqÙ³ÞkÐðìÙúÌb®s:fº'/Ðü‚Àã¼³@!þ]%¹ƒÜz#×=ÄJ¤sÇ`3—W ez<PIGòC“‚®û0¨@è4íÇû¿ ÕÞû5¸5gµ•xÿcŽíT¿GôÜûUô#¯RÔCCÆ?tdxÇô†øL`ŒÆ8§õëédgsTâ?M6}, _š“ –\‚kÙ¬Þøžlt΄l¯s ‹:m"2×ã5·be\]\ò Ë›Üä{xaßLo¹‹QÓlPwK7ìé?M�^a,Õ_þlb(ÔÀ1‡?ñ¿ëƒíóÏ3“„ÝŒ^7¢Ûö:ð…ËÞƒÃÃ^ºus¬ÏšqB¹8*Áèh€GxŒ°YþC“m5ƒM~í{SgÀ9nè‘RX–C}[ù«‹ŸhOÎtC›—1#W3è*šû:;½&_‡GÛÛ‚´&œH|‰ÝÐàÁè5‚L‘‰ÿ<4Ƀïò\b¦ûÇû¿†—D?]fM{V6*‚Sä<‡›ÙÛe™0, !«Ø A´Ëؾ¼çö…ä¡öŒK¸Ÿm¤œmÁÆßÃr‹½O÷oC“­¤šü¼2‰ ÷Öá#ƒÃp'$´FË¿@!Ò{0žV„¦YW©ØÂoe­,©Š'ª‹H'º¿÷`çrý1ÎâÚèƒ#šÍ¿MRS–ÝYºß’ZBÐhÄ|–x²·Hó@ 6ÛYziWl„wQÁ á}‚yqsà­ì³!`«³~y#¢-OÝ Õ‘ªö·¡I¢X•÷mÖ˼þñ¨ÌyÏñÑõŸ|ïü*0o@¢]Û“‰^(`PÊqí«Âƒv¶­ef·éÏvî'šOA=B€ûŒƒÝ‚päïC“J# ¼¨ Öžž§ÿq•æ5± RÑÃëwV&í…) Ô©ƒÙn@poïç²]ÝÌ{3¬v¶: úÇúµ†ÞÃY‘èÍf*aWïÒ_‡&' Jk0n¥‰¢¯D¸xèû ”\/H“ÜÌÉD áuÎqZ–\ÚŒG+啵X ìZ¥T>z'7ùQ‡q›„¹Ž¾¹ÉŒí#KâR.ò/C“»VÖÜgÇQ×Ȭ¨åéãó\ âì`¸·?dÜÛ1y³”åuMÛ6Ƶ8ZX]8Ãø^p…ªwQëE¾ç &­1frRšÁKiûñçÐ$G¤ÎÓðÔÝœÛÇЕŒ¯ðh3'À®Âø”·“Ç{¼±š;;Ö~F öKî37Ðkš–Ìu<pöµdÊŽåèˆ+C¨š¤™ Rá‘÷Mz¹Æç¿7)n�Ò€©æöÔ lEGyÍl½‡:Ì‘ÿIÞí’o±Bì<A\ŽŒš\6dðèýF¦àqàϡɅQ‰[âµ1<k¨îÝNÃ>Þÿ—S%|ë‚ÎЕïsTuÆleÁõ’bšA}A¸ëæížÍ´þ1ãý0ÀA{ÉKù“ʘÓº¼tjÑòÇÐdLI=rž ¢PRgóûÇó_Lb¸R³£é Åžël?«â”ž)!°Ö[«‰FÂæoÖç wi&k^”CV(t@püW2Ó÷²ó{hÒxH—GRn²͉ŒeCbúxÔ‰°ªé6GÁ³©÷‘¬Q…Öd27\ÌØ«dœS‘É=\»F§f*¼0é‘Û£�ÜOPúÇ5(r„Zß™xQ‘Z>¥~G AeN-õãùÿjYôÜ7—Ò¾n;ún?Ó¹"P·¯xÒ}‡·•/àNäö�ÞW:ÝŠ&´—×¾†Ù:x" ꭥу;†ÄRç펔¹ ®cä›…Ñ™õ±ñÜýüýElmG§a= hò¨BG_æu…³×YnZì«­FYs ôUéµ"zM&Ë:ËÝGn¸Ïuí.õDX‰ƒÉ5XnšÁ¡ö›;Þ}¶Ô«%XO?½~2&ùÝØî¸Frjj¢¢…8ˆ› yAÊÆä*±W ¡³‰€©ÒIÒ˜÷“9/¹§u‚b)õZ³l:ë sá¼¹ 8²5ÀÀJõš>~ÿi´œÐó˜I<kí¶ ˆÙ¤ã^¢S×xš[‹è²Ös€­GD¸áÀã(†�+‰—"E£¹³HnÖ†A_›á\F° Zù½Ù%ÒÌ‹’ÄÒ?Þÿ4`µ¬¬w×_{Ù7¡¹"ôÝ0«Yíñ®@“f}˜¥¶ÉÿçÅPEj¯mÈÚv:ïQȈ¿ïÒÞrN¾¯[wÌôzà*ö±Š5‹c?¢jŸÿ唬”f7µµ—?K_ÑPÑ', sZ(oT |‘êÓ\-%êè”’ûh„’ìyƒÁøÅóÊ\ cK/ ˧YGÔ»Úþ†Ñz&c" *Ç(,ßÑÜÿ·yíEŸq(šy˜[õ¼²q`åa 7XļÝà~ÿÁþ¤¾R®¥Ð/æÉ{h’h…ñÌ"¦gøÃ=w˜Ž÷Ý ûÕ—ˆŠ„?úÓéÿ̶‘uNh{Ügóú?tqªžˆmí,å¢u¢[÷YÂóÚotÿ¡+ô€!«hfÚç.2]ìݹ?‡&•œwAáRˆ´¾FÃľ붾Ue­‚«%ýdÏËl³iø‹Úþqþ—Ms&ç6™X›w-&ÎYí¾…3(¥­™G9‘¬{c×Ì֬ǿMæÝ;£¢­évÞðú€n"—Îíbµ¹)½<ƒ×¾ÍÜñ‡e_ð1¶üœpèè÷ç}÷«11ôÝF#‘ßYXƒp¤q]—ÜsŽš,[Â%*&¡±@ƒD¼fóÃÒ¹A‡Ù™fs” ½Ë,¨ƒÞ>¿þ3YÏÔ•;ç:#hEL¬×[ROd‹Ê^GéšAË©fß~Y!ýËÐäEåêñn·ôü0¯~Åà/«AÝò –Kåm÷‚±>^ÿÝWY¢q†"µ¥â<цFвÎë*c¹½:xÛw„|¤Ížw­—%ýehRg°åØúæÜæd¿9ç´üÌ•ªËÃvž3Àv Dg™hç>>?ÿò3é‰hŸYDkgCã(ʹƒªÔ•ô×SÉ·†¬Ôœ|è 2QÁü94©(ñ½?OG•Q34… fëcc³¶PopT€Yaƒ–W(£>Çÿ@­tãX4ˆ`ðLG¦Ùžp•‹É„ãaïãšÅ°l\¤[9‚cû26óâU M6f,ºŠò¼Ë�'›¤…žCÐÖñ4øi<D÷n²ï¡#øxü—г Hz5ç¾[ª ²_©ÏÁ·è´QtœÁm‰vNËC_Ìñ` ‡xèÑüâ~ Mb s�×PEx»†Ç؇;âÀ÷cWÁŒ*n\˜Ö?™ÿ׿vƒ:Oõ±3@f¾ƒÂÒRÏ&ÆeÛòõóïÇm–[mÙœC„‡ê5f(ü MÖäÖÙNi¿ŽYXÐxШ¥æÕ=§4 yÄHO‘<äž0|šç3ô¥ÌÌ[ÿöB :d1‘"ZÙO$+Kx÷iÌ’=ïs˜åJ¸þ€Ôg¦ˆÈ ~ßi[Rz'†¼šÆGž#¯v‘—}Ú>¥?W~p¯sÏ ?žÿk³ÞA÷×KÃrŵÄÅÎk@–Ið|>^xðs¸?ý\Õð`,DèäõÌ’©Œ°Žû5¯éWÛüÉ^£èøçw €DÓµMˆáøXf_8<%|�8_왉pPó1†…ãî„WþÀlm߃˜“Šf?4žý¼»:½òÌ“_£Ô”v ûûMà;kž:pÍÖ²â_ÖùásjØŽqw]$F‡£}ÿ¢»y« ××û,b'Õè°N‡Îþ=Ôo¹öÖôÔ0, õ¨Çÿº»â~–ÆM‹ƒÄû Y•R´‰¥4â6+!”}@~u‡j°ctCÔúàõP.ÅY(ýxÿ׎ ½×zµ?70ÆWXFÜ£¾oŒ½·¯‹3z‹Š€0°®Ác8¨R£êG±¢g›0àö ¦T—Uëøò„½»‹w­"/4³ÞÖ÷¿¾îC¾Q`[{O³“ºcÈn¯]•¶+•{Û{­ç¼ÞÕÎ N!3•<®ÞÇVí‚ìyxé,!C æ™b². êlfÖ×åÁø'„ÒÁ\ ןÎÏíãëgu,μ·¸šw-/ôß3Û¥ùºñíN°íâX(›c ƒŽÓâoõMDð‘sÊ¢a·#ü#0{c ÁÈÀð%µuDWCB¥Z€AéÍZ6»,Øçûxý (Z%‡±µØçw€ÑÀáŠHbhTb2ùþ<$÷Æ*cÀ¼ænk÷³”_÷וð«Ð÷¿#{D+B<™!âÇüS/¼gÿÃ`ø9”­.^]ŸÃŸ™ÆCíÌ+>™ì3ïƒ+•ý5Æë]¤q‡„Äp¦j' r¯9µ¼FDȬ)~: ã躟—9GmÜì“x2’¥ù-?s–raG"yvU³pa;R«çãø÷ăœ ÌAŸ\&ú¹“ ÿ?#Äìn Ûí0Úee½´“d~o’qå¶­¯!�!DzP^H)>¾oµëÈ‘.®Ä¼‘Ô¶=Hy»7´S´-M½ á?Þÿô8y£c¶Î™ß§q„|Ü#Þ5"ù2Б ‡lµm#—ýU‰ÑÊ»ìýeüΤÎV†ÎÈbMƒ¤Í˜÷jAÌc7¾Z ä]> 4½gbö Äýñõs 2WRsKgí6Þæç 's8qzñTT[”R›[wÄ�Í)I‹—9ø5x¥ŽÜWjýÚ #”!nN+zP’ÄÚ”â ÁKgâ²ÁÞTEŒ,ÂÁùÇë?³¥{é^R¨DÝ¥=´R¥u^zîc¯’§³Ì¥&D¼‰'i74øSËJ½ß”í&H¥æU©Gà»[û‚ácrÃͦŠ<ú’‹¡׿~þ‰4}Ú…žíh¢°Î;¯üòlpAZð´%’XÔZ;t®Q?„±÷÷žóy™ïk1+Ƴu6Â[«©ÌÖè† áDõ™c4¿ÆœÚóÐÝ*d„•B#!}Þÿe>Çsamh¡¹ÿêG3c^çæ—8u9󼵕⸈߂ÏUéy‡‡B;f "Yi=ÖD§ =Êâ‚Á4‘íŠ&¡Ž’Þ×|¾Cý“Ò3»Ä÷šg]Ø~üþ›WgjhSIXU“‘"1A5Fr4×{üáÜëAä—éljŸw¸TðÎá–Ýt6<ï/NÁ  \û¤õó«R¥tÇû˜a| Æi¨ÌÍ>‰T.šWo>>ÿxŒ•ϯ¼Y¼æÈ{ç··�m,J²{gg}Év~)ê]Ñæs!?wøè÷X›‰æè˜G—F°¥l!7ކUœÖ|Cnáfï³…:.@mq%®Á臔±ÜÿÓRu?.–:¯èaBë¼ÖºÌÌE#Gƒg'yX«Dåÿu‡SWºä™ÇŠD)Œ˜21×ѵ‰VµˆagW¬àP޳²q½ç«ÏÈ’Ï Ís”?¶•@åg")ªíªç©s\ÖTòâô{Þê«f3g÷‰oÑþÏ^w:^ë¼"�•Ý{¹ªd#³!φtà}©,nÆyWFKv„X”4–ƒ|<ûB+ è®Â8ˆi=-;´³X 5l=/xlêóŽw•–å÷n³]ì à+SÛÓ¼,{Õž�¯/ДâV�¡û»+<< ØÌ¤®Ào ŸâÞçèÔ‡eNpù^Oÿþ¼ÙùŽOv qR¶ £wHF3ûÝß=oý;ü`~k’RÏwCßÏí²”u¦ãk¡jE˜|û‰qÏ©ŽÔ‚KV,Ï àÏ*?ÞÿþxkáÜ}QxÁU¹éœ/MÛüÞÄÂá= ¤Õ°pý¾Êæ=çŠÎ^xúBË÷ÞÚKx«§Ó@ð[òÎI™¾ÔYB]Tª¦âž™çÿúÑKqÉ.á½€PÖÛwÿ¼ÃÓAG\ôšWÂÏ‹Øâ9ùãÏ2S³—åA\è“Y\œßy=ǨðGj÷¾ÌéÇõÕ¢ÂMî@âŒtÔ‚¶„vD¾üƒzÎ+²ÙÌBĺ\·Ÿ¬ü¼ÃÕ¬…÷Ùë6ËÛk™6Lþ¸Ê¦ÚRß_rýnl|UAϯ< ¢¹Ë|¦²!‚¸;ºÁ8™_1ÜgésÞùÆCŸ‡ÿ¿ä >êVB‰~æ,¶¹® Ë˜_ÿ&f™äÕjpñ/WÙÔÊwa�ùO ¼š°H 3ÉÛûþ¾I`˜ÈòuØù»õ¸1êͤÉû·ÈÏ÷ÿå+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò•¯|å+_ùÊW¾ò€ÿÝš™w)¦÷��AIDATxœÅ“±KBQÆ7¤1áÍ-Ö¿ÐÔ L[üWl·9:ª“âÔêæÈ]†õå!‰ ¾÷à-§A+-z8Ãwïwœï;G‰»ÄÞNÕÒÀQÊp”*9J‰£Tjý–Zã’£”±U "[ÙË×Z$ ¥Ò‡BDÂP|­¥Ö&ÿ[D¦‘×ßD|o…§“Þࡹn" ‹9Œ]Îæ3»°˜ÓM$©@.r ^†bDôýGv@ÊPâ›|õuÚ+áæóž>?ŽOiœ˜"?ºÀÀt‡`kð–Ü]\‚·[cºCDÚ8‚Ú¬Õ€À§™ÉcÃm3“‡ÀgÖj0‚Z¤YH[P­ƒ\Á5pp…:ˆÕ,¤#mb€œ¿ 쯱Ä"Eümüÿ1½qé�±´wã?����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/values.png���������������������������������������������������0000644�0001750�0001750�00000000657�14517772113�017065� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß4™„µK��<IDAT8Ë¥“ÍJa†Ÿ3 Ñ¥D› M¡P ì‡#ZYBAwÐFˆn $DhÑ"B0L A©¬@¥î .¢ÓBgP‡Æ¡ÞÍáãð¾ß9aX2RUUÕkŠ€º �IŸ<wç¡®„P÷«-ÍšƒªbŽ6# kæj½ÈÆÎ>†"â£ÝÕåÞJ†á¨Ö‹c&'L7Dd¢eYض=1¶µÇâ’À¦1îìê7@­l#—OÏ]¸N„‚8;u(Ç©u�ÿ óñ™@óc©9ô6ø§Ìq?ü&éãóAL&“’Ëå<ªª+Û)™‹Æƒ„¥™[€§Šƒtï[žûù% bìèB�²y³?…ºÓÄ£ÓæR¥ƒkî6xÇ1PÇ*›wxo½r“9õCtÒGû«³“´ký“~�»o°}.qÍ����IEND®B`‚���������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/experiment.png�����������������������������������������������0000644�0001750�0001750�00000001410�14517772113�017732� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��šIDATxÚbüÿÿ?:H/kž¤20Áô™]µYÈ�Ä�2�§7üðþßÿu{OüŸ±xíÿõû΂ù qtµ�Ä„n#|úð~Íìù‹45uìÜüÔ´ô@|8HY=@�auÈÅçUÿ¿þìëÿÝ7¾ƒqbA HB]-@�±0`ÿüù füþû— h§,÷{°8ºB€�Âj@xZI®’’2˜ýç÷0mbbÉZ$\ dö « FäXM)’R5ºzz™a¡a ßÿc¸÷ú'XŽÿÿ{Æ×'f¬=;ÈmY=§ïH €à˜Çÿû÷ﺰ°p°æŸþ1|ýñ—á7Ð ü™[Œ!ÉU2¤¤¤ €à�s¬mìÒåÅ™ÁüŸ@Û?~ûÅ𠨄¿þøÍðŽIŒKÖœ!Êüo:H=H@�ÁÃ�hY.zÿDExDx^1|üóœAOà2ßKht10üýÏÂpë…0Ãnn ú Õ @püýûWD‹2?óÙ™~£%†/Þ€™?¾}…« &XâùóçÏ7˜ZŽ¿@[ÿ~gàøpŒáÓ]8þýñ%Ãǧ×¾ûÂ�RÒ@LÐÄôÿ˧«/œ9ÍpãÆ-†oÎ3°|}ÌðöŸós >|`¸ûÈüÀÃðìíGpà‚Ôƒô< ^?{0eêšÿ<q¿ùCþ|B¸üÖWG†//1ü&¨Ÿ¾3<ûÊǰ|ßÛ5ož?œ’ x:�º†MFEÇ@XB6ƒ‹Ç‡‘ähàÿÿ¯~|û²åí‹Ç3ŸÜ¹r¨÷@�¡$$! pba fÅ’HA!ûä`f�@€�Ö]mÿß����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/zoom_out.png�������������������������������������������������0000644�0001750�0001750�00000001216�14517772113�017431� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<�� IDATxÚbüÿÿ? ø…©L 6b^ þ Ä'xúÆu«×1`�Ä3ÀÛ/°LFI­ÓÚ=€AR^™ƒá×Ï ÏÞe8ºsÓ{·Ê·nZß…n�@�1€ põð JÌ*ü¿íôÝÿ÷Þ|ÿÿùÇßÿßÿÓ >H$RRŒˆ dÈ?òí<4%DyX"ÿþüý¦A|8H¤Ý�Ä"~ÿúe¬¡¦ÊÀËÆÌðûÏ_ W‚ÄAò uèr�6àçÏŸÜÜ\ NòJÂ0`Óê¹ y:t9€�ba--íoŸ¾|áâå`eh©-Â0àûÏ¿ @y†Ÿß¿}©ÿu�Äâ(*)_»s㚉¹%ƒ¶Ž6†¿ýf�Ê3|ûþý²f� p ~ùüyù²9Ó^>Êðý×?f&&Vf0 âƒÄAò uè†Ô@QAA¡ÎîÞÿ—mÜõÿ½Wÿo½ü ¦A|¸  àkkëÿèÑ@ƒ77w­€€À â¯ ÄgggߊÓïß¿ÿwpp@1 €‘½ Q %Ä|@Ì Ä 8ý­� ®ÉÌÌb¸~ýÃþýûAz�ˆÝIH.bDã‹qÈ%@Cà. œà0TÝ€�"É�tC€áó €Ñ¢•(� +!z 6@€�QuèBô����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/base1.png����������������������������������������������������0000644�0001750�0001750�00000000363�14517772113�016553� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEà /Hv™v���€IDAT8Ëcd```è ãa 01PX ôŠ øó÷?C^ËRFR5Oª‰þÏÂÀÀÀð÷߆ÏÎlûßÿ!að÷y>øûï?#4¨ d„à ƒZ_NÊ€“‰…™‘ätðçïD:HË*$ÙöéSúK0000’k��ŽŸAµš6à����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/cancelProcess.png��������������������������������������������0000644�0001750�0001750�00000000744�14517772113�020347� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���Ù˰���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��vIDATxÚ�%�Úÿíííââãòòñöö÷÷ø÷ùøøøùøúøøûüýúúùEFFˆñÌ™³||¼ŠŠŠþüùù¤¤ìçÏ_¿~ýû÷¨óãÇ�ÄôãÇwˆ �J000011±³³³±±ñòò\¹r €X>þ Ê;wÈPUUeff~øð!-##Ôd�Óׯß~ƒ3qâÄÛ·oß»wÈ�rYYYYXX€ €�bùñý;Ðz " üüü3fHHH�@.Üv€�bùÿþýÿÿ?TñâÅ 0`  €˜@›´hK@@@FFqãÆ  4D'@�±üÿûèaˆVˆ-@Ý@Ä7ß¾}2�ˆåןß@EŒŒŒ@¿�] tP‘ššÐì>@ô‹ˆˆ0ô€@M@—…€€Jn€„œ´´4@�1Þ»w÷Ìù³î?bÀÌÌ,� �B§åTæ/†����IEND®B`‚����������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/analyzer64.png�����������������������������������������������0000644�0001750�0001750�00000005562�14517772113�017565� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���@���@���ªiqÞ���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<�� IDATxÚbüÿÿ? TwNGp†1h-Ïd„±ˆYEéQ ¼<<ÃÒ㟿|a蛹 E €XÐ}ÿñ‹•õ÷° �ßÐ@�1¡§�†ÿÃ8�ýöÍ�Ä„®àß0€X" €0²À¿¿ÿà¡ôùÓ'0}æÔq3KuCIŒ—î7t�@¨… ÂÀÛ·¯±²‡š,�Ðý�„V �CéBÉý»wàrÈì¡&&¯¨ I ¿¡åp€�¨ÿþû Ï62ÉÊk"Ó¦­öMV&Uò7ºÈæþÿ撚ý�Ä‚^2P¡ ¤–§¨nçŒB €°¤€î&„ùâ7TÏF�üÿÿ*É`pÔ˜�@µ�0à!¶}˜4½ þû -r#üûÿ®HðòOª9Â"¼k�ãÿ?´!„Yj�€òÈßÿ´Éƒ Wüò#2� ,)�QWJ™¤PÍòG÷n ˜ÇeÕàMaô�@ !pA.^^^†ƒ·Ôˆ¶ÈÏêÑj?¾yÁÀ/"çŸíj¦ŠgËj1ìù/1B�„QþEk-ÝM¾ŒhÉ ŸÔêYý»Û·€F0BÍù6" eDdËÿ!¸T!##,ñUƒ˜Ma€�÷û"»&Åqüçx5ˆ¤ÍDœüÿ$`Tõ €}gC<ö<̘*›j?„Æc¨úèßÿ@Ü ’ p�|ûÉ +"k) )€œÆL1]=5=¸ìøí?ƒ„’%Ã÷_ ò 9€�g&&a6V^†ÿ?@… Rwøóg†`£³D[þì!‰CT@óa@£²Ž*ðì!f§ˆGP ZBüò+0µˆƒÄ�ˆštDþÿûm)!¨ä†j&¾¾W»í¤�ñóD«E¶ƒ=ÿQR(üg`bd�; €`… �¬üïÿ?Šc”‚“¾#Bÿàý �Ä-Oxáyÿj]ùŸ„ Š¢–È‚ó?‰À2 ˜žÿP?" �4ip€SÀ¿ ÀüM¼  €X`©ñ, u‡A…rAEl¡lD¼ƒ^>&¿à$pò‹B;Cˆ,�KG�ÄM<@ƒ¡(õ&¤ää!Ê’ïß­YýŽÓBDë±W»E’0{Û4àÆЯ ?ƒø�Ä+!¡í Ù‡!5wþ'±À´W#¯Oõ^þÇô x�…ÊÆ˜>¡uÔÒd ,`eÀD� x �gæÿè`ºøŸ^zþCk°_¡‚�„È A&Ô64¹… )êƒî“ ž¼BOQü‡”°�� HÞ€�Ë”>¨dç&Ê’ŸŸß­–õ»Î “äi7ã·p{“�,�þAÅ�) †‹c�– ʸü�Éá)� €P³�¶î)-/JˆÄ˜Øüð3 �¼ø €Á^’c6ÖB*@,°áb,MáÏR‡¤RŠ´Rh¥ÁF¤õµß=G°…x„0šÂ0¯|Hì/´%ˆœ@… 7q-µ?_ß­–õ”èA¶a9 €à)àï_äY“áÚ@ÔLÐ�@ðBÖ þ !H³6Ô@ˆ¦0lâp˜‡�¬/À  x�  WKƒ©¤D�— J•ò+¬ Œ€¼Œ„_\vx ‚À&FþcŒ�,üÇ2i0,G„@)�¼”äe`ØÇpf#ià”dаŽbP1ñR½sf ÃÍ#˾|xŽ"®ªÿ€~}mV�< xú†1蛚côï?#CG]XÍP çÏnìb¨l€Uþâé“ K¦4€Ù� �`røõüÃçQ² I202³2T5÷3´Tä€Å{ €<r]Cmdž_oŸ0üÿû›á×;ÔTðëù]Øè?@�¡‚ÿþ…ö'þ+ʯŸ€fêþüøÆP4°¡$¬ZBÃaPzþÅ ÇV514ôÌdøöôï/õ=lâ6CÌ$…�€�Bª€1°øöPþ/ØàÚ‚$ÛÈf~‹AåùN0YQËÐÔ?áËãë ?ß¿Ä9ùò ¬ ÄxÀo`Rùõ \J2bégþzñˆá÷ï? Íæ1TçÆ2yæ2|çTb`ãäPÿúþ™óû=†sÛ§0´N^Äðáþe`„=‡zâF”€øö+¬É@ð,ðóç/†ßÀççëÿpúûÓûÀ@ø ´h10âU �yþÕÍs _^=Fs9#<Rÿ3Bø?þ„g€�‚§€_¿1üüExQÔ»'wþüù¶p0gWO1|zñcl[ËæR �@¥#‚0ðòÿ'Úµ/°È‰ÄÈu0iÆõN0Ú;ÄoÐéóo™™ÉGoÏx[JJí!4’ÞHƒ 4Õ€ <Ä Âvn•þË# `y}!!•Ùq‹0opë£tõ\<;ÁO�!zƒÀ³(ZÞA.àaôÙÑŒH‚Ð@¼da@ÒƒCŒhVÿGnÊb‘üψe(Œ±„I 9‚þýAŒ "�@³BèëéA±þï?ÔnFèÚ¨i ÿQÃäÌ&æåÿ ·ÉQ”´UÙCýðQ8ÃC2€wÔúÿpFDÌÃB€âW˜0@�±ÀBèbÖëH$ÌCˆxûÑãÛ ^É_Ç£häÆ ©¬O–çŸß½Èð÷ò,xXCCá°’ šJÑÓ), "' `äüƒ,€�BjAGKQ’&b…Ö”à€öÿ?RÈ¢$EFhYÂÈÀÎÌÌÀÊ‚XŒv÷þ#†³—¯3ðñ2üøñƒANFŠáùË× ÌLL ŒLŒ †ºš "Bî+ PïOPªüÏù?A FP€0B8 7ÁÖIýgD K3‚Sòž€�BÖÿþ#՟Ѐø( á¥##¦% °X‚Ðll, ìˆ�ÐÖPcb�Hï·?ÿPR,™3@“:#ÚŠj-/pÿþEd€�BM XÿÿCK]ÔÒy”…Pˆc€ˆoô2¼9˶ÿQ£cÿ‘ÖûýGÄzzÆÖªûc~�mÒ•mš�y @�¡d?ÐÑRx%¶ô$y1@ªBXÁ/”qÖ¤‹²°‘ZšÀË%¤ê‘á?¢ÙΈ’ØP«X1" =ØÚÂÿŒhñ%PÀ©6ø ”ð� ˜"ÂK¨Cᢨ$fC5Z ÓɈuTšîqÿà¥<#ZdCj F¤ª!ÃȀȚÈë¡pi9�€ sÿÿ³ÅAñDâVm` ¿ÕqÆáj£5Á‹„µdaÉ–ZžsÃJv *Y$›¾;"iÝÖË>îƒÞ/ $µ, üþûÿ?ëÓg/QªYFäÂî?fDÂÅ1óZC„É<ŒDkÄ—‘`{ {9ð­zÆ" &p» €À�,h:}N™a`b¢ˆñ?¤¯ds2Œ,ðè÷+��`Y$zû î����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/small_left.png�����������������������������������������������0000644�0001750�0001750�00000000260�14517772113�017676� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR������ ���ú­æž���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß ¾=ÍÖ���=IDAT×mÁ �1 œ¬öŸ ;ÑOUµ¹ãi#Û�HbÇÉäJò]ªò˜ »;>`Šû(þà G¦=7Ó%����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/backward.png�������������������������������������������������0000644�0001750�0001750�00000001211�14517772113�017327� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��IDATxÚbüÿÿ?.°"[8DØSß2ùŠˆd�6¼4C(ˆÿÿzw÷?ˆ†Šù0 â 6›§ mo9Âðû݆¿ÿ ƒh@|€�Â0`Aª XsDý†ŸÏÏÃÂè¿__£�@(ÌI†hŽ®]ÏðóÙ¸øŸúß(â�7`F¼�Xs\í †ONÀ­œÝÁpãùŸZ°†?ÿþýúŒ0�È &cr _øï¿ÿVÄV-føþø8ÿßßÁxÉŒ6†+O×NÜýuHP \„A|€�bHü_”^¿„áÇÓSpÓΞÀpëåßÚ™û¿OÆÀ;¨:†ÿÿàj@|€�»àÚ³?õSë¢Qd ’Ssg(·ÜÉQ“ˆ@`æú1hHÕŒ©}pÉÀ@ÌnZ ²eqk0w ÜH�Ä &hbz¿ðèÏÀÀªš2©—‘‘Œ>?ËPضdÓb˜09ñˆ )E¾_rü׌›/þVõ÷u3033ƒñï—çáNÑ0qñˆ -Y¿_~ò׌[@C::Ú˜€Š˜  á~†ŠÁĈ KÞx¿êÌïw^ÿ«jnia``ee€yLù0 â#®Üô£` K†‚0Sˆß·ë'c‘;†b€�bÄ—A†�)%¨ËÎùÆèj� �bLuõ±‘=����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/data.png�����������������������������������������������������0000644�0001750�0001750�00000000653�14517772113�016473� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEßõ“ÏÇ��8IDAT8Ë¥1KBQ†Ÿï $øúÑ$ ÑbX Ýn-B%âÒåBÐZB*‚†@ÌÜ‚BÃ!.w —§¦†ÖZó4ˆqõžÀòŸï;ïy¿­5Zk�©uJ•&«YGú¼?Ûȹ”*Mr»Å™æ×Èäv(dÒ$WìÞ«€RnÖb6>¯ó{û?\�‰'-½™w)dÒLND¨6|Lr³�Õ†ÏëK›«óCPåÓÖWpqy{FݽwƒÌII¤}2,¶t èÿtë=…N(ßxbJ¥ú% ã¢2ÁփР²çG_F6ðë—!v}aN 6–œ20ca ©_Ê‘¿„dÛvˆ9Ž3ºçy¡TµZÍhøŒ~H º˜Ž‡Î8ã½³5Àb†ú?%Ž¥o%dt×2„����IEND®B`‚�������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hamburger.png������������������������������������������������0000644�0001750�0001750�00000000224�14517772113�017530� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���¹·7Ù���tEXtSoftware�Adobe ImageReadyqÉe<���6IDATxÚbIKKc 015íâÿxð^lš~°�.Ï‚$è9ê<z8ñÿÿÿ$§€��0…$_ _x ����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/error.png����������������������������������������������������0000644�0001750�0001750�00000001332�14517772113�016706� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��lIDATxÚbüÿÿ?2Ø#$¤3à±.ïÞ-q�ˆÙ€]PÍ&ÝÝ ?ýbø÷ï\މ‰‰áLi)Ø7¨!�7`;LsC÷7o¾ýøÁ •”ÄÀ©¤ÄðýÞ=†góæ1pqp0p‰ˆ0œªâ 4 €˜@¬Í‚‚1þÿ_lXXÈðñÖ-†_ïÞ1ü~û–EX˜dˆñAâ y:z>€�ðh³qb"Ãû+W~½~Íðˆ¾zÅðåöm° ĉƒäAê@êAú�ˆdÀo ¢¯7n0üFòóŸ¯_¾\½ÊÀod¦ÿ|øÀðç÷o¸ü×ÏŸÁú�lÀ+€‘ `�†Á§sçD<<À4÷o(ò Ò@�ñ? È ÿüaø|ö,Ãû'À4ÛÏŸ ÿþ…Ëÿ�Ò@p/`�Ä¿€w-'‡ …<< † �Ô@L0/üú†¸€½=ƒåáÃ`ÄGWÒ@L0°Â8P� }¥¦&v0œà@êX¡ú�¬gϯ_±;€‰‡˜ÒØXXX€˜•••áNc#Ãï/À4ˆɃÔÔƒô8%222rù²³Ù±±-‘—gø Ph|�ÆÌO ›è_^^°ÍÜ@öš‡5oþùs@�±@û hÈ:¦¿,NÑÒ‡°(0àÈÙs®]c8üûwìV f>€�bAò3ØOÿ^»†37jÞÕ â#zvyHiâÉÎ×ašA� À�tµ_/*xH����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/nav_bar_arrow.png��������������������������������������������0000644�0001750�0001750�00000000716�14517772113�020404� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������½ýì���tEXtSoftware�Adobe ImageReadyqÉe<��pIDATxÚbüÿÿ?CÛ„™ ‚ ¨à}UAú tÐÔ=…÷ÞÃÇYÿÑÀÃÇOórâ ‘1˜¨më“xóöýd ÿþÿÿ~þÒÕ0 œ(²&-¿ý|Ý3yF÷×oß·Àlfd`àÐÓÑœnb £]ÙØp.LgaeW÷¤é†?þº„lÓïß¿oΜ·Ø (Ïw g–ó¯Z»Ñáïß¿/5}ýöm_iUƒPžÝSÉ™y"‡Ž ù÷ïßwdMï?|X”“`BµŸ?~0�ñ]¨‡$‡¢!,*ŽßÆÒ\ÓÞÖz:###Lè¤#E¥•­?|wŠ_`WjF–Þ÷ï?P<ýóׯ›õ-f@y^¸§Ý=½™€XúãÇ›‘=ÿvöœ¹N@9A”ˆstr‘xøðQJÄ=½cçÎ0 JÄ1XÛØòž9s”4þ k¸xñbP#i0‚ ¬‰ïĉ‰ À�Ù»uW’6f¢����IEND®B`‚��������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/synctrace.png������������������������������������������������0000644�0001750�0001750�00000001577�14517772113�017563� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��IDATxÚbüÿÿ?däT©L –âÇ@<}Æ” í P¤/\¸‘ � ˆHIÏž¦¢©“©k`ÂÀÉÅÉðýÛwÙËδÅeçÌœš ÖÌ€�clBr¥Š¦^›£‡ƒ¼”CwSCi]ÃÃg¯öïØÂpçú¥ªï_>¶¡é»ÉÈÀÔ»jõÊÙ�Äôýû÷\S+QQF&&†?~€i$’ùòeéÏŸ?@xÍš5ê¯_¿žñýÇ·"?¿€4€�bùùã‡äéC»ÔÔT>~ÿÍðõˆòœˆ¿Ëº@ò‡žeeeÅÀÏÏß ³[ŒŒŒ/lllxxxj�ˆÁÙÕíåÆS÷ÿŸzôåÿµW?áĉƒäA^b> V:4àù\\\þË»·oÖØµ>#>5ƒ“•……áçŸ? Lÿ™ÖïZÏ�’OÏί€Å0¶À14¤ÝÑÑ‘ ��A�¾ÿèççÔñìè!õöù("')�¨¡œ�#'�¤›�µ¬£±,.2�&+.q=BH047�"%)úúúC Ÿ ¯­«\ˆ1**êÿ²eËÔUUUK999ý€(öÿß¿WÀÀÛ¤­kðÉÐܦ_  Ð4hÀ´�6ˆÙø'?Ó72=Ž/†.Ÿ;™ @ h|æçç4ä!÷õõÝÄÊ >,†þüûCMÅ Ü‚à –OŸ¾Låææ¬öòòbضmÛ’?À�¥:OOOÆßÿ½²ôŠûþ…‡ƒ•¡vâpô~ùñ›áù‹× ß¾}y@L‡œúéãç…@¯Ô¹ººþÿýû7 Z!>v&n` q²€iÿ4†�§ü@¬�Šg‡ÿ lll\äËëêéo(oìþîþëÿÍ]À4ˆÉ#,7€ÝÿÏŸ?—^¸paPî0pÕ°ÅÐíÛ·Á© €0 �i�R/@š‘Ää”r $`�Ÿ¡ ™á5����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/hollowArrowLeft.png������������������������������������������0000644�0001750�0001750�00000000475�14517772113�020716� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���à‘���sRGB�®Îé���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs��œ��œ”SÝ���tIMEá27t”j���tEXtComment�Created with GIMPW���˜IDATÓmÏ1ƒ0 @ÑOÔ½w`bN{r"E½AÂÀr€VtÎ�\J¬í’T4Â’ûÙ–‹eyK²ÇÇ ”bž× °€×LÓs0ÆìKAdàcŒ‘Zë¿Í@MÓä×ñ\¨ëú$t¤÷ž®ëòþTèÊòZXk 8Ç ™ s.õoé»óÛ¶M¨øM7÷.SkC����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/remove.png���������������������������������������������������0000644�0001750�0001750�00000000360�14517772113�017052� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���¹·7Ù���tEXtSoftware�Adobe ImageReadyqÉe<���’IDATxÚbüÿÿ?Czz:±`æÌ™ L d�tM]@ÜŽ&ÖÄXØÞ@\ŠÄ¯„j¨ƒòwñVt›@MPvCÒÐÓ€ÍyõH-‘4Ôãó0£ñÙD WCÙGœÚŽK“7’† ¶Eó£7¶ÐÛ U 9$¿ð  šó*±ø±žŸˆ��üÓQ+&7����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/number.png���������������������������������������������������0000644�0001750�0001750�00000000517�14517772113�017051� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���rëä|���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEßœtsé���ÜIDAT(ϽѱJQ…áO{ AXP,)‚å”6Ú¤Y;Q|�­ÁRÐçð|ˆ±µ¬AQˆ®:Ú¬°ÑU ÁSîÌá¿Ãi¦­—dæQD,â«™9„Ùo–upSû.ÆSI±„ó¸Ân±Mì`”™sí»8kÔŸÒ¯qŽã6žý~¿ÿòV«,˧ˆ8h¾icêEñ “ÉDUU ¾/LwXþå·W2ó¾™´…Æ8¬ý FµïÕ~úNQàk™9ˆˆS¬gæÆOL:iØr¯¿éLF•î§Þ\����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/i_o_usage_16.png���������������������������������������������0000644�0001750�0001750�00000001304�14517772113�020014� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���tEXtSoftware�Adobe ImageReadyqÉe<��fIDATxÚ„“ohRQÆŸ+w©È2¶Fµfk«ÑÜ b‹DD¦-c‹J 1¨ö¡‰¶UP0*Ø—þ}haâX”Õ‡ T«µ&(…bIRÌÜœz¯Ú¹×¼äŒyááÞçœó{ß÷¼ç\êâð� J<ýÞZþ}¸:ŒÆòÅüðÉd4û÷îù/ÔrÕûK!z³ò1¢nDG]9?qkèt: Ÿÿ Š#$›ë¬oˆŒv¢Êt}m2È K°`òÕ8Þm,à]/0ý£0fd ÞêâÈ X[XˆX†EŠI Á�ÿ~ç%äÒ¢dj¹†6̓ci–TÀ²iJøžbÕ¤aò=W?N¶ÇAó |ìÚ�L½ƒh]û ;ëúÊUÀmc]báG¨í~$H–õ¸¯°òÒm¡Hã0™ÏádG5ê7H –ˆs0,ƒÌ÷7¨ ?€ÖîAÜÿZ›GÈz÷l;ºîƒzw3Ÿص}+&ž…HÒ 8–fI_Âlw"îsó ~“¦©ªÖ`=QÃ6?FQTnaEÜþcJ#†{µ‰¨"ÅH�©T²LR^K³¤ eÛ¼ŒÆ1t~—®_ÆK_ÁÑÝs¸ ¼L&ãűüEÚXSƒÓýv¼šTáÔ±¬½à€¦¦æ¢;6ûyKé»M‰Å’vþ²¦RXˆÅø••¥~$“ ×ÍDr>«NÿV§Ó®9N8ã­m”Îf³¾ü¤¡Ëh{?óÁºR€²2ÚF˜é¼§ˆ&Éñpu+KTþ•0?óæ��f')rérR����IEND®B`‚����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/welcomeBackgroundShadow.png����������������������������������0000644�0001750�0001750�00002030715�14517772113�022367� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��b��ƒ���(PeB��„iCCPICC profile��(‘}‘=HÃ@Å_[¥R*š¡:YqÔ*¡B¨Zu0¹ô š4$).Ž‚kÁÁŪƒ‹³®®‚ øâèä¤è"%þ/)´ˆñà¸ïî=îÞþF…©f×8 j–‘N&„lnU¾"ˆ(B@Tb¦>'Š)xޝ{øøzçYÞçþ½JÞd€O žeºaoOoZ:ç}â+I ñ9ñ˜A$~äºìòç¢Ã~ž12éyâ±Pì`¹ƒYÉP‰§ˆcŠªQ¾?ë²Ây‹³Z©±Ö=ù Ãyme™ë4‡‘Ä"– B€ŒʨÀBœViÚOxø‡¿H.™\e0r,  ’ãÿƒßÝš…É 7)œ�º_lûcîͺmÛvó<WZÛ_m�3Ÿ¤×ÛZìèÛ.®Ûš¼\î�ƒOºdHŽ é/€÷3ú¦Ð „ÖÜÞZû8}�2ÔUê88F‹”½îñîžÎÞþ=ÓêïkÄr¤{1Ô���bKGD�c�m�¶EÜø(��� pHYs�� �� �šœ���tIMEæ #(0“«�� �IDATxÚĽM“Ç‘&è©ÃÚÚ^·ÍÚºm̤¦D$Íæ¶cskð¨B¡�ٔĪnh4š9ì4#  ­ ³ýÓ«¶Q Ä! @¡P@$ ö˜#)‚9ÒžÕ‡¶Y³¹uì!Ü#Ü=Üã#ߢÚ•‘ñùFfÆÏãÓþ¿úñ?ÿ!L‡��Â^<R�Ž´›`Ù'ý7´%<Þvë;&Ò-hÓ‘i� Ü Û1ÌN¾�0­ÂU�€x ¦ï¶²”;–Ë7ì¾ �Ë)~5åóʱ◊xÝžÕ®rœóÓrü7ìâh-ù㸗…„ñ<‹l» �Gñü-Œ; -“õ-§ÿné¼qõÚÓgÇá*À´’Ê)ë•vÃŒ×ýÔýï†M'ìøp��Vœó;x\™]1•{�`Z‘áÔŠ?ͯÇ6šuòì&ë/Ï{í—åµíº™ßk[¿O¯^žßü]O'ã1\“§“2=÷Ò{¦Ëi˜×oÞ^^ïx[å ÌsÕøVسýNײÖ|6:½õõί£Ï¡Z½7Á¾?èþ9¦ïgLïýÎÝßcëwÁâ_Á°è—_…S½N=µßKÍÚó[Ë®«°ž¿OTóYóÛþ´«jŸ[ÓJl=_ŒþxÖ—^?½pn–§Ÿ·AÕCçC_{ou¥ª™xaã—íjŽ€ãÎ{Ï¢õa|ï„eŒß|¯¬Ô_{¿³ÆÉ›—Äùp#½ç^Å÷añžχ]h?'jóôm؆«�°«ð �ÜÆüKø>úçQ^On—ü.XVyvÓÛêŒü®¸¡%U/ÅßW­ï­ ê ø}9©ïÊpFí¦lׂFõQapãÅ g|‡Û£±çô£49“î©°®gšÞÇ6þ�öÔLpÃå˜ö1_À™ñcæípfÔð1ûÿ}€é…˜>|œûv ËÑí8JaLŸfJ¯Êqã…Ý ;Óàùi%¼�wË$±œ<£ÖËKÿåÑnÏ®ÎÊχ»í÷û)¿H?)âûì\QxŽÂ©Öe;CØ5c?môáÙøËŸ+7|øÃÏb,•«Ã¥×CاxþÙt~·Qžg±}÷RxIÄ×ì*@¸�¯�LÏà¸Ý³Ó€ó| wšë&W±}}ë*±Ý÷rž†%x�îÃíáï0ÿë"Ý«}á¾,wzÚJgÎØTßS8Ãÿ:ìÁU�xÊÉöëÆ(}–Ú¿‡í3ú¡”®oFÖõ=•â)¿÷dÚ�ÿÓ_b¯ÿ¡Ycži­øÏT?¬þ÷XÑþd�ˆO+Þ³Þô:ݤú‰ñÙj/¥û‡Îr»m¿òï׸zíhœOã3·Ý­~´ÆÇɯۥ¯ã_ªr»ÛïÔÿ—ªœ¿Äø½®~uãè}Ð[îh;åxüÙüßÿßþð÷ÿô¯þù_‡0h2?X¦Å«Xî2~hé׈Ýt^۶ȯM¿¤01KA}0À±5 b›�`-Éó×±2~W•³l”ß²M�8 Ç1ý ØþÚz\•W3›N¿¬ó5ÀBö÷¤Š¿ XòùM•Èô‘ÆzVŠvÖûÛj× öc'öÏŽþMø9nÚñv²q¾tÃüÞìl›T»pÁwã·U¼N?[·./Û¬ax Ãâ<³µo·EF¿7ðx…ÅÕgGÙ^™ËéÇ–›Ì|­°,wÛ±í´cU¥ßVñ^½å;7ªoÎ}dû"¶áÄ–¯Û¥Ë½â¤íçÆåÕÆ½VŽukåùË·e¼uÿ­â}¶]äý´¬^Në÷\¶¯Þß¶é~¬u¦ÓéÅyšG§†9Ï Š/ÆÓ­Òù@9jm ÊõžÏú|µ¡Hì{¯Šõhàn…µcÏÏz?3ÚÁÃ;zC†Óò8Æï°÷¹M–®Ñ¿°­÷¼k2…u¹¢½`¿Gòå|^OˆíÉïã›^Ç0�À-|Ÿ×@á¨ÑwÆ2Èï‘Ýâ;…¬b×­˜Ž¾‹Bm|� `û§ãN=høvÛwnþ2°=sîbü2ÆïºéÇgΊ…Ûåß­n‰€¢:'Ìë×lïlÿÅÆË2^ß)^ï›:žl²~ßlùV”ã. Uþt,¦7U;dý‡[åÊúÃ^ ï¨v¯8ñEMûÛñBSyNެgÇ,_/SËKæ–ˆ—âƒWÕ|Óó)¼ƒáv�ÂçU¸ßì­§Ì@]§åür…ëcÅ«gœ°¼é¹âÌ-~¾9# ­÷<óÄtyF²žƒ¨=ƒñÀf×Sˆ›l®LÏÆó¡Ö^k}æ^ˆíF­TÞ ·e9tÓô›�pÃO«ru}÷Á>­ãxéñ•Ìò̹îÃØÌ€]¸/Ï›íê©ÿét¾¾ÅÃÔ´¹@Ÿ~¨-/ŸáùCnŽ˜™Ã¯# 7=%¾ðëÙ[8�Ë£òGÏÀèկϋö³òZåt•«óOêú ÔW=¯Çcz*]h”;Ú¯YçÙýAíôòŽûP>ã¾é­oV»¼úØý¶hý½×:Óí9íî²?ÿÓ?ùOßù[€ï,�„EfÕ’|á¥ÇGXt§]ù8”@™ß®ÒÖÁø€ð€°Ô“Y”ôšQù�,wLóS®«øÓùåîx/?¬ý‚M‘¿LÏó­€üð_Q�×NxòDX×{� 줅‡ø"„¯½úhô[[@Ñé¨Ý Žº]úB¿€Õ€äÂÕ ë¿6»sÁËÂ* `~½¼žcE}'Íð¾a©g6³¢XÆ …K¿¿FËÓª\�& Œ…é| �›·ð»jG�“РÛwʼn¯[ èòÚ³¥â% —ÓÅøøÐ�¤tVÿj÷˰Å^ó�"}5Qîô¢Hdzð§</^·S„§›@˜WÞF%ßÈýÌÓõ\G0ò¯VÂѶL v;c€aç=+ç‡Þyb û»æ”çÕgS?0®ÛÑÛî. Œ-Ëšóè´Ú,¯Ó¦“ÕøUç9¢°Ôž™@Ù±F˜ž¯ÇÒóØ>ßÚ°B½<f‡E|€ëÍïIrƒ—NÛJe#Îz%L''äûft>\o¾ŸÑ{%+·ƒy~­x•ïƒeÿ- lLj·ßãµÝðýü(ä÷ûV¿½ó„Étñý¹üî¸î”"aïÇÓQêïäo¼�„Yéú¿c½-z†ÿδM”Wù>®GÝýÓ@Í´6ØmGŠñX ›`)Á4Ç2´ü9)€®cêXœW@•LG@[n±&Âè‹ê°Â(|˜ÒÕûÃÛ6#óoZ˜'�l�`:œgÊïUTÞ´%PõqQ¯žÙòL¹Y)‡Å  -•ë�atþy  õ¼Î?l„ýè²çáÒŽ6Âûeøzn,3a|å#`]["Óm]…ù‘ÏD쬛ñ匵“é<s€ÆÊ „YÏŸgØ*€¹i)aÖ:0 Œ—Ë#]_¨‹ãs_1à, ªïw’gÜ„ÝÁ|å ߬gÀïŽß/¸Ï:šÂ~­Ž…5€0û}¨Ù#sö ›ž.§šŽ�žÔz¡Þ¬Ÿåß³Ò3`œt^»« ?ÏŒöWƒpl•Ç�É…€ÉŽü-¦£§€nhÜÙuîê' ½|³®gGÅýÇÚaŽ_Çïgn»ºÊa¿‡Þû]Øô‡? CL›Þ‘æ|HLK2ží§XÌJ‰6ÏjÄxsÅ f˜6þIåçþÄÌ]8Q�a±ÿå¸Ôw #,†o)¦×Q¶ã”3ÆJ ?i+F=¼\¿ßr'q ˆefØ&bë" <lÖ_m7í ®ôgžÉžµ@´Sœ×;Žír:m€ÖÛ¹½G‚o!sv䯪ü«0¶?æ öx †iµ¹ðÛ·[c¨pk1>�FJ3£—±QgvQ;ZŒ,¯½-†×~^ÿQf8é»Ê! *|ù©nh )|ÀŸ:1_¸ã«íÙ�˜ŽÇòDúÞqðúGíÙÀåÉYý憎Ëí1~_Ía ö0Ï"ð¶…¿ úðÖú=Bã¼ÇÀ¬·¯·?µ~Õ­:°ù�ļkæÓóô·n.#yA†Y¯´%dåyýÞ`Tá&¾_9Ïë.&™,ÿ¤/™R’ßÃy¿Û¡NSÜH¶ḆŠÔdí}Ú÷À6`µúïõ‡Þw¯‰øöx”Òè=]†åûü-cõ7ϬïŠ]ðú®7Ø*ß á´w¬óó·[ÊOÎjÝ=3×±ñ{LÎ,»j#f_ƒõ¯]/—½Þ¯na4G¢rQ`L··-Yo%KWef1S�K1£i†˜.·Ëöh¦œx 7#0FçÛå:çw��Â^?CŒ€*ÿBï}ñö1¶<€ ×á®>bžÇø»ýå9Çëî`úc8ª;'ø¤)Y—LÔé>cˆ‘i¦Xf†5€0ZÉúT¥{ä|ÏYÀâK“+ˆ÷Œ™©ÆwÆKH_n"SlݑĬ½G܃ t™@˜ž¹ 0«Ìè›ÐÃìÊãµ ´Y@YÛî #Œ€°#¾£®Ó�Ê &éÈŒ�¿Mà€XYÿˆ 27²)qäq†˜6Pç¬Ê´ª0|�Ïë…ýªu0†ªL¯ýb”íCyûmfûÈF™CdÌ?Í0Üo&YW+ñCL½zZãfjßÂ8ô¶Û ÿùŸþÉ¿ 1²rúmq/ÄÒÈÂ@ز¼òk@Kȶ¥F|ê/1Åèk:.w,Nu€ K„°pÅè’¤H2cÌb€Õ^£ø/¿žIéÃüú&?o±gÊ×Ãx"I½Ã5ç;Y�=RbÆ“<ÙÂD=zÁCIz¾°4#¬æ{£¶c7—sM-�ŒŸçãÔaÞÖäïo…ëõSçoªcN×iz‡þT¯¿�ÆzëélÃ<ð„fCLçÓ ¶c̨хåÕF8K»µ¬l¿Å@ñû‘óKfM–’# Œ��¯¿^{mÆŽÝïÜþ}b`i‹@L"ýFˆÚå`iÇ%ÐUKìüF^î3°+¹}�Ó‹V;òSÌc–±tWrºé8•ÇÂf{õ8ɰ° oœ÷ƯÆë‰ïÉgý¾jé·ùóùü;# ,–¿e2òJ&™þj«aº?­e×ýÂÖjG6¿n9ù€§Ó@˜7_Ï7º3luŸ¤y ~Cw:Ú âmT©J-î&ÛQ«—€0û½iÖÆŸb¹“K%Fe‚Ò„d"{l1§6Õû'G¿ý'ðeIûã!ëç \‘+>ˆþ%ÓR‰‘)v´¢QWˆˆ¶›$ÜA³µÆõ„õ-¾—Z á|a3mXt$ìo³ãˆ”¼V"wæ&}ëïb¦¬2„‘Õ=1ófL>µ]ß¾ ¶*Žš9æ/›VÇ‘ó8Ęc7•”¢Þªwlðå™±ÿ8l‚XÖéeŒ‰s{y&@æ˜ÙosŒìxíkÍÝúé0ÍVt¹¸’ç³vKØ„’FùîjFÙ´2„ŲF0²–Û{TµIéD2ŸÙUÂ>IÇe,gz–0 €i¦˜6ˆ�aú|}#ƒ\i#f?zù7ÍñÚ�˜°]U ¬eüyòŒÂƒMÏØ$©hÌè{|“ÏõÛ4- lÜŽ$ 20–zñ´ÜŠ0 „‘åþIÆoLj=¥Ž…�¦aŸi`lÞ L—ýb&‘yÌ}^�€„—n¯îÍg2Û*Ö›n¿l¨¾Ê¸Îbyé= Ó°^fWW½F–y?´\ì¼Ç´ª¶G„-&#Õ[iŸw½FÇ»úû΀˜f‚-Òæ‹z¸Ó/Ìk=þýiK•0 uî0ìò ÆÒUöáœpôӒ‡ýÐ’š-­ÜòÆcG‘Æû×# ¨Z…”M²¼#V@‰Í�›\)ع#Èa†í¨óܬþ¯8ùû_Ç5«å+¤jÆBVkǺ'…(Ø<æ×0¬±“>-+h_- �mÁÏ ª ‰.mä#¬•®¦gSkye£’Ï«·%¡V[0'i¸ q^Kµ•L”¸ÀO€×–ZØ×Ì—²ŸºžªÐáI�jÓÒPÙîÀ˜\€€”ÑŽ ²'ÁXÒ�›Ù>x…b::¦–}$(É+™g¬?”žÊ5ò#ñQd¤0FÀÊ<IFv}4pWòDÿ*Ö,{%%ùùÕJ~�¨IIÏ ,åß­”ŒÜ*ʱëYS¿O_ÚÒÙýéû}¶¬œ¿ú%!v@fHÕšåîsÌÙ°áIö‚÷Üê,W[ë9›—}½ /úy[}/0%ÇÌîWväy-±¸bH ®;å™a½¡‰½Š·ÊÆ'mÄc±@&ßwK Ëb‚­¨`z#YÏò®|¿¡Æé†úÈÆ™a\ʰ‡‰·Ì|ó|eþj²ô;+¿“§À,Èï™bâÆÒ÷^ÇFƺ#ÌÛ20ÄU×F=žÁä+²Èx?0Ìs˜bý�™L——_í7ܲ<sÆæ@˜Å”bˤÞƒ4S¶€¤ª4¡?ŽIJQØaèb°…½|TL®~Þê?xÁ©ï… hyÀ–êÿ –—f"*ßcpɰú’7|‡¡e”uÚN I¾ÅšfH8Æv7sÆ*û�“3Ú¨/1å‹€1yìÔHšžÒ.Êöl%¼ (#³-í#‹˜b$YÃó6dÛ�Ù22ÄÀН´«¾!æ46Ž0¦|Ž‘”â}öû#ã³d¢ôQVØŒöOO§cÈ¢õVœ–w°}£[&ìôMéD2%™xˆþQ ±C­r\kIÚyé´úþµE%ê@åë2zÛ¡ÏSùÀZØÐ�MK‚±r¾%-Yh*LB}}õQ_/=.½Rf;½ëäÝ¿p'âµo00nÕÓŸj»*’‡À絫zß±ë ã ÉĪ· öB/Î/ ˆ•>Â[úæûSÖA~(Åš½ÃÐg¶Iûž$?²~aùƒ2ö¯½“’ÕÓe’)–%åùãÍa«~¤vœø\N)‰X?mmß †“t}~_Qùv”sõÍ(«Œw �$i+Mß[õÞµ}€™é kù±Û5{A̾éÃ}¸†[»j/ {>m`a6¬Ÿ–Ûˆ"٘Ěg𹕙+õôÜNbœ´Òñ~x>Ÿx?$óÊe1&-èl:1­ é%У¥ s¼,7ié –Oå=yÑÊŸB7@H!Rû ®bùÔñôã@å²v{ùÀOOå ��**gCõSyàŒëF–Ìã,Ëíb×Ign(FWÞ€H9ŽJRù|>Фr^hI/γ–äi?3µ×L†˜!ô%Ò€Ø×åô›–JÔãâ<÷Üü J-sžëù¼ôñ™­«Þ®÷M|ÿXïH¿SøN%&½´ Ô’Ò«´“y乞ÊïyïåñÕ%žô§kô~?¹CO£/±hij„½ÖUúÉu gIAiYJQûF®JT†[2^o(,7êï2ç€/Ø-)˜ú%g R0)—¯«3JK9¥Ã—˜ÍÍõanÿ< ÂTü‘™RŠ„Qí¾“�”U6ºfâ€ù¸/1Ä)v“§Héä?cyÊ”P$ß`LQ§—å…›0Âô{á¦'yØÃ {.U†>V啊ɴdcÍç™á“¬[Ê�Ф�±6�Ó:@@ Æ)XZ2QÄ϶,©x ÃZ*QÛ¨t¢g$•H6K2‘¬”JlϰUë—$Ì@1¡¸‘ï®gTY…O¯J}4.ëyœÂ§ãdµ—¤©=÷ EóùÍfnͤ"@ŒÂõ~è™\Ž—fžù /áÛ‹€0’HHRŠÙÇK×4×Îo?AhaÞó1V`Ÿ©èC˜9çÆ|‡™¾ÄZŒ-Z¯0¾I¸wsÛ3WR‘ÚéIå‘í«¤ 7.°UhF¯«!™¸/ýh—Ùÿ’–]L®Žß¥kõ{¿¥ÍtÚœîÇŸÿéŸü§ïü-T|ˆeZ²^@21ÚîL`¬öÁÃhœ| Ã~éôëƒ(OšÞI™ãkÔòLÛØÎ—’6¯œh+n:-‰è69;‚iáajívÛ§¤q[q$GM/ܬNÕË…î2Äð5 Óù^૨k1Äü–Úå@˜>ï•ã,@¶Zј%*¾Á(Þ“ÄF€®–ÙÀT«[Õü¹=2oç† [�ž./×· ä½>»�¤Ï¬ Б#P4ƒÊÆðe¹%`¤StRKR»©}€2·gx@Ÿä™@Xç à«jà(}— †—q”>Îäø‹r¨_PÖã› dR=ù>ñþø6ç¾ß®”Cfÿn%md–ï³mCz±ÞÞ1`­Ö.Ý~i½ó®×ÚÐÐ €‰zº™eÍù[3= l& æYÀòžÿÞ{Jl¥ZžácÌ®¿7Űö)[ŽO¯O1¹`Õð%ƘdœåVÁ‡¨3Æòû²ÞH&ÇGö˪Wn|“>‚Én)f˜Ê|_c}Æ—!IÙb¤|´ëµòµ/1s¹ÖÌßéCLol÷SþâwçGÄdA�eär UŽ<ßöÜïá0†A½¯_Çû@™ år†�7 £xeú &…°¹I�X³Nóþ   }ˆ%àJù# lÀW™bŠÃk‡Ÿw™cx½ÃÂX<•KÌ0–å·ÊmÙ]�cÌ,ÏÈP»z-1S†»1L ±p×IoÔ/Û«Â%pgÍ ¥õ3ÅôÌba3}Š‘eßbqF Ÿ´�1u^ùîJ’‰¾d¡í3ìeÏÀmó9™|{Au}*(_fÓ³q\J<s¬ê[ 3žÁùaŒ9ùjíãv¿’žK'ò›§ë¬J3gìn�Ìj?€ÏXËéê�˜gOu¦+$ñxH…­„u�Úz‡}Ì ŸYÀÑò)å<”~,`šIFã0Ëf\÷j»`q€²Ú>ÏgZÜ×v°zGÃVùØ"-¬rÄ*è½&_ðK ÷>kíüktrOüt4~`…[,ÞøPÓñ`팔&? ó‡£Ì–Ýòm+_ËŽ§øª6ÙŠ“n§’N§V‚&î#ùÓVeŒI©†æ‹—Ô±€²šYãTažµ}lTl€ùÕ[OŒ×;Ç¿-FÙªly;æÇ�°T«¿ ©%{¤>@lžgÃÚìÖb|m 1¨V“O¯-nµÓb²ñòk ¶^ÉÂ^à`(½fjÕ%/œ U�0Ñ^°xŒ&#Ÿ`hU«}×Ñ|ÀÆ[ÉÇS·ŸúMÀŸ�½ë$7ÁÄÛ(¯oÉä³-3Ó¼ó¬&ólÇ¿VNù;“óÿ][L­U·\ž#ÉÆº´âVWGßû2¨Å3i[!u ûŘ+¬Á óÒpæ.÷ézߪá€åÌ�Æ´•í±€¡RR0~Œ)¶ÃÞû„rÀtB¾ßŽbU3Þ;–wµ¢‚ô5ë½o–ãAŠÇ‘¦}‡Wí»Ñ­á™õ}²kœv½Vn fç¬3Ç,iüu<¿ µïG[.âi ½Œ5ï­?«%å–1ËÆccýiµRzpn"s¬83—´T¼avùÁ-WçëÆðš”ô"cŒu3 4³ �,`Ìczí˜ç5­b6s,Är‘ñe1Åz¯€ |‘õqÛ�˜¶úŒ”¥e¸×rú]QN>?Œe L†Í­Þ›ß»!›Ç %S,š\»§|ŠÝ«”o×GÀ—‡’»Üû¾`1¿î)ßb=3µå{«Çdc=÷¡þ\n0ÆCŒìŽŠ'&ÙØŒ^dwÌø¹V,x3>·Ïœr5Îg3�¤XhOÀëë`øèü`è8æ2¿öHéíç\@ªcÜè|‹ÑVÍO6À€Ó醉Ðï}ðZýùc3G}¯ µk�€iI.m´¤ ˜ÙNƒ5�¶›âç1 é­)¯—Àú¤M%æ ª|m9¡úÝ/‰ÈMïìÔ>¬öi ÅhåŽRëL�Öîl])Ê/wº�Y[±2æÎµówE-lÐÎ`èÓæKöœT篙ñ3mÀwG‹ñe/l›ç£Ìh©SNC*q&ÐÕlúlgÀ—Çèúv`ÐßZ í]¨n1(¤!ÍÜèmwÍ<F‹¹`®>�œq•™>†ž�–0U^lIÃ*3ˆ™rJéÀsJ3ÒöÁgHOšé´µÊÛ/ÀÓ @c’ŠÙb¼`ö€½[÷�ðüþÀé¿€–ÍžÚ|†~æ©]¾”`Õf1Æj²¾µ€1OWÄëræû S̰Ô}f‚µL/Ëz€ÙÍ&c¼ÊK½Võé÷ÓÇ©d‚Éúàáï—Ü404,Œ$ “y'$0V÷Ik*€:Ï|߆ׇ®ÍËÖfŽñqãfŸHŸcœç %ÁÌï—TÌõ_ïlW7µÌÜfˆU$ïE:<ã—0~Q i·ñ;hl¹ÕtEàÍk~{ ±ÔÙ~’Rœ/¡(­ô1&Ço”ig0ÄéÄh{Pøþò€1qž1ÂH"ÑŽöÂMOR°%1(¤!@�ö˜÷k§\‘±’ÙµSͯûÏÊ�Pö¯õÅïlè”Pdõšå0 ÌÞÊzWå÷%ÖÆâ F>ÆÚÀ˜ ìd€m׌ï´P¤ïšqm³°–Õ¥93Œ¬cã21À¦g£„b•f=߸ϰÚó*1È(ž1ÉjVcˆéñÑÌ0ìÛÈâqz÷:rì �� �IDAT#+¹Ç8Z·db ÃøCó$™yŒ¢Q”'ùÖj—')g�Q½€šç MÛu¼¤÷Û­Ï?²ŠT#Xùö HÜïþÏuþ[aÌõšˆ™K½žà¤=�l>ãŒèô~ Q>7âŽÄŠD¢U_*¯Ù_ïö_2ÂøëP_ùÔØ¿RQû;^-Ï[hð(jŒ'¶`à1ÀȺ€2Ñ/ÍCçéÚgXo§¨;3_qv,ëñê”Fì¾fH"ÚF¾FPrqßaé×Ú`x}˾Á<i¬iàdYïç¹'e6b= ¯ ŒÍ:¨½s‘^¦–!yW¶ÓöEç³Ô fI—h¥Ö¯ûÀÊá&k¯ „°þ—åWÆoÑëÁãO`üõ|‹ÜO=6 °yçLßw(c×'¦�mÎo\_q_{ãÕ!±ømZÿrâ膀.†V³]½’² ñ.Úý\°†T¢ÛÏcz6ÀFïd'«éz{¹ŸL1»þúûWÍ,…ƒÒçm´p½o!®.±ØácÌëîŸÞHÆ¥ùû©Ü¨Ö’”ÔïÿrcÜ-üN8ŠŒ±šo1=>3 €×èñ*•4¸bÿþZW˳¶„Ý¢nš Æã¹oiJç›=#ä~Í\•ïi1C0_Ý^=«Øþîö)V´¨Þî~ÉD/¿,ÿwÀ± Æ—KðdS€±eì$_bº¼ „aié‹Mœß+Ë™c¡”\ÔÒ†é ¶ ¼€Y À“.‡Ò5}”…Øî»øÅÿ<bwõ @ØéòIÖ·»[&´„¢'©èK&êøhš)¦ã³y '}^çŸ)¡H’‰14=WºÂ'ßbüù¢¥)Þ·ÛîsÀö)fùøR>Ä0Ƥb_m¯uŸ‘/±g”„bj[­1Îî;ñ^½ÞŒÝ¬ÙñæLîÏœÉÇ}šÙ¦¬»12œñ?sâÈ<ßbs­Â(ò¬%ý·/ µÚÛU¯o6ØšÁóÚ©í%e©ûÓÛÞ}ŠzÛ7×<Ƴ}õÙ¶@?L`ñϾˆ€Øw \º6_Liú–Ý3ó€°%#,€.ú@bJæùÔ³ãüÃK¼ð¡ùõ€�—Ò'Õ:;Z@X”H´Só0p–$‰H¾Ž'� ðèù[WG€rÇi PLG)íÇ+/4\s}µ|ˆÉ3ŠÙE #Œ˜bzçokgѺJ/û/bVTüJeGõf |y;§ƒ³@Õ!™(í˜Z0:ÖHïZƒæþZÕÎøoy‡ü´Z,à®ÕâÁ_ðc†yÆÇ#2°FË%_mICΤ `k¤´¡7›kŸ`5ÓŒ§JzíÛÊÂ� æŽ T _Zº&íKÊHw…§‡ÁJª ¤2.f:#ÞÆzŸtÂÈO@˜®‡—Â)·æaÑk·ÎçõŸÒéûit4ÃÐ4-yI÷±”V¤úJ¦™ôù&Žúþ4€0’z,¥#µ�m×ý×0ý{‡",%TË·®ÖF®o¾ë]îôß3mzÞ·¬#“T힀i£ç¨~žÒsRŸ×I¼çðL¦õMõà¿/ I;·6úLVùò}PDÞû؈yï·röz:¿™)V¼wªô=õÒ{ðºx?öú¯óÛ¾Ô<@ÏR@åg Œ¾x~Î3¿Ù¿¢ËpñeZ¾0§«.Hꈶ�²r£"›¡uÿ¹ÏhZf¼=IeŒÖÇ€Ð>¯©ŸÞL[«¾§5@F@Xå{[Ψ^º%çX¶hUi™11Äœl^|™.•cJmŒ¯Ž[¹õ¦ ¥™H�aÞVÁ=XbŒ°¢M"=Î|TÎáé˜ðèxb†…M€épºv0 ÓzfŒ•ísÂ/¨ñ~¡˜i)¼S•xÔ€ÚÇmà Ç 0Uc}-„¥1A_btd&ÃøjK&z¾ÃŽŠãsÐk¥ÔŸ<.7ÒŽÌQ€ „éxÓ¬û|ˆ=Ëâìë¶„ù—T}w½.Uú[æå‡O‹q*Û!²ò¼év¬“Pœ–’´¢`ŠÏìð}oyv_“wx|!&Œ¤§§;Ê­YÙ¯j½Éž‚NÓ[”RÇÚ“Á¶–­…L:ÐbÀ“ë|Ð`Ƴröjé¼rt{ãÌËç1<™È¯CÆøn”ßbô±ÚJ«í©ÔoŽGGý­þVé»ÚeÜ­ôÕû¬â«®«¿•ßY+¯”¤�Þ<�núÃþéÿä’‰ú|@Q›'Ê­WQ›ÕÍ�apéó}„ùñòÃ0�Ê”׋óµò,ß`Q"Qú Èùo$`lŽc͇˜-•H–,Œ~¦çÓÌ.%aÃ}‚ñxï:Ìé·îO´^‰ÂªyÀX… ÖWO‹ùus0}Ùò:C,ýŠ>ÅöÉ àË— \Ôø‚wÿlU÷µ³ª$5€Vú Êåî·o¯êy „Ò§“Î_JªÒŽÛŒ�CúŽÕ_m7Ù·â“l`ü�ä¾÷àSó4éoO?y¹2ßžß*�3 ¬m¨öÏ5Óåÿ±˜cû(åH÷§ÒJßt¶4߇™Á,[”Yhoù&Ó¦%ó2,j[8/°_—Zœ+ÙºÌ7³}Ú×ØÔ˜ïçK+ª~n{Ã*¼­ÊiYËW¨Ïðê’LåcL[‡Ï1û½¦dt]SL/»]m¦TY¾w~ò†«z/¥ XРxï»aGn 2ÆC¿Gçþê÷q«?µ aÜ·ØQ¥0‘%Ø£Õ„³xùÞ¿~fXŽç žŽR‡)èeJ):ço;#[¾¨=Ë˱RñDÇwZ‡§šÅ¸µnùž1Ñ’Š¯Â-+¥·cŒ�´;~„­;àIzÒ…XÝô|Võ_ޱ²>Àúú�,Ö�YØË¿ø–c‹)Ö)é(b”ÎdlùL‹L1§žçÕÌÙ!¡h^£œoLl·íSÌcˆéó¶Íõ)F’‰ 2ÄB³~‡f™'Xg\—Ò‰Zº eIC!HÀצ�Ê–0~ã[ n«¿ÉÇ™^ e35ï¯öýÅ£M¨û³ß/\ñÛTߘ _b•z¥µ™a}R‰žyŒ±n EÅ;„É?ŸXj¹@ßå̰ւý(£Fäcõú–ú•‚¬´k4ß\QïubA› 6Ääë¸mwËÇÙ\_eCãåRþý0 €ì5’Lüδ$_8µVùÒˆ6�6ç1Î ·5wÀHô¤5:˜CZ¢C0Ãl;‘ŽœVîóiaP %ý7ª/*ºœ•ÊÑ`~>Ã@¤;Yì\ñìŒ9f2ÃÄ‚ƒÞ‰«}?Lþ8ö˜/ÑØpNޤ×;¨[>7ŒrÂtº"}çNôbáRa:ßÖZxÔé 0ó|€é°f´¤ËÏôrØb~q L3C6X¹CÌ kÆD/�P=O ÷Úç™é r|  Ìâ<¦‘îW 8i‡UÏ ¨3qN@}|­ó<Ýu#ü4YKaÍð²ŽZRSç7_ÎëÕãa¥?ᜧzµtãußÂ6ÀfÀyãÜbN h†/1a (L0b¦IÀLK/’O²üû 0Ð�Ï_H®ô«%i3«ÖD>˷ئ“ç·0¼Ö8yûZ¾·£g%Ÿ õ<00ò5¦Ÿ3aœñë˜Ç£~jiEýnaƒPŽ5ÂÙN:Çk�mF¼ŽŸZ ö•ª÷‹/oö¼ïô¾IŒ±àËØ¹mzÆ‘ïã'‹÷dÙÏrC–f„YýlaTÏÑB1ÂöAì)Sèr}Þ‚ô™L̰åâ‰qÝç.Éz&y_rË5s 7J.aºÄWP ²~“>Ä´+€Ò†6€Îøî–¾Ä¼þ4b^펊ïeˆyÆòJ'Nß}*1¼n"S,2·“«¿\,ý˜”PTñ€û¼ÇêIÀ˜ÂVz}€%ì(|qi ŒÊùu9•q§ò$ð…áÄÐÚ Œú1=/°)3ÁêNžWÇQ_bàäI(¶¬L¿Œñ3bѦçäÑHqÔ|ž| 6p”™X·­ç"x3^Ϩ™)Ç›�]‚ÃËXï.€�È|&˜)™Hÿ„Û‰æ­ÓSl"`´ 8" jù iÉ<^2|[H1ö0Ïbþ;<<i ®5“?ÝŒ?â¤ë{B<¥Ž.@âùSÉ>ƒEMHöÚ�§—Ád–«}ƒyf�]̱ý*¯ƒùæ1ÃÄ8t´s”)§}¥µÒõ2Á†â5àTØZýla"žúë1ÃŒûÎcÖ™L.ùçdàÿNz™h]fI&ƆÝNæÀ¦wÈï*`¬ÇøƒhIï�¬�`â8 ZôÁ%Ž›P((³³¼”I‚$Øåƒ�êì–"5—BäL1Í“’‰òƒ‘�¯$ˆ Ž¥ùŒ¯ÊŽ¡I}¨OÞ‡;L°˜}„Hé¹Cx®ãÐïœ} àéÀØù1azÁi¶/o˜`žäÓÜúTi%ÀEñkü¼—À•H¬[‰PgRxL.2 “ñVýÄø²|ˆµëõ2a-ßX2]^¨×L1P íšÑöó,͘`ÀÓÃ|‰¸Þ|°é‘œã &Í ¢óÜJài-ÅËö”ñ " *—¿U0­¨bZÉþlaº|ßÄr·`V²¹¼’ÙÈÏ{@•—ü´Ìý–€ü8ÀvŨÏæZ’ž=�ga½¿P¾ÄÖ’‹(+‘ 8ÓLÉ (|æAòÑ'Û)$IµTh Ø—óŽ´U¼N«,Ìj<�*Òµöy].˜Ç–K ¬òúöÈ�èr}s:̲Ն±¹ï Çš>ƪŒ°Ô§¾ßc6C…I*ê^ö†.ßÄûº#ÉÍ}Õò÷à#ÿ®X1ެœÉRZàL8>ðe}o´¥ëá£ø]q˾¸ï±P¨%w'è:µô|Çw“þN+0]NpÚ�Ùmõ›Íqõ¿k·ùc«ÿÀó-Æâe9-iÄqà/1üýÿ}BY¬¼"f– flÑ ¥g bˆI)ÄÃàJ÷ÕUYR‘¤5CŒÊ÷ÊåaÎ #ÉD^ÅÆÐV4ef™1FùwÄy>Ö‘ ¶2 äÙýÌR‰Ó:T|xu{_öAYcLš|=_Ä­†ŸSÒ‰žcû „¥qAßa9ÞÛŠ€ñ$•èÙ³×¶wƱWœ!æ1Ŭ £ð,Å(xgZîãÌÜøl_iécñr2 ¶T�n^¹ò:ÁðfÒ‰ýRƒüqËí¹3ÜO€ €u3…Ô H1ücoé>�b.àk�ÁXðÇÞòµy̵Q†•” ›+Yô< eÀF¥ G¥üÌþTƒCR–Ðy¡ tµY 1ÿ¨l1µ4 ©}Åé#ôsfùÚ¼r+¿//óý㿉’‰à5Ûg˜çl¸ü`h¿øZ;9ší*½Ð�@Ò¢/Êë1ù€9a>�—Ýôóê;ªòÝJ>ÄêãÓjÿŠ›ÞöaÀ6Ë×TS"¦ú⬔>Âxü Vóµà;''a]Rˆ£À×tlPŠQ§oI ›ÇÓÒMûT›lyé0ýÒˆÒG޶‘Ïm ´|èØí˳ߖ?Ò®^¦Ókö£{ ×À•-WšÁô2¥;òQ½£’v�¥�“'EØ# ¸¡òK&Ó4[©¼–„߆(Ç¿?¸tæuuh¤·î» /Z%sÍp7Ìòµ$žʧ¯/GJ6zRŽ”I`οιœQÉÇßS5ýhùÂ4`Œ±7S L¼SŸá+m¿K·fË÷‰uŸ­: ³¹ãØZ^n ‰yÏ“9fŠU%gK*öJ&jž©ß úÞ¼edŸÁ>T@–ÍÞëßèÔ(ß?w¼ \Ÿb|Á™[Þ².½7“¯1J_ôÊmõ³&X—~ÏRì€ášdÖ-hoäù¹)hôIÒ_ç嬷KJQ”goŒÌ€˜#¥xF¿í™iwd_1­ä£’‰KN¼_c]*QÇ·¬Lg·»!èy˜©ùk´,I) Æ[¶±¥�ó—^<¯f¶=ÊÂM œµ%�Â2Ÿg  ããS˜ûs­CâÐ 3ë˜$#`0­P�6EÀínØ ²NÆ_S díàùŤ½óÙ´¤¢ ¢eDK).Œ ÛD`,^ u)ÈOey� ™M([éï1fÙ&d�JK)æòw•o±]ñœð˜lЈ¿Çž„c¬¡”PÔ�–Ž8°E¾»ˆAVšfˆ‘SÍ—L”éóL½™ÃÛ7=㙄¢?sZ�ÌÝ7DqkåwK&¶ gþÏTô!<~ÖYJnz§–ϧYÒ{ÚZƒž2ð%ù<àcH’oT°C¯— ÕÊ×5nÆxôJˆ1™{€U)Çý’¼4$Ír;¤8{¥>=Æ÷»êí¿gºüjýdöE”L,|ˆØˆÙ;¼F˜`5ó>X’Ï0bŠÉ‚´£°ª=ê5À~@èú0â;$[¾Ç*íIÒ&ùuŠúí.U›Æbb§«Ñ;L/%€c|è‹üª1ß íS>\çèFøë®š¸Š8.'q‡íO°Ô‹q€ªµ›¢bø¦J¿o>ÀðH;Í·=aJÂiA†˜±pè-<– ò–yË�- e¾5”ôÒ’‡ù¼Ýž­$fùóÚ;Ǫ øHi__Ä(a¾‹`&©ÌH‰Qáå×õj`ŒÓò…¥P5ÀÊFj>±€¥«žÄ $æVÄ,+ Š_í÷|Ëõø<’€X¯I Ä\ï–s]Ú@Øh½º<Ù¿\k|®c»½ûA÷³æÉƺot<Ï·¡Ê› 8å  :þ÷bb`ÒïXä×¾Ì:|éyT¾9Ö/¶¥Òë 2]«¾E™cÝÂ\u毌yyºÍí§bŒ¹WöÍ×X뽨ZÛ4 •Œ©: 7ˆqÛ!éDµ+÷èzR20ßCë@™¼&¾1Í–^¼VøãýÞaÌ2^Ž·Ì2{ÁP~oäï§¿ŽáZ¹»E¹^½RÃö²™ÇG)x ûã˲µï²~F•üÅî6gªY¾ÅÈÅÄúg²¡~éLÅ-wŽ`GHñ}„Ù­/ÛÑÜRˆ€ô)ֽܤf²bYÏïáùÃŒUʯùââ�†µ•3W@æû#éÄUÞŽYÎ@$0¦Vfúó€±p×ÝBàŽ›ª7Î4Ï#À5*©H6 €yùKßbCF>ň!Vúk�aÚ>J @3Ñ=Ûð!âÉ7Ø2ú ‹ýyV&%éDæk¬¾aÄòi�pÏñæY �ã‹=¾Àìõ¹Ûnþ ù,bŒ…^ßd¹r‹„ïc¬n´à­¿ö¶>¤H ì?ƒQ3wÅÇÑ¢¾·†|Xy€@5œt�nC€‘¸íu–»¯>Îz h�jd3˜sºžêx,Ðÿ¹@ìBãü-ø¨«[Æ}*ýP¹1²Å|†Aá3lžÑŠ–~¨°&?|Â-è¾êŒ×­‹¢¿úPæ×–¥l‚=}˜’$¢ Û¦}ƒi'å>¦¥…3ïi%`'àµÙ8ÖÆwˆ–ÚÇvæŽH4”¯»¾“x-53`zg`§sK"qŸ€04í{D6ok‰D |-„1éÃ5€Ò' “¤òa޺ݷŸ4 Ëg˜½Ð½U¤§öq lÕ]Ðõz{%�½x½ .˜%qA½d”’jÂ'“~åW¤ßºÚ©Ìczé~[’}¼Ü\I ®€9 ’•: ¥% õõ)QY*PPýRŸ6SIKiJ‰Äò˜ûa[õßo·léO¶{«�¼,_pù:­5úç]ÿð(ï'ËšçÛÍrkÒŒ5ë('a:®@v˜ï1ù{Õ€7ù$˶ FæÍ§Û*~[]Ï’9 â|k„NÏ}ŽyóûtfßóG?ß´3ÅÜ~RÊ™’V,d ó`t^2ÅJ;Y‹÷|Œi ¬R®V,Ѐˆxë}—Ì{/åçW˜â¦*Ç”ô¦x³¤œ¸”â&0á0Ù>”Qÿ¤tÔ5ñþª–¢‚çûLŽ‹fŠÉôGÓñFqÞ2b„q_br|²t¢ü)Gã;®º\«%ùqIûC»­Ów›­„’ûkÏßÉŒ‡@’‰ž7\/lÛ’nx÷=‚ç= l¾o1º¿8, G/›NíѾƈ!�b™É–ÔÌfìŸ̱=°}|Uú6Kà‹$1ÂÔqEP¢žó|‰i F82|”y>ÎÌ~�–˜a8cú3€0mó˜b0ó�«¶tân#Ÿ5³6MaFŠÒiˆe�ö¬›£\Á‹Œ°,MXc&—ñËü96=k8k‘‹þxñ絃3Õx˜|†ùíÊ€´t¢<ÝN€Çûéè¯ØÖßwÄŒ=i_`ãF@˜~x\b»žK-¬ad‡0Ýgî‡çÊó}Ô’b3Óúæ2€0h\*>½<ßQÚg—(‡ùêÂX:]n ˜O=~ŸjÕü3€°êõðÚÝëãͨǓ„œ{ÿuÕoHöúÂóLÿÞ´¶V=Þï°êsÎeˆucžDâ²³cn¹ò¢kJ#zbAÄ ŸáÔa“%=M;}.-‘h—Ób`Õ™dG§×­rùë^ü —;lw ÆT´rƒ>Ð×Õ‡;€íÁ‡˜C}øjÉDµC×êgŸÉ~¬$FϾH0Äê;¬5Ú3,™¨Ìt<Úª#‘8º_×¾ZHPQ<™Ï¸’aiž4–w~‘þhI¸z;l&Î>ù\+ÊE#_Bá†<ŸgMÍ“åÃD0SªÖ‘nŽ"™fêœP -§E|YN«=’ñW»ëål©û¦l§6[’ÏPû|¡8¸> W~-&—çÊÞÖŠë¢2{|ÖT9à�‰²_×Õïô„ êë,Í’|ä’™V¿5ìeC¿ã÷¦™c$}Ê~÷%ÓL&©`‚/×h¯w»?ÛN¼?oÛ’Š«‰QÖlÇlL`Œ××z>i©EÀðbíu%Œ½.t½¦ß74`V2Ø»êY€1Ö2»þ𤠶ê{&I(BÎøûë{x_¥÷iñ~Ýê§½‘M3êH ¼_JÝÄn!ðUóq¬™b}ßaqÜvá„;N-¦X¥ž6¯ÁPhû›Ï“ñåwó, ·ÓFVáó¼™Í“Ltûçq]UxQ E?ýøŒ­{° –¯±67¶£\ Ø"à ¥cŒ˜a(™x8d¦/]g^þŠÄ³òÛYâÐcÞ9ù´Ï²niF§GSF1ÆžWÒŠýæI%Î×-mT:±ŒùL/.:ËÓívæï´8s–L1c Ÿï # Ì ûæÏ¬S¬þÜÈãÅò…O¥´bÕx½œ!7Æ(@Œù#³}€Eó¥o»ë‡Ñ–D:Î0ë`„1©DàR‰“bx…û r}{$*Œ°Vb¹Ÿáñ wšœ�`0cb|yé[ù;P¢\£UfÍ€dÝ~Yµÿû¿·¼^&Ÿ¶^IÉE%MÛÇëµ(óp4t¦÷ÊŸÕ.‹!�]@˜\ÚØUœ‰egéy¹ciØ| Þ2„D¢á4Ùc„±°±ï%ï%oí$ýña=ùé<9³>ª˜bG+Òˆ=Ì+.?Œ¯‰t+üÞxZ;Nu:ÁðbG.…¨¯´ÃÕðÙPñÑᓲ<61ìO›>ÀåítfVÝ) øº¦ÂšæÑ³+™Z[UL/Ï èó³M�aÌZ ‹õÿmulµ·œ| —@\-$ëd¾mÅx�è— ì°‰€´ nøŠÿ‰ð\¿ÁäbGÁ$ék‘Z˜‡ú‚¹Å̱Â~º-8h^'’Ï©µ¶¥Kæ”<úR™6�àV-ÀNey[æ}Ö „Qy7Üò|€ÊcÀÉúez.¥éa`¦óÇ­VN)™™x@åéuØ»r|Öª÷±Žoa–ï9ÏD:Ƽ4€0 çys©y€b|gæ'Í3¤=¶ê=^¥o1~ îY.ÝèL×Wï–îõ•Ù6OQ?÷5“{A_ ÇšñºÜÖûOlMÿ{S¯é\ij߇0ÊÇÞcÅ{¯~_%ÅÞTçõ÷„Mþû¹?Î;iö‹o`³ßß%cŠ|ßRñœAÖ«´AF 0nËE¾ë*=Y¹QŽ™ÂÌ ñûÄÞh™I†bò¿«ŽË6ë ÛóõmÄ—Z¢NÝ 1 ÓL±ñåÔmQÎLàË ;€Ï1ȱ0cyÅ’Fí ŒÎW$=¦Xؘˣö!Vk—9N/äcØ”áÑñÖ̳i½VŽÂiDæClD2“Ù Ï7=_åЖÖ¼ôѶOÀfZµbd„íª| dŠÉ3|â­˜[ jë2û„yÖºÖ‘ &Óíº(<e#ž?1Ħ’ÉF�™·%QÏÓP>w)€HKΑÒÝNù´¯²^"�ù㬽�o¿uJÆÛu”ñO©x +Œ€0À¯‘‡aÇ4Àe0¢@ÚãafÕþ Ê'ƒÇñÂUfO+?€Íôª0{z™L½é÷áV¹`š+ÝW•x‡I¨­Li G3ëFbTŸÉ�ôòÍ`ªuIKBÿu¿#6¾]¦™…cQ“Ù®ï„ñÇ‘fzQxŒƒ±Ôˆ_5ÁN‘Ù‡�º6ñÈ&n“ø-'v[qÙXòÚç[å’•$Ñn¤£ü ½á–Ë>pKàGJÆp†6h×ü�� �IDAT˜½“EøÖÌ/£ßU`Œ§ÏŠãr\WôBAÅL©Eð>ô½Ê×çã‹”³/°"ñÓbØÉø›I‚ˆÂ²*_»M3ÀÔémíƒdær]ëª lŒ0/Üg£Â0>#MKº­ f϶DXL/Ì%=ëZËp?-XKfG>Ú’h‚bWé´º$^Û'@ Ô¤yúœb0±òÛŒ$Í8*%Úê¾â¼þ–L# °Y××Zf³¥Ë|ÆÑJw�޳òl�ŽÒ¯©°?ž:=/¯lÏ–8Þ(Îëþnã§](“ñþ¸Ú�§=Þœ‘hï Àñq*Z(nÍ WjùôïXK•ÖœÄÓŒ0cÛQc~ê�ÌøýQJ+Êq/¥rµÕ™Ã^¹`ÔsÅ̧ÛáÕ_•¥ç –RÔñž‡žÙ–|}j dG¹×<¦˜ÏŸ8©Ž×œx“Yæ1Ã:¤å{ÌŠáó6Æw*037’‘[ÚØEÌ0Í3Ê76˜‘D¢³<lç—¾}¯©÷a’T´¯·µ \cxùßO7jýaOj^¦»ž”7z,¿Þð(–q«‰!F’ŠæŒX3ý=lûÐÞ-¶´gÞÊrÙu”9e×ãº$Ð3Ô¾ÍXõviÆ—cÓ |‚!€å°/ùWeH±/GÁØJ 1ÌJFWƒ1¶ €0 ¯8íYÑåxãeûø*Ú³#ÊùXI3Àæ2Ä&ª<†I%æ™0ô®ðÑ¿+%ɇ˜ŒÙÆ�9awÙÖež.›œ1ŸsŽd½Ì®çŒ%Ú,'%Ósze¬×g˜ši¹D"¿¯r¼žY´/®%¶|ŠñcÎg®; b›¦Tb{¼¸D"—NÔÒŠºßñ¾Î^yy�³˜]¶ÅržV@ÙÓ°T0Ä*ÏK!¸‰Ì°u ƒ�Æü™¶ö}ZVß:á-à?¥Ïk†XC÷3%¥Ø0oAÝðqEñÚ4 £°*€Âl!`ÀèO/Ð$Ú×á[lHš  zùG4j·7þ½åêòFc­øE}¥™×µ—!æpûÈl¯�ß™™ßó%Vñ©WmÏôÿÆ–LtmYI úb8>c¬GRCïdã„uHtxûé¨#hÙ:ðŒìœè©¿°òÃ’– Kíþó\ÃZ’ˆ›*\ʦæ‡ód/m§×M-‰ØÙ~ßp—ۡί4Á ó\€0/Þ®_—7WÑóF `øZí[k¤X骾Áf›·|Pƒßõ»Bê¾¢r½k‰IpEÄçú9“lÓR‡L-çq½À­,É˧W ÈêéÇ '½–&¼6 pBN×ÀPPÑJ@D¦Ë×µ·_à’%}‰D]_ˆºaœ§øÚõ(¥¡�´¬ë]RœIó–³óF~Š÷úÃÓ]é(—›'½hßÐù{÷lËRû}ŠqÓ€0ý~®«þÔ~7Úº€vÃ×›òr/ùPcÀºizÞù–Ìb˜µæ­‘y­õ|é—VæI/.¥Ø·Ýš9¶ ¤"YËY§¤bj¥ˆuH(ÊzvÆ$»m‡ù¼•-=õROìt:=lby¸Â 3Íó9ÆãI2œÇ·¤$¢–RÌa)õóÝh³êÝUçé»++qhæØ‰ô]¦mÝÄÌïGB‘Òß7\ Õþî³ßP}‰ÄùœU–Ÿ|ŒµÒ%ó$»7Ê:\X-¡¸¸t¢´#°6cº`‹óÂ&Àtnò|áθt¢�€ö ÅH‹¶—0¥¦ú<¦˜å“‹ûÓR†ž¯–o/�à’Š;-`$¥ˆÑ;”5¥ ív†N€T×–\¶Ïðò¤ë@™Á\ë4’LŒ+@Ï5$}ó�°Ý9åi_bš1–­Ëk£-•hß7$ ˜Wú¬ùù4aœ‘80¥Í®‡˜aË�(™(­O¼–û“í£‘Ì3¦dgïZBÑbvq†•ý|‘3öý†Q^(]ÞÌ[ŸÉKéG;ìÕÓË ÓéÒ‚½fˆi� ÏÂàg0dfX°áIèíƒÔÝB�‹á›Lô«>ÁfÔÛò}ÕzÌ'«Ôt=í6¥ùØx˜íîhïP?ÍïIk’}‹½�ÕÐøC[ʱë÷$;ú*w°í*éωðr‘?›ðf ðZéüXò�ü‰’)¦?Tå‡Ö2_Ëp]•ßÂì’ÇÓ"“Ýb̰–„¡µCƒ|ìÒ€åpe|Ò85*ÃgÂ& ïà1I"j§ãÞ‚B¥ßÔ~kœK‰Ä.óZ:œ¾·Xlgôí…£™æù�ÂRÿ}©CÍü oñ#XL;l/ú˜a¶šßYn¡c-”î×0+'37Ș à‰´­™s£¶0Üö­e¯fr•Ò„�ËR†òúŸ¨HRj ={ÜÚ€‡wïϵêxW@Ykû u,ÛŸ.¯ÝšeJ–Yé,ÀŒ×4ÓÍÇr\J Œ·ÃÂ6Œt½ýÐ@&¥Ëý,2iš!êK¸z÷eϸÐ}ß„ óck|ÌñÒ@‹' EÈR‰ kyXK¬R|…aªÍ»¯j¶í\§UÅô[-æï5È”é�óï—éç$`c 29žsÛQðLè¹O€×>adšÁ~³ˆ÷ÊÚ ´�cLnŒZ)|Ê‚Šï?âïµ´lªeN¤ dr'y ˜ñ+‡?¡ÓÆÛÑzßJE¹£{G™ï0�)ù®°Ú8’•Ë”×ÅwYfŒi‘å<sr€#o|ì—tô¤7xR0ñ%í_r›Ÿ0WJ±%n›'¡¸ÔPÿTgryÂYžqã“ϲ†ç`¾cè[¬ùEfAä;ÌðýU˜Œò _b•åÖ€5årµ/=s¬T™t£«Už ' ¬jMIÆ gjæ{¾K¥<?ßmËæI(¶¨í“÷A‡ç¼p\)›Šöz’ŠŽ= q^¥£Á/%€Ì€¢q ¬oÝÍ/ò5Öóœâ@œå[¬,ÍÑàÒL*ÉqÒã Â\ÎRÊo•o3ò!6•ùú¶4<í„ïCŸy@د[ñSlPJ±a˜tHÐu™çs¬%uƒ€\‡ôœÉ€cŒ/Oªñp-¿.Ÿ1Ô¼ñhIói`i”Ñ5$! fRG{L ¬WÂ:„Fyf~èÔŒ,³œÞû½%©Ù!Y9K*Ñ+gÀD}=€™½uyXĬAf̯^Ÿb $Aå¯ïä³½ìBýƒÍ/O~8Ué²KÞ¾£bI²Þ~T;Ia%`8*nËp–JHξé(¬æ;,I8ê² [i0Ƭú¸ÍÀRkŽAûƒª;’= i^þcpniÃGšf†µ|„yµ9¿^¶§Ž[€Ä<©Dî+lh!˜™-á¦ÓÓë–�ȨÞRêË+¿-1føø>Â6òõt\‡)½ÁüÒõ÷´@o™å³‹3Xòù,iÈüµ0ËWàÑföäü5Ÿ]ˆáÆ5-˜Ÿ"%L—ïQœ©¥']ßq'?oŸÇôð™UVzï> `Ê*ß«Ÿ×sEÅ{÷—%íȺ¼Zº–D¤euod¥t¢Ïó-g—sJlZº‘|Y¿'²ëEþÞ~Û×3JÅ}"®òíÊ�ÈXÿ4“j¾ kÒV@]`I"z>Á4s´åû+ZKøÛó‘Öx®i E˜û\ì6G"Q3Êa±÷…¦ù>ÇLóÞ·Z�Y—ià'Ú5u”¾Ç,³¤¿½÷Ù¶qLö¨ôIJªœ6¦m‚ŇÈàÖû9ç9Ԥ̩>+]4ÎáµÂ ÂÜטÎìñ£ï¬evŒñ'Ô‘¤5€Hãw×+ø ¦d~Þb$G<.¬ö1¦Žý¶ú Pú›i_à½"ßÒô²µ+¥èhFÜqÂýL1éSÌØ:M/‹¨MG Ÿb âç�@fxi©C’@”€S9S! 0<îeIů|´q ŒcI*°Å3}Šî–ó‚o�m^¹�`2ÇÌþ%à‰$) s¤£ÄäóeºJñ°£N¼^Ì>qcƒÀ[HÌ2 „åxÚb bálBÉ #+}ˆ-©çA9“jIÂÚFpnpißa›y|˜”â²»ÙÚ`oJ%Nª_fñÖsø¾¶}™IéÅ2þ¶(_3´J#�,K&2éDÎ+ë×åÙ3¼^ ×á´ð®¥@v£MƒOŒdUIA8b6ºÀßtÔÓëûËc<õ¶³‹ÑS^tûz ^ÆžHÏ�?¯?^ÿº¤%þ‹0»&àV¸Ló�9ƒçµ{´üj{ iÊÃ*¾Õ¿Öï zÊ©ÜOÕúÚ’‰žDâ²+ÒRZ¯¤ OWìHësr,€±>Íi{)j9}ˆÉö•Ο[ý9^M´™_ZÍÙ¶ç#K3Ä ‡�Æ>À›íHÎÁÑ—‚^Ð’1#�˜Ý~Í+}uQ?+¾Ït9ze@QZÞgx²qÞŽïµØx�™’J\Õ;ÃûLc´Ã½"…8_ï_¿Õë£ön³ô|¡¸G‚‘¬W‚£µÐ¬%cÊ¡×F¥Û´o#+=g¨ôøââéA¯·ÓKW—Fì‘´˜Bïo7ð%þ4ƒ«%8Â|±–$œm/9÷é‡î¸ÁÌxï¼'Ù<¶Æ—_KŠÔù–ĤfÈYé[̰–T£”z´—åïoÍøjí±�µ! UCrT<“vÍóœdŒy°f»£ïƺ­>oIÖv2=Éð¶Ë õ-¶kKù ì2OB‘h[*ý 9ïÛûãC´i7›ÒÒc½ñ%û¤²µ@–׎Úò(/ååm“& ×åûë¤& †X\O»´Yß5¡°ÞölB¹œ—Mo8ñ¶ñå]tíBfˆÙ‰ž×R9nEýÌ7µCž¿­�3­«pí»/WJŸc»ó¤µÇšp»éÒ`ž5ÀЍ:À8 ¦ßÐï´EmkÒ…šO��7‘)–˜c*Kñņåß$†�cž„¢�ÂhÆÚ 7…/1ò5¶—g8¯?–aÈõ¦_ö´0ŽÀUØS’†º<bvy ®ÌüÚé•\嵘cÚ’$!Îx ˆÒ’Š=íÑŠÓór†½ˆ:])¡è͈-À,š/}X÷ö‰Ã#ßcŸô1ËBQ?›9{ž –t"…9€V2Ÿt|6k§-($SoP:qÂö„OU¹VyVïi›ÇÖ e}%³ê¶Z×´En-_b½¶îÃô-FF¾ÅÆDpÛÒc"ºM€Æa‚}æ�f‡è|w <ßa‹ú~�“ÁÓ,æJË™r@X—´Ý€T`UúN—S‘øë’Æ[T’Ò“ºœ1N³ÒwÔ?¯ÏC#]k|¼ûX·_§®:¬uŠñ ÉDëß±6¾„]¾´Õ0SÙ˜vj©ÃhZbãzñÀÛdé{Æ!î„”†d–ϰ9�!ßA-~øçÛÒWغÛÎ6•2·öa ÌŒ'õSoÕ8ÀUúó>¼…Ó¦~@ªPê-oØgXj±ò¦%æùc¦%GK«PdíYÄ—¸«Å¯ œ½õÕûQ˜áã‹Fúé8´Ú¿Íxí³È‚«ãù5‘Þ— lùrÊÀ—.Çò1åíCçå[íµÎטY�Ј`Vú—ðø¡SÎK˜ïC_öS¦UîK*¿x½TœoÛhÿëõåñ�”ÝvY�ç'¨òò90&³-˜µ®µÆø–éd»·L¦e‹É9kyØgc è"éļL,}Œåó”2 &ƃù(¹8s×jw–X¤ù_g|œ¥õ`­åäü|ëÝb¦cÏåj{*ÏqÕî†tòvë}bŸ|µMÔpƒÑt¬ˆŸkö{äc†E@ëÚðûª0å;·�šp#x 2¨~ˆ lnI‹[Òé%0v{™Yß%åwÏßÚ f›Ür£7&–éDùøò„½Â-ó|Š©ø…}p)Ӏ؂il¹v1/‰n¼™Ç™™F}‰µìN@¶= Å€ ƒöÖEÍ»Y¬öJ &†"°{á¦` U–ƒ<È&\þa¾ÆÐZQ�ZaZÑ©oG¤¯”kŽG*?¯@H` ãðE絨오b*ýn§±^»ë`dr†Ò�ÔsN¼or†ÈùšAJcìdÿ[M߀՟·ÍrîáÌú Î@5�¬Ã&_ Ëã2°‘:µãÐí¥‘»Ýµ~Æa¶yO˜2]m]±!]H¾Ä X»ƒå•Ì1í Àg¤ ö´*§ß‡Y´Â‡˜ÞâÆž0Ÿ ¥æ&�&Còo_€2² Ó[ßP»¨oV{*@ÉüÑL¯€Šòú ›5~ã¸ß¶/÷ÝÁ‡Ý,_`÷‡Y_…Á&Ò·}ˆí6Ž‹x]àvzÑFŸa–¯0¸8³§&‰Ñ»3B_òP>Èz¹|éã"¿§ño¥ÛA`+�_K(’j0£½ôúha^ÿD¼b|ifYòFþÍë Ma%#œ|õó±Ÿ ˆbŸ'-@IKì̳n Œ�0GÚh{¬e´c½c'z}Á${€0-¥'%óˆ3'²„•Ât=5ßc½ñ† _:¥$b>Ï[�Vp¡} 0ÎËq´.îL2VJFKk¼d¿Öv¼ˆ¿ZºO3…´„¡–êkÕãY/`T¿Tœ·ïƒ—T˜�°r#ðt²È)Ÿ.W–ó’s7,¯osø«_ß—ŠxkœZ@Ogaü¾¨ùZ»Qø“íµ|šE+¥¯TÊÑÀHö9¶&~w'ÒQ–sB¥»óç5CÊPHµ‚’z<n€-¹H°&Ó úQ „yFél ,š–ÂW xÍÌ·ê”Ç™ÈóLHk=úØÍ[UÌqï|s¤=Ó¾Ær|ë=ÊÂÀy?Ó’Š¦Ù€‘Æ¢­8ÇV¹Z"t9¤¨@'‚òQ<™ßb™×ŽÏŠò½_åy­8ad½ß'Üør°-Õ2!%ɤ=àðGúß…ëJøk`:ßÔtºü=šF:Îl·õw*Ú| EiËêMuq ,ŽÃR“3Z·O1Ï¢ö1†6W¸*›œÁŽd ¬!)˜[V‘Fä>Æ<€MÄÂJ„yùˆ †±Ç$s,ÜÔL3mZB±Ç·X؃nŸk#¾Ù Ž$ D@—ÔX¼îºœñ{^1Æ}‹¬Â›çŒ!—wtVþq L¦ÿ°çTy3}—™@XŒ¹Õ\ãñÄ{ÖH/¥ÿ¤/1.MÃA:z€“ñ¼™ž3j@€nz¶8ßVH¢v™¾Â‚Ãl›–Üç÷ö´Šç3/ù“>Æn#°Få/% ŽuËÒ‰1È@X¯çôb|lŸhÒŽˆx^O¹Šž¢ŽWáÏðx¨«öÂ*�Ì¢@˜�™ç¡dàx¾Ÿö(é(§Ål3ÇÍcÆiIJ <vHBŽ2úæú ò|ª™í`ýëjwGý£í4í[îz/½÷‡6ûÓ ˜6%µ-aÞ¾†Ú¾¡é®\|¸À(5X2ÖՇ/oNüQµôJÎ¥­×£ÚΚ֎͕âW·ÇÂÒ8*æí0VÀéú:H¯»ÁÞ{žÚ=(‘X¾~óÍvŠ}Ò8ÂW_H(÷çõJ} ´aæZ!‰ˆ RÛjju0’fbŸ±Þzm};á[Ò„ÛÅ1¹0º†ùZ;ý3S`® ¦—Á|¨0À Z†6#¦€Õ�1-¹æ1F¸/#h”o1WÊöµ1Ñ,˜%e¨Ô-I»ÖxAgú^³£»²ãL·g'HʳNYÿ/í%³þ“˜ïdÀ­ñUšÌÿ’[žn‹)çµC¦ó6«få·Êñ¤uùùþö˜c[fù¥O;{~ãÌÎøûé²O¿-ówlùì5’R /²ÈôÊŠš)&ÓgiŦX/“̲6pÔË|Ý2ë×R>ï¢U÷J)ŽK(:ãã½oôZ‹ù¾8³+¶ªQN‡¯1O:Ð~ïÜQé{yKK)ò<^„ÁÓL±Rª²çûÉjŸÜà§}#Çð-¸!¾',Á°‘ï7 ÒJ=ã‡À˜ÞXÙ=SŒÌò½U+ßBÛU>Æ:2-¡¨ãaßbEÍŠ†€Øg†šÏ“ŠGR¸ÞºR21Å[„Ì ™ ŒVå 1”HtÅúsX3Ìè|KB‘�0€Ì È’‰Üç˜e¢½Lòò�Àlj½åa¾òšTojfÓŠdÉÇØ0CŒ|ŠyÖ7Ó—ù}Yi}b²£�YÎ7Rg¶ >!�ÌçÚ•ùi3ÅmðhY÷ ‹ÆŒ€01Ã’O1Æ[N¾ÈæØ½p[øKŒ1 ˆ9 2ΓϋRZ’â{ž[5`Œ]á>¾89PÖßS?äú ^ oH'ÂóŸ–ëÔ–™J-æÑ~™ÉaÀ‘HW‘`ÜWFÙ@»gµg” Ö/hHù-:.ûÈ ûV‡‹šq¿÷Jiêqù¶ú54nmÉDý¢ìKö-5ë„¥‹Ô=@iÐÇþè¨qWuŠõqSJñ(ôî,¥½úmßY×Ôƒµôæ`5+�/% ³¸µšK«cÞÂH%~lçóléÃT£d~%i# ãq&�6 A ›»Ã]߉où|)­å Ìó¹\™ßªoTbÔ‚®Hç-ì2FD5}ÅF�—ž__}¡y­H§¥yºãŠñ⸢/€.ÏG“Åø±� Ѐ• È´¤KFV à‘ÀU´k`%'1þZQ®w^›lÇI _C@è¤bVååÎ,­(Ëýê–9ˆ]cL4¨Äv]Ãvñ0•,lw^|ïõ”×:¯ù�l_g5iE*ϺßyX¼üäßWcJjk °ÉÀ@dzã D::"½5NU+Ê:�ö€ã7ù 62ëòAf–V´˜É2-­;âC̲q ªK¢Øá_äñ i@LŃß0ýžä ’µ6:™õyËÊ“õd�LZ^mIs7Œ�0Í�Ã÷g.yØZh26ÒU–Ûíä>Ï´ÄùŽ“Þj@ÝSNÌç½)ØåiÛ…Öþ.`Ì“TÔÒû�>&™(Æ_ûs¤}ÛÆ~‘oîzü 1Œm«øºo1ýÞúnïõ-6æ‰Æ7/—çiPl[@’µ|*|„µ¿ìäLcøkŽ Êöˆ1†F’‰4£Ucª¾u~À”LLç5°ecÿB)yè�[…a#½Ãx ;$•¨ûMçÀ¦z€1Ëéƒ9®Â¨Þ¶/1iŸàùç06�# Ç—`œ%¡˜¥ã ™c [³g.QhÙ=h]$(Ÿ·y\$Sø8Ïíp»±N(û�ƒ®|åÌkI1ƒË/ß”F$ßaBJѳ1 EÏú$É éD2ÇwÅ6ìK¬ºð?ê˪Ã4€0 ÀY�˜Y´½Òƒs¦!Q•ò<€L�>¦^«üÞq"Ûo€¨*A ÎõÑ�kk|GïGm3€N³ÜJýÕò-ÉDù‚¼¬œýÚ"1¶qçÂÚ–@ûž:nírõãwꘖFLþ²G×ÇÈü:ž`\±t¥zcã@•/K¡TÊ&]”R)æNÒ!mæ œK«X@ئS^­|îÜœïl-_?‡|„õî$®HíÈúŽ©øÙ@Xj!.@¥Éþ´¤ŽZ¥o7ã…4”Þy‹.jka^}[NXJ[Q¿hÇ~)å3º¼x@F1$¬ñ¼!°ÀÌ۬q)4ÝÎê˜ãåÂíugNx@X_º „q@Ë›½5� -Z>²€K 1·#K÷i¦‘– ÔÀ‰\°Ï’„€åJÏóTÌ«€úкN(`ëClåö¼$î“ øÚPíÐý¡z(ýQˆrN&Àê%U¾°®±|2 "]éáñCѲ¹>¯ßr¼Ëþz>Üäu}ɬñÓ÷³5?X¾éôqÉÅÞrO²ýkªÿöü¨ŸÎ|áç}F©Ý_+¾ö»MR±R*Qû"37 ´|Ö¼é=gVU: ôC“½æÄGÛVÇqfrK2Xûø€ü<×ZF7Ääq" «—‘¾¿Œuf]Õz#Ó€oØh£@Xï†-ýžLÊ ; ÓíÐ n•ïÍ Ê1|2m˜³%ÇË hµï뻄]Ùw˜„J©xÏ6#a$¨7h.C?Ól½gWaº}ðe�aµïaÞ~�îš@Bùƒ|C¸kãû¼øîF戾ΕP<’Žèò—Qó—•„Ѳ©>û²s$oš€N‡€‘’”L³ÃøÅª}‡í#-èÚ º8FçÕ¸ /³ü2@æ[ÔuÜÑå°Ö². l¦1éD ¶ãÄGó0Š·¶d{®?jZ2QΔϹ\T9.Ÿxñq朞Ó[­®ù÷SvÜ)¡Ížiža’ŠsM_Ë(™¨aŸÍê—àHB1vGw’ˆâÏS’ô‘3¬ñÈÒ‰ âëý±¶(¬‹ø#�Œõ�vVºuu^Ö×·5â)utÀi†w€°™¦%Ø É¾ªd`EÒP›–$ÓÌ/°Î³öšŒ^z]?tJòuH4V%óh\tú ÐAãÓ;žà”·gå×ã®ÇÚR}º]­qìÊóÊÕ"ÏZJQ�Œ•û¬˜™í÷~?­þƒ#9iÔß;.v;ClœÖC™-^¬[̯øAAÚîÅYgÿ‰�Æìö3¬Î Ë^¾É‰>b�¥é£JB¤Ìßç´ºò’cÐæ¹œ ƵÇóý…éVI‰õ"�� �IDAT3lÌ7@´ì¼<ïL­[^˜°´¡;™`ÆBI9ž5k1ÆcÎBR±µ°¯0±°¦}°…³y̰¾ÏližÏ)ÖN³É8[álHrK.ÌêÛ®…ÜV¿Éz¥ùøp懷:³¬ߺo#{ü¼ÎŒ±$ ï�*ö¼ä\OŸqT“Âó�`R…ª<^¾N¯™XÐÅ­”.÷<…­t×Tzoü¬Yn®„'€ç‰G†% W2½8c¯Ö|)EÙ—Rú–O6ÀúlÓ>Ð^rî/Ð匰žùçx%•Ó’2•íYK@`ØÌê@“%¥8 p7æGÁ“’Šz#ðÍ|¹ÙZìi¯¿±Ä–H,}‘yÁ[ê¹$Í{ö — I+z€Ù°ù@¶­â{­Åà*™dÞF¨.Æ˜Ž¯˜÷H´†˜k®qFXlÙõÂ7¯É„RR‹”›cÆö€ïÙ†¤bn?ÿ.âËæü½^K·çzòwNàEÀYÉ¡m}E€¬|3àÀRU ¶d‚éú4°å}·’o1 ZR‰#–—eå̱Y¿d½<Úí³cd`V”«¿0œð~1ÅÚ[Ìñã’‰žT¢Ž7K7–µO1[BQÕ¿—}‹IÀLÕÐd¤¡T¢8?–L°P)ÏÆ>Ï F¥Ì2&Å蕇Ì8lçd¯¸Š˜ÿn8ô¤§çÝó}À˜ÛNWJ1†3c 0 " *¾4 K¨}>óÌ¿O€æË[æ¼O�سN>CL›~2c,3ÈZ‹1&€@ÆÛȾĂ%åØã*%ÕŒ0 ôTH$rÓ€ØÓ V¼^)‘¸d>)|%&µO²60¦ë¾ÄÂýnoŸ„£æ “Íó)Öm€ØgÝšL' ,Ê`Ѷ_’|¤4ÝŸ…˜W0“!Ö‘:Ë©2﬷½í[Tʱծêu¨H~w¥½-àµ:‹ö³u½-ÉÄ 6Ów“” ræDÉœo:JÅü/9EçÃ1ÅË=ÐËòêü«ÿùqø1ÀôVx.„7àÞiѾ‹Ó%ü÷2�<ÓM¸ÞÄsâyï�LâX˜žTíTõLQåø° �M) ¯ÊôÔžp`z L»±þ° �ƒXOªÿbÊÿ/oº(J{+¼ï„7Sú1=œ‰í_�L¥MôŠÓŸÁÐÌ'í�žÒS|Lÿ�bøKLw^€_ÁGXÞ"ß9ˆí?ýºŠñ_©òÞ€÷�à1¸¨âq<à€ˆ ãß„%µ“ÚÃq°þpŽõ_Œ·nÏt¯ÃŒ_ñ¼\�ç(ÝtA¶Ûˆ£ÞÞçÍD×éË”/¶ç †¾Äóåõ gâõšb?¨ú„8&ó>˜ÎÇóá\*ë™páóçÏ7L—â/ðtÓ¯0|®¬ ž�€ó”âïç¯Wà`8»8 Ë¢ü«° �Àoàs�€i ^€sðÿ«¢=çàIlÇi S».©v-ã(¿‡õ^Æþœ€p\Ïaû“±~|Áú÷åt¾`åå_Ùußcûáq Ÿ‰õÃ…¦òwà \€Ó�ð#Œû%öçK8ƒÏˆ ��Óp&}r|ÎÁ¸Ìïã˜o:Ç'äëuÇç,ï`º/ŸÄöœí;ˆó <Ÿ”.þýNÀ—xå»à=Ѿ³XÞ+pZ¤;—°œÓ-qœ¾„à �8g�¦óð6\/cúƒp¾Põìb=¼8n�pÇím�€ð2Ku ÿgãJí ¿„³ªž·á _Âñ–Ïô³òþ‚·ùuŸÎ§ë˜Ó¿Šéžãð"^¿à4Àô#¼?²þžÆ|€çc{s¹qƒíýN±ó_¨ë–•x~”®Ë%,žÛ_à8>åÅzÎâÙW0ÿA,—òý&ÝG—ðþ\ÆôO`ã8IÀü<\€]5Ît]ÆçÃ),—ž—ïa>²'ÂËpïšóï2Þg¯Äß_8#æ%�šïÖà �87Ñïçá€@ÊDõ?Ò~¯kˆ÷õƼÊçó…8oœcóß%�8ð÷:áø¥v^Hõ\æõ‡31Ýt>‡<~€í=7mÅñÆð—ðxìçôJì'kדª¾Ëçÿsñú‡±Ó¯0æÒ/i.ãsåžÿœŸóÈt>>·ØïãCö~ˆý=€×åAºc}ïþŽã¼~¯÷t>Ó—�¼ü°‰ÏÉ ¼þtŸ§ÓË©|y½£=�eì¹¢Ÿ×¯B|ÎÀô+|nÿ0=¿L÷÷«�á}|y^L÷-?.ÞïTîtž½'¾ ¾ÂÿßLµ?HïgÑè÷ßãè=ÞßÞÄùÿ-„%o��À¯à"¾_Bz®Òýú†õ{¡4ª—Þÿh&zkߟÇò¦'à‡,ç{�ð¶ëÍâ9ü€ÞÇãûu|Ÿ_å+–ã{ùôd|/8/LO–ïëŽGxûó yó¼…eþˆÊåa˜¾oÂ�øöu l²z/ÀWò»hz+~·¤z1*÷áôQø<¶cz2/Ñø„7!þ.Þ‚8/@øœ}O†å…ßGÅüðUx#}G]€·±¼³@ÏÍxþ¯ñ;.–ó.†Ó�ð+Ì÷Cˆå<Šß1€Êÿ›”ŸžŸñyð¶ÿoÂç�ð[<Gϱ‹øî2ì+�€ðèKë«éÀôhw�0½£rÖ/pRïŸá4Ë÷£ý¦»Œý<%òý6å~K}GŒw.ýõXþôÎtÉlWjw8 ΆËX~œ~0½£ëãåOoÇóá,µ#ÅŸ¢þzþ>¾aÿÓÛÀÛx_ÅßÁo1üƒé"|ñz�ÎÐý¾Ÿã² ü©íkjON—Úò0 ±Ý¿˜.„¯áa8 0]€w¦ŸäëÎÀëêþ{Gõ÷uLÿ�`ú <~~ï`{b»¿ŸÚGé? ¿ˆù¨>]nªÃá4Àôx8]gRþø»¾ïÖÞŸÐõIו—ÿM.ŸÚáG§K±¼p üâ}ñHxNÀ¿ÃüÿËý&ÝxŸæû(†ãý Ô:Ï7xçØ7Nø+*W–Gùñú¾çœò½ŽõRK©üߊßÏ7áµp�Á~\˜Þ`å<’Ú뽈éÞÐëUTn,/ü÷éÝéÀô~?j×ϱ??íøïXÞ_P8¼�0]€Ÿ�„3ðóŽ×ççð@8ƒí…ð[«¼t?ü^ÃøwÃ2ÆÓ÷ãñ­D®‹ÁkXÏOñ~ù–÷W��á•t?¦ûÊ»ÏÂrl<!Æï¯0ýUüëéRLNÇq¦ö`úw§]�ø]l7|O]‡ßaù龿�€7¦ï§ßWŒý:ü�~—Æ/ö÷êË…ÍkØ.‘ûwðýéÀô=VÏi�øY¼îð½Øß€_ÓÅX~xczWÞ7áµ8^*þw8 û7½ï €Øn>+O—ò,^Á|ßÅñø}*‡Êý~j‹ŸpÜÓ[ÙﱜïbúßËzÙ—3öcz$Ö‹¿¯ïÂÏD9¬_Xïk��á Pãƒ÷-Õ÷]xûó ¦{D=o_Æx¼®é|ŠWé_S=}ç1ÿð ¦ér<˜ùh&ünêçßáxýÌz/€‹Ø¾7R´QûÞã–ó½ŒãKãò¶óüý<‚×íeºn¢ô;ûÏé:€ç¿Áó`‹qÅã7Àí»ØÞÿ�¨q’é×eÚÄûpð÷‘ê•ã§ëÍ÷åT¯u¿Y卸t=qüþûõ3š—Ô8P;¦Ê{$œø_ÿöù¿¦ÿûæûÎ�VÉæhž}+@äŸÿéŸü[-™øíaïaqHÄAFÄζ 5…ârg¥”öp%Ãiü°$�I¶ÃlJ>�á�\WðC‹><7�R9ñ~ åå'{ ?¤©üÇÒ7~èEõOárÀèÃ?D ¸‰å<Äú* ì!=Pc?§·Xø‡õcÔþð"¶#¶g:8]_Mé0šþ/úÒ‚@^y¥ÿU¼"Ð"äÎÁ.`\L�Y}Aã ±Àó€ª÷´°B-�xhA‡Æ'÷ë=\H{òrvi¨9½é<ºX{§_©_ŃtðÐB�ä…3Æ�2P•Êg@ ¸ÔœعI ÍÉü*@¿ ÎM% ŒÞ)Líå÷Ö3˜.À�pÓ¯°¾ ¢]ã‚i\x¥…Ûƒ ˆ d@•W:8ç)üÝ®% ìs–ö-ôb9çéˆãô#È ý§�à<[€¦ñ¦ßÿ�`zvàüô8œ€ƒð8¼�çÚõ < �çÃo`DFž—Åõ½æ£dÄq=hý%äyësÈ�E>.À2Þ·Tþ)„A Œ�êß+8n(:«~ÏÄ8�«7>è¯âù°ýEº/Ùÿ|>õ�@øeÖ¦à7° 0‡« @;0}ê!€í öçñ¯óÛ8€0Àzháü LGå-g€å°ñ×í <*a�ð¶Úz6aô¢¨Ï¦v\ÊG6–—U½ìƒ•t§úb{ϦöŽå³ëPÅölù>�—'1ž�¸]ÌvñzÓïíÖË€78Ç#ü´ó}@€ðALÿ¥È—ï³<òOˆð‹˜ÿBðÈ>éÏ$àë L¤=‰ý¥ù~`ú�Ÿ“çÓxŸIÀtlíÕ8ÞŸñ<?ÓV\©—!Ï/Τy .ЭazüM‘iô2=`ò$;ž›.àüï‡_Rÿ§<ŸÐ}Gý~�·«i^<…é?gåÄú^Æùû<yð8îåóÁ9Ö.š/h£Aœ—¯¦ _`ÿßÃç`þ„Åçézâ¾ôÆòBâùáEØþ'€ €0¶/ýJïåë=ý8Ž[ø¡ÌG÷8—žËôÜÎû“ß÷ ‡ø!¼O€>§©ý ´â=Ho¨¡0>_Жæ3*„s ƒ tÑûO8—ê¥z.ð÷¾4Ï�’7ØÀ¿ð=MK_A D¹o¦üE¹Wޯ㑿7Æçgù�p>mÈŠF@ês°3EÞØ¾ò½ø=Ö~˜âûþ€ø~–¦Çp#Öfú¹Âó‡7ówJXC@‹�Ç'àÀ5½•6"ý=~8ÇïšMÀßgäà+Hïôþ?]ŠõÊ÷)Ù.x4¼ëÁv\‰@`x`{_Œß_p |®ä…Ñi7n�bá…7(N›½§‹ð�œ…‹p �K ¾[.cûð»M,P< ¸Þé߯ûémø0öCì÷‡8.Æ|?ÀãÙrÁ#µ”ÆëãñÓ£1ÿô(<†íL,Ð<p6dd´$€ßÂë´ NÀoñºöƒÔŽ„©òbý?Àü?È@XºÎ§¦¼Áö•*0ª—L† š¯O—"�F�å3Ëû¶óíðm$Å~Åñy;…A_l~¯#°ú¼)È ô_áñ¡Ú0›®' ¾ß?�_‡×åïfz¾�€ïK@ <Äûà|Aú>¼ƒ€„_�„3ð‹‰½çMßg÷×xýñ}¥Gá‰øÿt)W)ý×@ðU„q`‹ßï_§ö}ˆãAÀd/a9ïˆ|tŸ~“ú_Ë�ð pº0ÊΆ龙b{þ Žÿ¿›h%æÑX/aù>¿wš•œ€©„á}øWíô_%–¯cl¶ã `´<™6¨€^¢úpÜb½ïOïêö‰ßïOS½¯ÉòØ=ÁûñSÂþ±Çø Û3ýaPW#02ý4ÅDÀãÌôƒé'�ðþ9¼†×ó·ªþŸ§3`-Áo2Ð0튷Lº?R¹iáû €éBšß"v&ÞÓÕØH�Ø/rüt1æŸÞ÷üß,]Ì Üøû"Àéµ`a(¯Êñïa=¿Ãü¿Ãú¿—úA@Ø»øûú÷˜óß `û{x=¿‡ÀIs@ý}�€é{ðu8 ~7½ÏG -¼×ja9¾%àïã5ñ\¹˜î¯¿‚'�àwxÄvMW#ðFùÂë±=áu=Ÿâ¼üº°ßÕÏÅ|ÿÉûëEàrú¹½û.+)^g „AJ÷³XjÓ#êyöpïb9¯q€Œ•ó.O?m@–ލ}°ó®j7µC·'aúþs�+2™>Èü7ž¼r "@N\/c»�äòjóËÔ5Žï"öž'�‰�ª×ø! K‰Ô¾×Dø÷˜î?§|ߨû”Ò¿–æ™Ø.1†üõåax £ö¥ûDÁzåàýÆêO@Ÿèïï3F@õG�ˆ¾`]ׯb—¡!HæI4Vë¯HC¶$ «ñ-iÏéÏÿÓÝþ×!¸R £V(üjÀË §!Ê’‰=ˆ¾÷‹ë ãˆùeò:¬üÿø?ÿ·ðÏs� ¼§�¦·â ±`~ÄÌË�Ó/ã‡exsº˜˜_§��à€Ú¹•MÇ_ùâ «±¤MÉ$‡Œ»ô¶WìØŒýIÊÈ oNyýÓ[ô¡Û;=–>ýqa/|‰܃łú<.�RîW�Ò‚@^PÊ­>ˆ _м|a’€,iq ~ Ë#à‹Â\]MŒ72ªùŠ× lÏL•wz¿¼½š¦*SšØ/¦ÙØÿu¼¾ÊÛ´c\�d0ñ­”8ÒNmZÈb;Û œC! \( °˜'ïýÏ£È�1 syiÁåE  ¥ʃi¡õs�ø1.]›ð*¤éÓÕ_n6óìq<ÿz²= ™v€3œ�àñÄ88 â×~ÏÄ„�Lwš¥;ˆI$EøBÿ¼]øƒó¨½<]ÀôÈŒ�dºAž?býkð9�œÇm:O Ö_"Ã$19€€­ œ‰E —â~£ö? ð§ð<Üó+ÿþÙ8Mç#C&œ“õA¼®¦…|È.c}±=Ä$zE�Sý/bºÌ£y–˜x`‰K*_2�ät'ý{Î'€çm¤z.§’$#Î8Ÿ¯€b2Å‹sFD½€û\”ë{›/Їsì¾; œ1vVå'†Xîõ—~ºÝi|€žwoc½ “õ‚Z(Q Èp^·³ø{É{¼cÿ~ƒL±ù$î< üwŸ¯?1½$cò7T$~ŸàCÒr<Yl?14_SyCD8Çôéw³Œóñ®�. H¿€ã–7¯Bþóç.µ›Ï£�WóS^'Jw51<iüâ5ͳcï"ÀþöëedræëA^)�ù÷áyœO9s–o<àx>@¦nþC KÆÛoÒýø¤Q~2Æ8æí¥þŸc�¢dxÇùñ,'içÃ5oôx`:Xç¦uqß?Hùó¼kn(ÁhMµëçvz>«çíƒé#ÜÐó%ªÄó›1Ðòý¢™èjܼ2—âý.·ÿLzo(6þö�z-§”ž.Šøª\ü½1[é+4Õñýó‡Xîd \A&à†x¿?€ÌÐ@Oå¼…ïï�g„r¾‡¯ ÁÚØ®/îËøÝ¨€ß!ͧÿ }_ˆïöðŽ'*E„Ϧõ¨<6Ážï¿±ƒ=1ÒÞ$ "µ+ݡӥ¸0bȘ~Ï`3½ Á»Œ×ëT|ßäùacº–àlx@ãÇ™ pŒãÏfÀ -‹!×ñþ>Šíæû ûM Ü�c<e ^w}½Ãç7潉÷~‡Á›ð7á4�¼…ÀÝ™¹–î\½àç_WñHËØ Èxd&îf¤Ìõ™ñ…@\â3†€ŽÈû›ØŸp61Ó’)ÆB4�d=Ô.ŠÇò@Œ? -1¹¦©œ �ñwòÛüE`ô”jObT…—Ä{JújËÀØôÈÀÉð>û¾üÀO° _ÃO��¦ïS,iÓ÷‘Aö\Ø.„ ŒÅp¢¦K�ð52ð„@ÛÃé'€BÚCL'�‹éB¼ŸÂÈ�¯ÿk(×=èþÚí!@1¶óÐŒ¹×�ùÿi{—^¹®+MpíÊDf£‡Õ(t!Ù’%R$ºGêžÔ s”m&ÐNÈ™zÑ6eÙTMÔ(ðu#‚Áˆ{)’¨NýHѶž¶„Ê ¬Izš@5¢DI? lw&á:=Xß·^çœKÊéÞ^žçì³_gŸ½×·¾oI{ÀÇÉØò&Úñ_ÑñÂ~èޔ̈í 2ì‰OæÕ“x3Ôë ¹À6Ãù0~ÒÿÛnˆÈwËxš•ü7G�u³rß©€ÂŸã) L�°xIëѾÊû´ÐÍ›�žÓÍD`î³Ì2æëõŸïÌ730³Ý1Ï‚v©Ýeˆa<%`fcãûî#�ðIš×>Ã}Æd³v:ŒÏ níœ9~Ê|¬^·‘/Ë @ª½"}&ÞçxþWìü%œÿ€yo7-ÏS`¦}*·s~ ú>˜a_SlÚ®àöJ(wiWé1¼ôùÊÚÛZ¿.8t—ñ �Hïï¦`p}.Ouç´ž""í…¡¶_Ê_Ó­� e<Ie õ~×™÷ >×OL1{^W2íÉôø/ºçÛ ‘ÆxŒgìþ«"ÀuÓ”ôê…¿OôÎÀ Àõ|¹ÂX\'"˜°šö>,Ïûx.–ïæÝFB½”Æme~1=`å ¼‡•™ÊÕP�hJ½ ª@ÑSîGøû ÜO éÛdÝ“r¡|¥LO–~~¿˜Ë�_¸d|T_e 1Õö¶~ioi}»3ývÄ_+_4Igã#>ô÷¯ûëöŸS9~[©Â#Ï ©Pºÿ˦1 í)Hq†Xû»@Ìi¿ F ìW娋:ÈißÕšPJÆ4E‰DÆÓóÿADäïÿðþ›ŽÆ•îÀ ¥~W7ZÝ‹Øh9�¥éiÛØr@ï@ÏŠ´+êyÖ]Æâ=Ý ÚFïcäû óó ªzXªgw™’ˆ*EÒÞ _é~..µrK/£ŽŸ’!iD${ 'zö¹'·à ;ÃX $¾‘;¦çn4ì�#cÊ !4H€Í} ôþ$U$d°UiD÷“¤'íݲq?H†’ã˜"ïIöØ’Fòö|ÉˌȜÒX)«®H!…ÑŸ�Ÿx‰†îrÝñæ@@*¯cÁ@~¢�Kw  ”îo+0ÖÞi›ž!䤨AïöÈói$€qÛËÁví^[­›á¹Ç!%uODN‰2Â>õìÏɼðþ0‘ÉC`à. ¿ï“‰`’_Ê´z’i+H"FƒcÚp¸¢ä×û�®\âJó¿ÛÔà|R^w­žÏÂv^Jˆ=éÆñ^ð}yÙ ¿É€Ív0†˜ÞÎJ–rTÊ,y]| Ça«^%hΖc>ÿÊ£‰ÀÍÝÞ¼(g%3nb¼ÜÀñi_€pJ"ƒ‚ïS}ÞíJ ¼zõ í¤ëÂ1�IÖ» éL|~è—LÝL×Ké?¿ÿ¦—KDĘd8™c4¬å¬H{A(Íçù€((ôþQîçP޵ÕCú÷‹m€ ¿Ÿ+Ç2r<Ю"RÇQÒ$}Løq)GÎ;7ûåHíŸë€ Û»`Þ�`>pü²Ü¤nˆ2¹>éž7)ιÜi/ª FèßÅPå�Ú­2îr;xº™Þ­ÿ‹V\æÙ �Z®˜ú]zïÁ ›—>DûÍð]~9ÍÛ Ì3+“FÕߟ—·ñ^½Œvt êl¸ß™˜9­sö#ɶ¡¾>.êw°½lLÝp|St¾¾-:Ÿçö¾“¾‡QÊö&òç|~KœÉKÚKšŸÕ&ˆñrÜq:E�‡ßÝ�Ð¥÷>ÎÓV?M ’F˜ld|%À,1«3SLŠÄb�®ÎŒn)u…ñ”™ß¶.xAz#,9£ìžI&VéÀþùëâ’Ù= é,µ8�˜ ¹ìˆTV:h‰1ÆŠ´8Òjà÷ØÎ÷Š#Ôqôç=‘¡ïÕ÷ ®¿ì�a÷‘H÷q�ÈpT©ò+í„J©ë:¾{Š "};œŒ1—þS¥ ß·XŸêsïÙ~&ÚLéâ›dnu§±Ÿ¹%‡([žÐ:™ò0×ýL΋´oµo‹ˆKÖ? ¦Î}w8侨”«–_ãÖÈÂïTÀàx¸Æåic|In?0„ÖØq@ǘ\·Däùå{¦‘wåcp""òIß§zÐ঻/?¥d#Îï)EÞ_€£Ð>7Äy.k�?µë÷E wÀŠTâ'dp¡Ì?mÒX?0Å”(2¬,Âr²\ÝOÑžŸ§ C‘hìKF�w6–#˜ém_Ý3ÜÞ]-á%od‘ˆadðw™ÉÓL¼Ÿò!“ëSéI¹‹uR`ç>ο ø+ñ»Ö}ªL¨önwŸý6œ§@}jR„¿LïëFîˆØãÉÒ§¸ÿ)QiÈOí}ß'@…ûÞ,ûû@#ð&Ð~Oj»w/¡}‚�|Öo·ãnÙ�¡CJ&f�‹Ì0´c”L|#æÝÿÝÌ Ã™`‚‚�� �IDATù $íkY�à~>c°pCÓ1mð<Öï�J*2ÿ(éwc ÿ𻈈¼J�,n/v–öjž¯ºY§åÿjS€íU=îf8ÞhyºYXh¯ˆYo*PÉÄWË{–�{·ïÉ/�ÜT†š_¼ @GFå'�Æ~A†Ƴrõ{sKD 8í1Ìôü÷]Ò.JBúøs ÈFJœç¾€éGè÷Ïkëu—ÈC¾Ÿ¶"�¬öºÏawü cŸðì.qÞÈó�µÏ à‡ç·CäûCÔës�wUjQDë÷…1/íy""í ˆ¸Š®^ê¼ŸŽ¿1�M:JB"ÀX÷`Xj±—F±P5�Ý´Hâ}Ñ.ªd_Šž³ŽÀý>ؾ¸~Z€72°¾È@‹8àv´CJ¯|UQR¾8 íÄ놀©€àÔžgL±rø"“lÀVLýõ€«�¸šºÔaí'Ö#W†Ò/úã¨2íJ{Œ­Óùè&)Å/¬>|~êç?øÛc-,ën 6Óßuߣң$ˆIwdL²&Ø‘ùDÉÄdöÖoÉ ûU=&Ã+�a)(eÂj̰ìÌàù1 Ä?+=‘)Æû9˜ð¡‹€UÜxUIB2³°a:^®m¤Î†ó&<8O‰ÈÇðŒ¼â×C¢ðÀbéÂÀ$U¸á5`î¶H÷s—L1MñüLj¤' )j¸×�hu/�X{&H4ê†Ò ÝiQà‹†‚Ûâ@˜Kzì0•¸Ë45¶ƒWLjX¡a‰@Ø{áŠÌû–å WÀ¸»ž«é¸œiïaKCCÉñó‚õ8_þj«| "1†XfR Bý»Ú‰ü;P«¶ÉÀsì0Âhî9ž'�&tYù˜ÔÀâžæŒ]¹S`vï |/IIˆyu<|£Ç¸yœc\!f’U&‘¸‘S"í¸Ü•Û�ÂnK² @Ó)\ÒïKé6žKf‡p)uø\ŠÝõ<˜T' sC;ÇãM1©-¡T—ˆÇ&;‹ó§E%ÆÒx¡tYˆiC‰Äâ@Í yÌŒçÒ}+©’‡ÏZþ4DŸÄßSâ†^¶Ã ŒÓw%/ÝóAºê£ô×°”(µÉRgò”ù HMÒ4R02·N� xÛ®;%*¦íC ¾�ær @Å91‰¼n!'ä#‘ö>€°Bf• XaýnIN% hÞÎ*Ú91žÄß«;‡À¯gþ'‹„å:fò¬T >&—H�a§ü9íý"ýæ#/yÎîÀZ�׬Ü(å í%"'qÿ‡e\|ŸßÞ7 lnÀÛ9ôçY\w¿«õ<åý$&Å®?™Ž™;[úï¶óON@*’LÊ $%©Í›bL±ö¾«Ýó�d±\n/*@Ô- @r€‚Ì;2¨+�Ëv>åãGîi¹S¸óáMQÀ*ohf˜g„9ãUç¡1§ãncóç=¶ç9QÀí–(@òõd’†(oG‰G¶ç³6/“aK ì|¸¯'Ù˜I7ED;Ì— ;aÀÜûÑ‘à¼8ÐE¦-“a¢ïË=Ìû”Ö±¤L°v¼Q)FÂëò­øï÷ßiü$’Û*|?®‡ï5¾ï,´`œ±ž×ã1$ã:C™[}i¿ëåo¼~„‘Ý[‡<ÇB ë ®gè0“ömÜ7àËÿ2¿ „¥X~â±o3v¥Hm¿|Þ±hã_&wˆ¡÷ݲ.dòz”¨ Я¯®“{ý`ëk‘«W΋È[²cè[*y®-ÌØÇbJ.a˜÷(%HA±wŤڱßA;ºäœ1¯F)·îÆDVÀ©{K5í íôow÷+ÜŸpÓý ´î§Ôqû%ÂŽÛ¾Düy±\v>﻾-·EÄ$»{é{³¶´ŸÅ;(Žšž¶ÿ©„¤MŒ-¦RŠk0ÌÀ|Mþ¼ûHD^„„â·  É@˜ï—¦ö}þO»s"íi±Ö¨èîÛ›–˜)Ý\Xí €~q Ì€¨3ìkú·/Ř™/í]1 Eä�5¨+’ƒ°SÀï§d–i>mM Ñc@¥Ò¬¥Ç$c}Ô¡>Ï�pÀ†ý÷º'5©ã„åþšÐñMûi†Øb¬ØO:2üí¾Ÿb…IÃî\8~ª�X›n?ÊÛÓVÿt!ÿûrR¤{±Ç�ô9§³7€†û‰1ö”& ê)±ØMq<ÅÙå7 ŒõëN#¿h<Ç� }_Ÿ&ÀFš¦E@Å�µ ô<iýÌ|ØN:Þ¨)@Î?YÊ/X¬@™YOVÉD2µº¿Bÿ21Ö˜o… )åz–‚�[eDhû«¼ Œõ4”N»ž4–J,Py��ì3PeRižëf,—I$^eyS-~ aæ’Ê0úÚ×"0×Í` þ t›ÀÐÐñâr=¦ä"ÿ>Užó HÿýEma¹íV®`íÊLF}ë@^ŸTFÖW=?2Ï’ãTÇ—ŽûÊÏQß)$ß¶ëÉì²ØYö~Ÿ”sŒ�&úãÀ%2«4!cZ>¸ZÂôûw©{S‚¤b(w�ÂÚAar}…Ò‰(/b”u?ì~ŒzÊÖG€0–û <ç ¿Œ4üe›D#€'Äø²X`þÌ@«sÆÒðž>Èå@~oµ'k9‘c,¤ž¤^z/`L&PœÑìÕŠP/J V`ˆåÎåu îjúë€_ž¦%&ÓEú±/ú}ÜÏòäyì™ ÆØ[rP€¼k¦ç“ô¢m 3Æ®ûQèÆ"µz?˜tg’&ü~ÿ¡3ºø>Ž$–ëIÈ—ÀTeÀeéÄÄHóqÌóÆôKýÎñAÆkÀF�À~¿?ϯJrV&Õ Ð€®A)Â/l °ª×1ßöG”D,Oýû¨ä’‰LœÔO\]% ‡$ ¿>,8ðèoôNUà‹éñ$‡20Áä~?Ÿó÷øÿ‘’‰ ¨_Ý7ucÙ>À†êžœÄ†@Û踈h,/ñãlºQ"åhòCš¤»Üý ÷ÝSf¥»Ÿaaòm|¸ÜÄ Ò›L[<l s u,=f˜ˆt£ÜCÌ–øßBÐsþn½ÃS“Ðb{HŸÇE¥I<ÑáSRdŠ9#̰*5s¼ä{¯4~n­¤|$z.×4èQÝN$@踜1Àà%âAé{žÏRDI‚¨eæZ•22&[Oâè­œo®‡K"v³˜b¢À¬½ÄX%Ò—<ËÏÿÀòÉ@Xbdt÷ôþv|À#sÑG2,iÅq“æª#綈œhn W ìŽ1ÈTB ²À`ªíÅúÞÏ¥íDaœx“n–-# ±•<kRbgÓóîÀðª�X4 Ó�tJ<¦Ö]•hjïgæ ãí}!P“<Ûƒ´[`6`ir¨€Ì›b Xrט]©Ê€Æ>š°FæÃ-‘ö¢2rºwmœ¬í©.nàXë3Çý}FR¨G‹pH\øù@I¬¿‰Î¸:-Ò-Œ©'èÍ—ä�ªÛ^ô˳’¥�ï/7­ÃyÍ/1´Úå^âü»ïCºXïPÏP¾“v]¨¯Ü±v&,Âÿ=g�×)…¹}À$ÏÊI¹%Ò^ÛhŸ«¬2èNpMLµÁß7/éý±6ÀëfÿÖÄ|»!‘‘µ†¤¡÷7ÇÛGÄYT Ç»f ?aŽ·Òuw‹D¤Ç"Óý�õI±™’K‘ÆquWò|áÒŸ|Ÿ71÷ Aê’­¼¿~׸`»ê<Äöß@zUº»;Óñ¦ˆÄXb7%HÇ6Æ(Ì�Úðò‘ˆô$ ùü–%#ïZý9RŸMõc,2q'À�¾K ­›årw3ê®Kð®‹t÷K¿wgl>y’¿÷耒¥ƒÛcjÓaændHYrF{b u‹Â¤wŒ3Â#£¬ò¨<ÿ4ÏÛºeѲD¢¯/¾‰û4ÿãíÄÈ:.«{Æ\“lž¡|\°=2ƒŒë¢Z#-'†°.Œ zL�);b½,îs]"³°:^¹R@,oŒËדgñ÷f¸?2Ç×ëú[lÿ¡×+Pô ¤ ?æ:—ýn1Œi@wS«³¢1oÊ4ü=î#TB½û™J*“Ë’)ZÐÁO™gi?‚çvçDäiH$R‘ã[ÚºoB’žÒ•÷¢Ä]»2Ìtë^P›<ÃXµ’ü¸ï¥[-UdŒ…ç´Ò“ÐŒ¿‹ü翃~SàŒ­wÙ®d Š (»ì€ct8’HzÚ€2!c �WŠ!F)Gž� Ú/% Š‰0ëÛs_”Swïçü HàŽô›é|áÏDf™?™†ñþµöKÔ@\wûê³ÉÀ¶Æõs�f|Þ�³,Ã"Ýߣ³„È�RC3�½K û ­×S0XJ`Æ�7½53‘¶ç§Ý}†D¤=%”XdÊ€Œh~m#û�¢a�Wšß÷¦Ý�'qHÝ¥ o‰´WÀbl2+¿XŒ²CH>™5ÝLþ<ÖGä>0àVÂ'µm#ÆËŒ0cŒ½Ò^‘‘¦ùh-Ÿ$1»ª”§•æ0•kƒßg`€õ¤Ëu2&XjŸ0bàý$;L¦Ÿ€ÉÄò<Ù»NïŸv?éΉtŸyóU®rþ¾>Cþ¡8Òû>s©D_•™3$½ç@ZG ÅKÀ@³;'Ò½ `âmyÇ?A~¯Šˆ´xÝÌ�«ÃR^{Sµ¼¡g£CÀ;´Wð59);«{)�b¯ˆÈW•&ß“OÛ-‰‡}ÆŽ¾7—� ]%€¦˜¦)�©ù±J!v�ÆÚ/P›¿`{š4Ý-ÑXb§Å¿N?’   $¥û1æ£ïésÉÊý$$ûãšû 0ÎDD`úë/¢t¢ØÃïíR‹û~¬oA.uçÀ`Oú\2ƺ©#mŸ/Ú°´Ÿ¥Þø{PÞ·K�†%ëžèJcýÎgßo7Dº3„ir¦Ñ0c©/åg)£vL&Ø0ÃÉgšçK~Wqÿ“8¶ò J VÀq\’‘À Gú“¥\” Ì@Ø´H(Öriý¾œž(1Êúƒؼ ¦Õ“è?Ìj9F˜mlðûÀöpæÚû”6‹=×MÉ—˜dAš’ýq[Û›éRéçÚ>—DD~ÿß[@2ñ·•Hü²é·ÍgLR1å÷%jƒåø—ÿâŸ/ÉËéôY½5pLiįË#°�„¹ô­òwø:Ââï§ÃïŒ!ÏßÊù·+¢D÷ÐãÆç^”"lïÊ=làŽC„@˜K%²¦º4ƃ^·"Ý ôd¤'gû6µúÉ`öm-—{jRÒQΊÈ}lôî#?Ï–ûº­ 1’ˆ¸.Ò}¬ž¥í=™±Þ¶¿z]¦É˜2öáÌÆÙ€EÃÀqùy»%"Çå.€°»½û‡$kž 1Âdàw—fÜ„'Šô§aÇÙÞø—þtfp±ž± fß½`ÀR’l!æÌ’�h©!+Dz8n†WJ½…çœÈ÷ÃmLÕƒ=y‚` å †´î–�Rè›b±PÜ0ˆ˜%/h>IR궨4çÉòü„1PÓ>4f@ü1ÀN€Éu¢}˜<¡^2fž…K™ 2½$3‡N„zXàuçÄ dï"ÿÅ�våÕ‡3¹(åuSDDPî¹dàõä’·Ãó å’z H%éÎî®xl¢S�´žÞO„B2�˜b€É‰`èçß›;™Êç1¾nŠ´åY0¿N |Ê\Œÿs"Ý»K¢Dž>ß\¬?°“�6N–û¢çã€,Iñu ‹-Åq­@„÷dú“3yÇþåónIº”ét’z5†FVȯ-•¡Õ-˜Þ±þü01ÓÞ·úœ”›âüA‘wä#‘¶ <—Ó"rGÞÁužôŽÛrÏ9…cÍÿd’FôûXO0sóÂÓ¯[È÷6Ú3÷™aÎ ûÇ'%2ÕÖ<žJ÷KÌ/�›k”oYáxñ¹¶ñõQ(÷]eL†r(°pBߨOXl¼»ì„2!ÛJîâyØ|C îl:&“òmû¼~çEò<pýp²�^×½|åqý*�^â÷‹þYüYtwÀô"t«Ì¬wÛ³ZŽö¡1¨×÷ÞæõŽÀ8Ú [éfö—é”8CwÅûS÷¦dG‰³""cš)SŒóx•f¼Û<ŠÂMäËöçwô– ÇŒTFù c0³‡Ï‡¿+e¬yl° üµ3ö¾)"&qÈšøÍTèhCF™žÍõ{Â�º¼®Ê ®šb챘&ÙÞ|Žˆ´÷*󽛥ã{œ%Ç£na±h}”ÖU’0O›Âį1b°º Àú=q%* ÄõÝËe½ÈzÇXxñú•9`ý<­+ß“äX$K;ã=»bÀÝŽ]U*û€/m¬ƒÛ3º?鮸™YC�˜îG0cB†Ù}RÓ1ë®o36¯:öù}í–ÄHVöÜè(—b€‰H÷s;œ1ÍÚ)q€ìçˆáô40s!3©ù@u/`ö úÁ¹oS¡ƒ�˜ˆˆ¬œab€ÎËT¤àßû¢@ÈZ»Mž1 LßYùÄZJÿþ,Rñy"âÒó|~ÂN‰t÷-½÷ic}�7¶ËÜDx.ŽÄ¸2©B2ªBù*+—»�atì^¬×år9ÌÚ™ïȯœg½ªôÝDytd†´v ,Ý?·ñ1MÏãêäknBîN‹È»°T U-gviì°Öc¨´["òJi§~7 ̹Wºý „PvƧÛé/c~F@IDc“ÉSòt‘F¼OIDîÏmŸ½§pý§B`×ÿõyŒ³û%FŸ1Èp̘fŒÝu€Kkÿ’e¥ýÜ= †¥+Ñî=ÀËÚ31¹B»¥÷~æ 2IÌ1yǯc\£9úIaxnÿyEêL4)Ì«Ÿàº ÎFÃ?ÎOs9ÛW x•çPÎ_–ç|’¥Kúj~ÛÛ8$ Åê7*G†ÒU�_)&Y÷²—Ÿ@Æ/Ó/2 Úñ¶ aÆ0Ì@Ø>ßO0ÍXO.NŠÈg;HÚo‰2_n‹FŸ·§r;Y?}w)v &]¨Ò„J5N»K©žÓŽ1ʼ?n‹ˆI 6J;>¥1È�ˆ~àõW¯ñN|œ´_ô=ú±`ZÎö6�©Ï ”åïD€„Ù|~5ÕÏ-÷Æœ‘ØnˆtSƒì?åy\où¤÷ô hó÷«eÀ¢HÚQz®½eÀ‰KaâñIÒŽé¾iŸDÆZ:|8À‚qbÏM€Ð8c‰ ² ˜õcYQò°Æò2n.¤5}Ñ[¯¯ˆô™åo”~FW`HU ¨´çó©Ÿ¿0 Ì¸è·÷qÿÕ²n0FÛк¦;ã±·×xÅðzÊ_Ÿ3u¦ ÄîœHw÷ÿÀGÀ¬ÇX,œd€=YÆ û™L3dÙ.cÀÔŸ”¿ ˜¥4À�û›Ç¼~ �;²¼Ùö'#ùŒI,ærüÝ¿ú¿ÿ-bˆývR‰Â~% \}]�8Q2‘©ûk;/’c‚…ã#’3Â"3í´d¦Ú­€1ÝÂu§%mÿ‡ÿïÿô_ÿ]i,tmC¤%¶"íJû€²^cbá×iï�»¬ù´3`†=〘n$!-ò–Ð † h÷M2ÐLòð¶çÇç™ÄáϽœøÕ<^MJñÎ3]÷ 6Û@_{1!>.Z>Ð6%Ö@õ€=CÄT5P¼mOw)ÄP¡Á‚R6/—ßfÐÐßi`vƒÇq‹a&¢‡ë"r¹x3ECKôôõãdH ž÷™1ƒarÒ€æîAçEÌ êËœ“g±y~¿ €—Ç1í3v}lO±˜#g´œ¼_úRG4(WƒáѤàŽæC*¯æNDïvœRˆEÇX#ð´n4DÑã|ÀiÑ\º/ž:9§À݇)ÆÌ‰î¹ã‹ScŠ=kíK Š€óýd ®Ƙ„çDóãíøKwìù·Ó1ߣgM-lœ#pu.Ý7ƒ|™RˆÚJïëlfÒ‡ñ”b`‰ÄFö~ÃÀþ6˜S/@x�ØË`t�#(1wä�š»â ¶ÓGl-?c ˜aýR‚ã u—Xü]pýér>�¶"AÂð,~¿®¾þ¯Ì'@8Ïœ�°ò¼œDûÜ–DäYy'Iž¾ w"³ÌÞÎÈÔ»‰ãäÉQL�n)bÏ9®º£€R{_™YÝóâL´³©þÏ™$ã ÜÎjgãª-uütKyGNŠ´¥!ÝÒÚí6b•Ä8àýï =Ùr쇓6ž‚a´-Hì–ÚrGÞ±ßÏ¡f7DÚûÊ| €éíÒN5‘¶6)BkÉ3;H)8"GÀ¯>ç¶d¦Ùu¹kã†R•Î,;-Ò=qî_ ¾7ŒU¶`wטIšO�¨˜´¨KM*ørOúSóou^ô‹–k“œ…*te±ÊÜÜÀõ!~—;1p9R¹‘9-Ê;)  ÷@{Q$3e ­sK$\yüôc‡Q2ñzjŸ;™¹b>ò=¾Uò•”Y7£á0ÈÄÆÙMm¥Ž”P¬ßO¦0Þî‚Q¥íp¼eŸóž~OéxrdÊL¯3ÈçDr€¹gõd–§ïel‡{CÑG$K;Ëàu)æk`¾1åX]¬ñ|Ž{EŒY„õ_VX`;¸Â@U"àºõÓCzîϑﷺDd…X`ã‹Jß²òg²ÊL×óg�Âñ«=£J–θ³8€[OT©$ Ÿ—¨CÆ ¾¢Œ°î²íîQÒPÏw?SYûv»%Ò½à1ÆTÁA÷팖ÃÊ%—+(kô“ŽS•Vt&bœ1¶²Ö×fAò]ÎJî(™'""w�Úb#HfXÙÿAÂçy¥ûbŒ²³"²ãÒƒ5Ö˜îÿ¾- TR'äÛxÎe{Î7 `‘˜[6× ”usùNwNTó†H÷¢ÇÎI’V…ae1Ç^´ù5<Ç%?ÆõÏàþc;8¬äWóŸ×XJ,yýwô÷Žðß@„¥£Ÿc†°+ã+Ô?!ÃËÄDÏ& lîõ’Ûz=LmdÅñ@`Ç ø÷c™ÅäÉÐTÞ`òb@|%K(CLsùTø¾ïƒyC ®Æ�Û7Àâ6�2i¯(Óª›I9æÌ0eòP¢ð0­S> ÿG9’ô£Gb~¿€wߤâ#­siþñX±ÿYζÑþëf!V”ˆÈg’a_8Ì Û ?øü' “ì»+,W!†X’^œéÄ1(3Ð|Üð¾bx&P¥NÆ£‚‚ !W¤ ÃHùó8ÿtŸ) Ö¾ Åô¨üð¾ ëÌNcŒk=©3ôW’téKŒ‡Ï›ic¿³ÁqÀJ¯ÿª\¶šx93ÈÚÆ×43(Û¾'Ý’œß“ývKD~,¯`3`{„Á2&Y  JclŸ¯àïçݧ`:p¨ãô© ÌÒ÷ñœù)efáÀV-½~ûÔ~?)ÆÄQ Íaþ~?kl0Üÿ-—Íz_¨Dc·ßý8¿Ÿí{ÃR‰àõz+ÌyÃO1ÿ̳ôiΧ<§2†ìº®3”´{�@¦2×FòÉϳö£ š�Ä´ëëA¹Ÿ€cfåñò.ߟ€š¦™¹ú»1”FÇ­„ö‘~Œ1‰L¥#ÌWϽr`éAÊç”Y?°…‰–ÓØêÜD“ kŸ’ߥ’˘]¡¾@Q²<Ÿ©Æ"“R®^l³’ŽŽeçýa ±Rþ¡½ˆˆüþ¿9ö?ƒ!VÓöeÏ?n¾J¿+†Ú‘ù’!Öþn@L�±4EàK¤Ï;ß‹!–c‡Õç$ ìŒäXb9U€ìÏÒuÑÈsF2@–�±øÿõßI’ô0 }iïBÂðE2‹àIù4=. 4Y}LËÿ¶(�vND>¶‰C¯glcÞ÷ÕÅÆQ™hYbQDrí§%+ÎtÓçw—MZÄ 8"ÐÕ}$gNâ<™bdˆC �±M’<<î†<Òˆ”Jœ–û™tƒ¾²yª‹i5pTÃO–Êg{0fÄË0L\6i›lh)É=–˜-U’p ÃR˜g}ÃO/šÒuÃn†¥ …ÈûrÉûI" •<ϳÁdØÀu<Ä&ÉùŸAñÄÕ�¸u.ߎ‡˜[L7ñ÷li?Ü®‹Èû�¨îâþw °z€—š™á´’;96$²"sB5ø±\7PŽÓ¥o‰2b» `�Õ»ˆYCñ 7Hß±z+`¤å{�ô 5DWÉ3+côD)ÁlP—È´K†Y¦³è¿SxB6(¿ fÉ(u("'pKôv‰ý$ã‹�ó%ð@æMš7C:€¯u1LKå=‹üA倈¾¦÷àYQ õŽ|ˆß)9ø¡>7D±s"í0’ÞCì¯;ðØ_ÆniÌš a·Ác:Û¡-Cji€Á‡rçÏŠÆz; åò×ë¸eã÷%´Ï£j `ŒQ‡ò<uÇê%h=)§D™dú<šUŸÃ}0tR¤{幩ȕ`Ý{€½dýê'd IÈÿ4ƃ7Žë�� �IDAT¶«KAj9o§÷Ô™kýñ ã…@Üí(õ—æáúþ`©àIó5S}îtìãÿ¶H{QóíÞ ù~€ƒó¦&b?PÀH¾‰÷nƒb'"ÞVòMŒÏú>JŒ±Ö-Bl¥³ÓÆb¤ ¥x€Ü»a¾©€ó í*Æ( @ÙiŒ˜˜V˜Oò2êõ,JÇkêÀZéó_D?UIáU�ÆXöGþ9@§#à9s¬8…ßOã9"ÙA"K ö¿ßi€ç%»þ.YÞ²Ø^•±•}¦OÀPa†‘q× GWÌ?|·Î£<¹�xàHóRv¼9p‹ëиîÐ;ìÉ[é9Ñ‘(C¾.«ùЏä¯;Lé}o Âãìž1±ÈNQ n°=¥J(Öctä0`îë×™­¿5UéÅ,AhíÐQôôËç,ê}3®ß¡!\÷¹ûxö ¾Ï€“Št°»ÏòQ5À@1å ßoà÷!͈Ø`1F3.+ßY¹ýÑÓ¡>·Eä>ò5©BÖ“þ(…õýüvwZD>nIÁÃa%/€6:²Ý3CÎ¿Ê ðF‘–"@ôK‰‰±¬æBàå; Äô l5uçDäŠd""ÂkØGu/ªô¢Åô¸îîÛ>ë^yN6Ô(2 é§”{ؾ£1À¬­Á82¡ç.KZ~ˆ)Ö´ (pÑÒ\ëo¦òZì/uþœ£ ÒøÆËwÀŒ1iH�¥kH!Îåhƒè'�£´á9ÔC]™L:·iŒ®O;e¤ VWÈ•L«¾£ÏÐÆHÔ�Ï+ån†*£¦>§½"°ÊÀ&%íf" ÂïÆ@£t"fZ~H)@íäó&òa¹ßl7DÚwMêv)Xû®ÀËÌ&�‡ºûdjé1ú}#÷“”a®Äæ'HÚÙïf†—š¿(í6�ÝJ8tIEÖ“¿#Æ&cL1ÖKËÿj¶ä'`™#c‰p˜zÌ)%y>� õY{5J¶Å;:} ã«<6&Ô'#ïQ’BtéE$0ÑÚ«RcÚqÜþ®'ÔJæ[BG$E„ï•ÂЦIûJêÇ_toŠÈgòÆ ÓrPúñj‰ñg’Ý›¢Ò‰qœ~ÅꡇŸ‹Æâ:@ ³©ÅKýc�c‰½$o‹ÈAû…1ÙN#2QužºÔé>×vk_p Ò‘¡}¤Ž“A`ó�åýÒ†ûĘ”’+’‰&YùCÄ 3@„’Æ€³̵/pü„3»s" Œ›àÔp½2‚¾è2ÐÑù4ìöêõÿ?:`D�*3‹‚Äß”_/=aùæ˜Ó¾ä ®¬ÀV–ìµGO0K$�˜šŽJóõ$ `cLÑA Ë ˜‰¼_Ê[û‡ÉfÒAfêAŽÖÞÒcc†Õ~=è1óû!ÊñcÒõ™r¨ï%\×ÂÊóžW¹Þï2Ò¼¾_Þ¯Áuæï_;ö×òÇéÔïxjdŒ­G1ÐÆ¤k9sìopÝïXû‘ù/þùÿB@,Ç{t•àúú£bƒe�¬2ÂDÄ/¦aàk,å˜a§G€1<'¥�ˆmïïþ½üŸ"²³´i"²'«î¼ž—‰ˆÌdÑnˆÈëÎåè^Cuƒ»Àä»’­ˆÌe!½[µE§ÞU{#Ü?—‰LDd- †ïE>ú¼‰LÊsVÝTD¶¡Å〟Èõ˜áØ~i7Dd+[æ'Í?}°¶X$LDä˜$¿ÜtÓžýoQ<ÒØžZÒ9žÓ †œÄi¼>Üø­-ßUñìÒRÐãÐ͑̕òçó_õ¼!"“ÅK?à«GmTÙ)Ÿy§íþ:òëÁl4 Ñ/­Õ"]· Ñ»nÄç`mmï†\¨§~äu'ü~ϻ枌ê¡Ö´}·ÝFËTŽáÞ‡aüH·D;-õl·Ä¸’|>ôÔzË© ½nÓ-q•æ3CþÕGºƒö†æÓ½¦õáxmâžšLc°ç å³ñò„уq²‘€@ÿð>ó¡Úây“2žØ Z§¶Ôy¡[¶Y¡]–ß²›¢¢}S=½ýÒ{)Þ{6¼QJ0‘‰Ó|»}½Ïßʱ–FéÎcœ]GŸÏý̼۸Çäµna%É­·Âsñ»¿|.Ú¥ÿÞ<Ìõé^Ÿ¯¶¡Dý|›i­»…LÚu/w›É¶;/Òm,ß òÙâHÏoñ<›½ÜZÞ##¶¯×ÇG®öÇïžֳ2Ÿî¼H+õn#[üNɵ"šÖh8Ý ¿UßD¨×k>-muÛL&Ú¾Cm…û¶p Y`ZÉ1‘¶’I;ÐÒÄü½>"Úˆl1?Z´Y»Žû_Cë ãikå´yOÛ¥Û×û´ÛL BÝBË•Z,•(˜Lã{<é6í Ù¶™õË ”`Šö}ˆö,ïçë¶è—qkßÏ8¯Îp¼Áè›uí@DmŠïó1¶Gw^DfM[{ãµE½¢íü½?ã‡ø=¶OÃw?—¸Î¸žÏÕè¥æ,œßÄ/ÞÅïÚyB©*ܵ´ò¼!"+ÿnˆˆÈó!ßKé–x_ÅæÇ”ºešgœOe‹ûó|½…at"[û¾ãû¥ýçùSâ*}/pÞ+í·B»,lŸ²Utüu?Ú>3|ÿù]©·^‹åà¸Û`³Âùò“6Ãu›|ìãÞZ®ä/’ëU 7Ì?—wð] õØ–ç…|J?.XܽÂèÑë/â¹\Nº-òç{Xbºà ïücÁñ�ÄŠåMõ™#?—Jg9K=J{î0Î÷D˵“~Ò÷Ô÷±Âl­ýYÖéÞu=Ír-žçúè"®xymí}Þâ=æþcùoU÷=¸Z¿WÀLÙb¾[˪`±Ë€ê~{CDæØ7p°³zÛ:Š×³~ÝkÒŸÇf¨G86Ö hß©lEd+¶ÞHß;Y"ûÛMEd.:-dÙ®‹îމÈNð^ãú¾Ñ÷z“ïcm.¢=lÜÖÑdíìå8Îo­=—e1é2ƒ’‰û!í—ö¥+ä·¶}ï~»®ýÂòáx›Ê[Ó¶®ßp< ãä<Æ÷³çC¹çVJþ~ˆóúÜ«ÈoWò—‘ãòÝúÏÏëuXÿ ¸CæþŸ¡}7hÿ­LÑߌ)fëïÒ{€Ž¯uyówþýÄý‹Rú踿ˆ÷qƒòûÛÎ÷{QÞ;ŸOñ¥Ã|Êšsß‹ï³,@¸¶õ6Gèõš±Ö^‘n­ïIÛÓzw±Ös ¤ïó.Ì·ÇD߯‡áx§v’†qÒ­¥÷}D> ô;·ÈoÅñƒvXtçDæÅ°ní}gëðû^wN¤Ís¿vk¼1¿-Rþhÿ槇È'?ygߟÕ!Mð]Y$)°µïdqß¿ïáú]*×Z çÛÜój7Dºµå¯å½¤ÇÝZfȃö˜áù¾žþ>-ð<µ›íÁn†ã;Z¨ß—]7i—´¼ÝUí†ñÚ-´~m.;”ÏúÐÖñLøîb|­âwº]ÒïvwÕ¾ÛXêûÝæRöW�wÖø^pþØ…ñÀïi컊~A½­_š:L/Êz{eÇ!ß6—]w^¤[Ë^-Ê¥Ç;™ÂÎ)hÇÇwzÎÊüº±þ’Ô_3kßëéý´ù¥\âýÓytÏÚÇ¿§z¼Åø;Àý;ä]zE~ƒrüÎÿFªÁí®y>Ü¥uˆ¿½ ”cÕi—¼1ß6×|íüNæ¸oå-ß©=<—çwÝ×µ¹®g»µŒØ?ìé¬ßå˜k9l¿|žZ´¬»ì|]ŸÅ_Û%ì;açèsíBOáŽØOGåÏöH¿Ûóô÷PŸU¬u·5îŸ3›ÏÑ.ø;¯ížZq®íÚ­Ûª|oSÿÙ8¾êåC?í•viA'mÕíÚõð¼÷sj¿=Ì»—ààëóË¿Æ}Z¿½n‘~í훼¾íºÈÿsêÿ×î7"ð·ÇòÇ ¸z¬˜\áü?@;òþÇ�Ö•Ï—*_dˆ=> cL_1Á´© P�2äs¤dbº4vØéÀüþ¸ågzKdûÜîßw):ÍëÙ~ø l‹Ñ×7fúð`¬zß"Ü Ë›5>$"‡¾…Ñë*ÀÃß \˜è…çs#x R[ûpna˜tµg=?ÿxF€K¶°i7´ÝÆ 7%°Û&�†‡‹¸êõ‘>œËíCNã6DËC€k[ŸƒŠõeˇ�ˆÕò'CÓĴŹ¡à6Å Q¹À#†¢Y1\Õð ”M Ê;1©šôWIª#<w°ý&¸~ÖåqÊzW`mZËÇÙàˆ¿×�Ôl$Mp£õ_¢þËlð vÍ fH�q �E�®Ži>¼®, z¾ÃføM€ ?ŸåVƒtw`†è‡¢�Wb¤[ê1ëåÀQj0™Ð2 ¶p³öŒ-é ´CO<´ûßHçi°'ð²L .3,Ë1Öjû`×ûÀªA� –÷©,¼xvÚ§• ÆãLÇgƒa>0 ¨™qœv‹Ò¨+ß�\Zht˜àº}y(ÒV xt3$=")0c 6”üЏà ggòP¯o7€¹nøJ?÷�›¸`í6n íßõçsî¶Z>™ |¯!ÿ 0*�dž  à=IØC”+Œ÷6Ó÷ªÛ@KàÔ øÓ�¼-˜“I·¯Ž"hõyG[̼w33xD ÊÆ )Õ¬8¬ŸG€^»þ@D.�8»f-f€–Î7�â¶øNú|x¬�5X‡øï|ßQo®O&@n†ù¨:X¡Ÿf‹â0@`>ÎQ�øì{DCìùþ²˜ÀÑGûgV9ÇD¿Eä‚ÏŸ½è-% ¯G:*Â<@6¡+q ü†ˆ\ëpÛ?:_[;Kiè8aýU¾ï£ßYŸïÐjþe!’ x|¾Íƒî€Ã÷©<¯¶›=¿xš¯�2¿zÿàú‰÷mÍ@Æ~Ñâû˜{†üRÏžá1�÷zÌþbïp¼ÕõÚ¿Ëår�lU zL¹<¾~w`B×µ[ôÀVqŒÂ_:àÄï=æ-ÚY«-úw‚ó[u¾ec+SÛ'ذb5Ç•¸^¹ˆ÷]ÛÇ _\™¡3ܸ.öcѰ(PP‡øüY;5,MÃýœ—6bŽPîÐn6ƒ¤yÂÉ¥±ßAMKíW�Aœ7ô¼ödp™@¢íE)Ä©}ç‡�®¹T–p^Màîáx‰RpÛ¸Ù+ÇlwÁ}€™cœøy‰—Ð:ëÞüÄ÷aÆvb¹Óó§ê™#×];�Z{0×ufß±2öÇEÜ÷:FúEz}ÞZâ/÷ Ûºž,÷ÄK|G–Å‘pÇ}y;ÐöMóÖ%´Míg¿ßLô9ûhçj­ïû¾“`+ß_´Ù[ÝkÚj�¤§°Køw,g¥îˆõykYÆù¯[äïH[©á¿CyÛ\frL ‹(ßTŽ©a^÷ÎÔïlÞéóÍI7¥Y.O·qGÛ:ÔR¹]Êo e>ÂLT)nôK·³ÓÁïVcŒ“EÉo‘ì4»Þõ^æ~¿0¶v²¹oÞ[ßH?_+ç%”ójn¯¿­óxÌr¥ñ²ìJ:ï÷DÊ ´Ã¿ù¾½TõPeýhÀ<ÆÓãiÀgŠ~\ò{„þÑ}꺮wì÷%ú/;fyy@¯z߃7ÐoÈJ�Ííw=�]Ñ�OœÇva|M`˜æÑ6×y£[ë{Éy·­€‚Ù·F д,í¼Í—z}½Ž@,ów"ÀùT¾ƒ0i}ö%íƒÅÑà@áùTþ])¿öA# W÷ÛìÆÖÀ”æo»úz¸Q Ìú7Ná}NýÜ­‹`Ïñüâ(ÐV9?ÝÏ:Ù³ÿ�¡‹C«ë©b÷0‡a{®–n·s¸®qEï‡ d­ fí Àu ŽÉa<ë¡FE7=Â÷_íˆ>Nl¶Híß­Gòg¾;ðlw` ýU�>+çÈò Ž›=ØvýþVýÞ?þ¹*ò{ìˆå¾sÀëÿ/‰ÂÇ}ΗÜÆb™·ÿþ¶2ÄþÙ—ªR”Nü:€­_‘ �/¦z¾a•!6œ*ð¥éVï÷zÞS}®þÕò8ð²Á‡o‚Ú~Ë Bz® ÿbAÈé@ŽÜxÑCu?y¬ô=ïÉ£ê¢}xWé>_ðØÐò¹a„ŒÖJ?À[+ç„@XZm|a àkR’¹•|úâÆxSŽ �e©ž^ï/ÀÊq6MÎËõuÃÂþ¹BC þÎ `4ï3ÃÒ‚@˜rœÁÕnˆÈbdî%÷üF«PÂhÁV³††2½nU œ›¦Y[¬O·H•‰‚K"°à�C*‡—wY²4`ÐÀÑ’žñ48¢~Ëê‘…ú/S;ÓóÜ<Ð;ÛÖ¡ß`hFÐkcJøÆQ …0ƒÜ’�Tˆ½¶Ÿb ÍeJƹ"âÌ2qÆ¥¢º©1Ô@¼MÌ…k’7ºÑýX(S` ôFÒk^kq&C\Lh؇ÿ�ÇÇÀÜ1óyœ×TÞ)5pp!Ä¿\�ùøaûÛB_ uôÌu]/‡dêÉD7Îf`'ð4Â&XØø.ïŸ1]Âï½|mƒÇĘE“:nXnI¼ÿ;@ 1^Âû3¸ñ…ÌÀó+¸Î¿;É“00Y_c EÚ,,^‹å´…ᡎ�ÂlÁÚ#”wÒMõ:0ÕŒyeùOPÔu0¸€qåKKz?ËÛÁÜK×nƒàŒ�ž3[0c{;Ó/92Ftô÷VË×V4”x¹ C0•ÿ€,cÐy?ç÷£¿ Ïí LjknÀtÌ€ªV�ú»©ˆÌ�„hãüNé@ÏL*lŽìßcœ_Pª¥'f™PHt"“iÒŠÁ¯3`©½!Î<6Ç>ÏúI™o3:8„IÂ6¶^ÉÌÍà¸`ó:ÏLãsF M™éæpsDaÎÏ�êÔ±Ã2cšù±<tøÀs/XîF.ë¶ÆÌ×6žÆëñ^„uG~NøŽODdAf8¯7ÿîE€ò‚a¬[5¼ÁagÁgäòÈ`Jf•=—Ž ÃŽTÍDéo}^eØKuüj¶þÍCZÀp †[·›#S„|ýÎv¥!~‚ül¤¥uÕB¤¬»{@Xš8N®YœOl?‘Öé3‘A†+óÝš¢ÅÊu3#c¤ô#Cƾáµ�£Zì/”2ŠçöíY“Œ Ì‹ˆ&éª×Æ ƒ¢@~‡Óºn":™yÝ ¤[ûÈJ@ØEq÷ȸÝ@VKy (sk�ÓÒòH–�šØ^{8ÞÈR€çŠ_zÝ·fpËŒ4߇`ÃвIå™÷âVx¾ž¿Üªì¸ü哬½‘Oý˜™o‹ @¦rH¯ý5ù>…ã óIåœõvËt4�ì±5Ãxàõ»4>8ÒÖ²gŽ«S¹*Ü÷ù|]°h¸Ÿ�sæÅ>ž6)Ì+gp²ÑཱùLÛóu”{Èq"{ØØ²|/t?V˜0ÝÂŽ˜ÚS  [Ø{¸„}ÏÖל§ŠtW1î©Dh»$4”:�S˜>q½Ò�°€E>¯ÃMã ÍŒ Dà=9�´ ò”ŒôöÚÃs˜øf¸rÆÄ9‘"ÌkzUÿ»S0ÀËß»¢ÐCÀMŠ¢N0Ü@¢á^™U++Q1—çy;§ïK�ìÈ€›•똲›¦ŸÆt°ï 2úæÃë�Ž¢ïG[…|o0€6+76*2qÇ`@6\â,Ÿ­D�G�èòý\àq‰\h?ÑuõÀñžam.ÕîÄrìÉCQfX˜Çº«Þ‚dìTæOÙw­;ByÌÿ ¿s,Ãïd„³LfÉ¿ ëø£Ó2}ÏÈóq¼‡qÁRU ŒI¿s¿±ce0æ–Ø<hµ,¿gÆë•Õ_Pžô;ó ÉsØZ§#q� Ì¡E)Çž”¤€Ší§PÈù¦[;�…ï"ö€¬¦ó×¥°NNùöí˜ñ;KFÚPÊßÝÖSÐò@6%c*ÿN�‘õ5�sM ,}·Y¿�ü0¶ŒI†üv¹Ÿ °·§Ç^>Û]rü¯ëz½hóìad6¦ú9àØ`³~ç8 c,å¿' à’Ý Y®‹ãé\¢ÒßÇÂh‰Mò8÷…çÔ|ÆÒŸ<ÎyJ*Ê8€öXçÍ#�ö«rÜc~×ãLDR̰#S´N�ddI¸îq$»ÿQD¤hM:ƒÇóðÒ …yZ"72VuËPn&}<%ƒ²mÜâÒaVŽ7¿‹DÃ9?ïÕ#–dnÌuãJÕ>-§°�‘9´ÃýÃR™€Â-®›Œ-�+SŠŒ®HÅlÜ“q“™]æLãaI…Q*ratõùQù 8”XróÄâÈ|{õvvòžƒ0úmP"1H% C–v€é7Èìr¦ s0ì]sC`è}—ì¡atÛ–‰™c€Zߣ¾xˆ«aÖ$!…EFØâKÉ09k ÀM`ØÝ€€¨ÌTâIéÌ´ž„Ô4´‡Iø‰®(áU‚vZ([€™Aƒëœ§ôc•þšu&µU(¿›©Õ° †.J ªdÚùLJ?@ O&}ÆK‘té<èinãK·: Ž—èlÊ›ÏÛ¶C0Öܤ Û ”E·e?%d³¢ú†v›¶ªL+�=”ìóYÎÞh‘n“=PÛ Œ"YØ•íºH»@�ª.<+“®ÌCô8Þ:И áoß´ðx;¢‡vÃ÷ƒü Õ¶HÒ—Û£=ŒÚ,×Û¤&'�–ÂýUZ2õ+F,A—^ì3àP~H[fiI1©I{϶ȗ½X¤ƒšnð¶` MðÝßšƒ‚9"<SðêC†Î ãq<Ì#ÀdÀa³ïbfùû:èù,30É6¶1le<Q0I|8)ï5æ·Y[š#@SÆú˜ ÜG H‘E›&ƒ¿tS?1ŸÇïÐ"2ë¦jØ®Ìà�Tc-©ã›‚Reþ­ó¾?A€ª÷ýËõÉ«@2ž/ÀAB‚tpbüZé–,ý(¿gæ:Êwad½àßýäiS’P\¸ãNjÍò[DfšÖS© XÙêŽÏéÖ(oˆÈEÔcf¢Äl³ïv^W™¤—3ÈDDärU è`ÕÚ±}áØ†ßÒÒº¹Ç5)¸ @¹Ôض 5ía¿°ë)Ld©qæïß×UYϻا·\/¯¿GyýµÀz‘ë“¶³»ñ#„ëx[&G·*E)Ä˦¨Áù§J@q]A‰&ŠÂnÍS_Ä'îC.ÂPW׌8Ì]à&ÆŒ3)ÑZMÙÙ³ydÈ é1GŸ¡—øuiåŠÀÛëxîÖ ±ük3-P«ÂÄRƒÊek—"ÕT€)`} Î ò0(q½jì?2³ôþj H=æüýøŒ¸ê`D©ÇýG|Ÿ«aŒõ¤4²ÎÛn¨bsŸEÉ_:Œ, Ou>ˆ˜`>%ÆuÇY8.ŽºEYûw€ŽyEJ¹ëû¿p‡žžRF݇aýŒ}ÁÂÖ!•©¦íG†bn/–ÂK¹äs"0¤¿šæ7bgR~oHd¢ìÈKŒ+JÎe`‚_ê숰)À¤‰S×£ŽX °w›2ßS"q këǼ®´ë(n¨­ý¯2®¶CûãÀ,ã÷‚~cLÞ1ß>0”ïßUIßÈä²sýìP³©~²='0k× ;©’·ý„Ç{ïo6çáÌX[”ûh·3©ÄÈÌ ýbãË€°ðksWºõ¸-Pa|‚9ÉöÝÙïñõ‚ûâ.3ºÂóÈsW†ZoA{Làú·ì?l¦3F˜2Ö–PÖJ@ŽÅx•žãBÄÚ\ëß-¤ì“R e&ÜyÉŒG�{ «ÅïH` Í‡~ï•{7r¾/q›÷÷î S¤»é² ²h¨@ÛƒýTÇZÕ±–�Y–”ôrYOÆ6œC:јMÎÓkùõzcZYd2�J>ϘÄ!곋€ï€t¥IRB0µ{ß¾›^BFžowC뉶@»è1-׸Žû4£ý ø#CÌ%‡Úµöoì÷ü{n/eéÆÀ$ä]Æ,ùõ{ÿð¿ËU‘ß¿vìÿ@ ±ßJú°Y•i&#@Ö±Àu<–~'1Å(™8ÎûúÈñ¯Èô:;EäŒXì°ö§â@X8ÒŸõþ¾…¿gD`úW¿b†= SàÌË¥×s‚ç{ßVð!�iº ÈŒ-nŒ·’=Ã]2±.Äö¹qM¼?l‹A‘á,Ü'©<„1ñ÷ þÝZyÔ3Û7ÞñîŸ9jO°€!¶¥&¶ˆ¸§ {˜rme.Ѽí|•èá/dž@RmB醓¢c?²÷F Ú%·Ó“Ëa’¯§¤ Ç37ÌÃW‘2*†¯‰ fôÐÎ¥QwðГ a<ޤ�°NjNìuÞ/"ºœ‚„UôÐqCnÞ¸5n({@T’Ü‹6±ûÈSGö�s)‹»ŒÛò 0&Í@ �¥SŒÌ2�{¶T2÷˜ö¶ì=­™è÷e:¦¤#ë½ `—Ç‚\3à…Æþ9†ç–ïªÇq_’†1Eø½ò[á}¤A´3¯­²äWùp»¹Ã ÚN‹¼QA>0®“`ƒºÎ»�<LÂ_ï?dÌ.‰Œ -©tQÅ­dä€�� �IDAT°hå"U¡=y•‹I¼?å˜%™4¯k^®a i˜’öÔÄT!c£ä7 L‰À µÀ¬@erVP{˜Ÿ[Ë©íÆüBý fãã Ì=Jlj»XsÀ²wÿÆU�ÂJ«BzL6á{¶Aÿ:#ëµø×Ê•4ŒŸ6S`6Œ‹ ¾Ç2ì]!¡jGAj€`l'c`Ç3ïGJL¦…= ÒH*n¹G~#b8/ ê‰mà¦ç‡1‘²¡´ d`ž: »D.æaóˆ~Ê| ¹0ÛØŽ´ºi1dI‰+âŒâ™70?[,Êì˜áÏIŒ2Ʋ3Þ‚3zUâç7ÝA*Ô5Ë2>—Iš7´[YgXÌ¦Ä 7fP]PDú@XvÄqvÖëäKÇ–kf±µ0~ ø‡Ò€å;IëaA/ 0Î$•+œOß5%ÉI6²þ¡TçOzë;Ö'¯sæ`†­í<×ÃþÎPÃß̰ñrí†ý³JTG6~Ÿül{û  k ͪ@Á~Yô6öÊ„œ ZÌ ™fAp¤â{ŸÚæÁ0KfûÈü¸Œß'Ab¨�aÖ¹…=víõð ¥°v´X xü›‡|Â.Ú9–cÅõ_a,”}ZOá@&"r†ÀµTæ¹lL(ö'™áq>žùüÌu˜ód¤3bbqœƒÆV»,›tÿ¤âæRšì½ôÄßÙßE­Ré• 78.€W5 Ú})ÿµ9 f†“ïOÇ:2~aRŸ\G¤ûyÆý¨¤À~rRí—×]²²(d—E‚ñvµvŽ�pQä�¡I·§v$û)ïSªâ ¥Ï§ žÃ. ÂuÆ ï?N2&bÒ‰²u3©0÷Œ)c;J¼Yì$qé쩨Vð¬÷ïÊT’” 1Èõ~JCNÐHèñºÎ×v0‡±¼Ž1i¹=Û/Š—W¶Vþ…•¿HZ’,k}f,¿sIY'H,:Ðò1Ÿq Hç~J¸ŽR€»�Àäò80fÊà÷}gÀÚÆ¤'2Äs�<�rAšŽÀš9Tævù>ÒñÊßs|'ØB«²¤Da•Œ´˜aeý9A¿nËsè@Q°eºÛ™eS‹9©íLÀx*“ƒÿžøòh‘ÄÄy“x‹÷7·;2Ö—æqIc<2¡x_‰V|^ïîªÎwÝÒ‹ ulhóC‘×ç¿&5)%1~ #‰ã.nkÙ$€â7…!ü{¸ð÷Â=á»ëYDÚu‘vÉ‹Qº°…ïgýŽòº,q×»n§× Û»À×ËŽÉm¯we¨oW\‰Í·v?™bTRbì³c‹Œrà@5Ç}`ëí€ç³‚ŒäX_;ÀŽ– ܹ„cé/攀´ðWJ9¦%ô/ÀÜ~Ö®„1Ö›=߀°,Eړœ+ŠA‰±Øç†•òhÝÀˆ÷ÃBsô˜ohMÖëA™OǤd|��Âj¾•VÓ?5™Öò†ÃßGI*êu=†Xd„ Æ -Ò7äK$b)ÿáãÌü:ý™?*ßpÝöb!v˜·Vµ¤ŒQ…«V‰ÅÅtņæye1‹²'Á&4pL䀙bÉ#t†ûÆ?TÝ9YÙÆ9Ƕša±qÉnP‹§M] ®ð¼¤ ±@Ù‡¤Á ÇÜèזؤz‘IÆz¼^¤iX¸â†´ÎdÈ™ƒ ¶�f1&pQ5Œôc“Ñ€”¥ Ýàa ;^é:ï7–j8&¯£‰Ó™^-‡Ûbp ù×3=òcâ±OLâÏ&̧ܗŸÄX_4p®³lKÉ-äoŒ±®Ät©HD0¬NÀ £aðB;@} € ÃãÆcͰ„ƒî&U…rohÈ¥aÝm‰¡%R¥9žr~f€Ób˜±‚Tä¶és«T"Ÿ[Ø©jÌmz€?´Xaè×ë)0=“§W�€ÌÓ Ód€ç¸´X½XXi!ÔVj豟 ɸI†Øma CŒmáÑ¡ºs LŒÅö“&´ÿ–ö‰É`õ>ÒC,Ì`-ãf‚öq?Hóؾ^<vR‘ dò:�4I;›©ÜaIéÎPb;§z`¼6�¶Ýb�X•PŸÏ ëµk°%æ™p¼˜«Ï©ýV™T<ýóF¢ÍúRæiUû?Œ›63n‘q~‡ò¡ô¤1ý¶ˆçwóÍýÛv`œF†&c‰ÅLñºÙ�S蘸T%(yÿaL ‡èÏ(ôªã`‹ëò÷‡ŽÓ¼F Œ@ŒÝ•€±àÀù=2~]š-3ʬ8/S²±ÑmýT¤e§dôêw�× ´ ¶º²ïAboêsü8IRnÈ|Cý6j¼®‘!MÇŽ#SÌqÆÃ‰$Funo0}üî6k/X¹ÿ|œøÊED×YßTiQÜGÀÌtã z;s#Ÿ§cFb›”ÇL@ %#MxÆêwXÖ”ìËëÆ#æ-Jf+Z¯nŸ’‰É#^ ¶õò e@ß_;×Ã%’3S®ó¬Äø±³$”c&\Ž2ÆÓÖ…ëuž'dZb­ÌjÎxß‘I’p^½—²?Z †Ifìï!óξws&1è£Cæ_›¯µœSHE2-E$^ËR?;?¸n±T’D”H]TÀeZò[ÆuÀ�Sl)1qŸ³ö6ûmcOÐ4 ³˜1t<\oùxî1,Ǥ‹ÀÓß_·z™Ä™‚õ>H*fÉG3‹Ø!€æÇŒ½f’0� ±ÎÜ<âý¨ý±â\ê«Ö?{ ×òÅëa�/±“rŒ¤Øž`°ÈC-R,Y„ûªdjÏ �½ú~‰I‹®ûú²ÜÏ„|»ó Œáü@ÖAèBì¥i™ßê<µsÇî«@I)ï>¥ÅÓþmç1ÏÑÿ“ú=±þK ÅÁ$ÌÇØ·Wcw­QÞ݃z¿sé‘z©ÍÕîÒ­ÑUbc±ÀR ±ö6æDa†ÙVî_ Ö£J@îÆ¾÷Ö\—¬FÚ%åc1«<6ÝÊÆ-ËOLjÂ4âøµrf 71à µ­ö‘;LÜ€W,ã÷&äG©DZÛèpÁz ~ß[P—ÆS,Ö/¬Òø1øüšóµ‡R{ñ»Z6-Ƙ1³Š’tâž~'Ú%¬>‡b#jZ¢T”NÔ:^Òïa·6ÉÍ òYÖ‘Ö®‹ÈoЮ¿7ü=kû= Ìß =ŸbE‰X} <ôçßðr`Þc×çrÀhd$ˆ. ±¾´ª¤û¥ì#)8˘d{�¢vÙ½´[ô”NÒ“Úœ€SÙWÏMBñ�õ4©¿‘TcaÐEŒ«n7ÂP[%;€Âúœ>.3£b{¡=²äö¨"˜· 3ünýX$(Óóâ®h„ßKC ¾6ÀÅq´š®‡ö ±Õòï•èíÛý×ïýÃÿ†Ø_ƒ!Æ4&A¨¹Œ_éþûx}Y¦Ø°•®{ [Jdˆ} ÉÄ"…Ø“N´G§˜ad„%†XM¾�+9]b‡1‘ö8�YLþüoÈ‘íÝÿ…&qB·še “*Qf®ìI…åÀÖÄ4¼]l.ÆÄ±tÚ y~Õ£“ÀbI…/®O'×$7q;àÄ4”ùËV<6TÝxpA³Wƒ¢‹”„ ÈØ‘¾AÀÞL.ᑤYh±Ø³âI¥éJ1Ô\í"¡œd²­ ¾2ØBÿ£ýhžÛTCe•`J’Dý|zh>EŶÈ(É1:®• ~æå†Û•%ÎÐÌVn.®=\_ƒG—úwæ¡_ëoŒ(mèþO,—K!ê'~ÙÛF㌌�t£Ý-óF ž1+,ä”z"ƒšô"’™l[¯¿1&á¾I(ÿ’6Ÿ`ŒøýÉ󘱿ð"¦oH Ý‚˜Cyˆ Ù1c�‰(Cñ¡ˆl1®IN³F`=b£ÇÔ á,=*u_€gê57ppüˆˆ3,®—bËÑÓ[@(hÒnˆKý Hâi~d9@£ùÖØ[ZÿÝËÚMóù,%¨¾[m¦Œ&—âË P®õ Ȭod Yì±-F35Ètׂt$~OÇn.=Äñ6-ŒœoB ËËØ’:“MÈì«@“Õû�í8­ýcRŒqoœ›ËO€)ôwl ÔHËŽ4”¹ApTJ ÔseÌ/• íiŒð²q€q`l›¶[8Ê0?±…hŽí¸ÅFyâõNí1P~+yÀñÿM•ÚD;Í<¦ `¨•…´¿gù+O‡ƒ æ-G–Ù£èUÈu¿E¢0}÷ÜÜ¿ä<Šr-µ~�¶>ßóúø¾Ë¬; P` Ò±¸ž4˜ùt­|o¼µs¬´úÝñï×´xȱ€±-1ÃmÚ4åÇïÉ6�mÊåóÚ©s ]–p=NƱ,åà¦'ÍLàK|ÛŠÏ+ƒã902Ë÷?æj0ÈÂg‚d8¼`’‹Îx+Ò‡XÇì#ÌgV=¾ˆúö$GÆb· /” �—­#qCuhªë/Â<|K¶u=SÚˤa  ‰ë£ºÞÁ@¸×3ìX°ö*‘ž³172Ó ¨ÇѶ”“†u’ v[ž? €ïrL �í7¡ƒ còmÓu[Y‹µ)rs Ž>òÝbýrXœ+¶Å`g’‰IJœPäJè°€SŽÔ¹?Z�Hœ;#ìÈï›—<NR‹3�^©±n·0¨P:ÑŽiÐÃ1W¹ËÔþý~©RpùyÑ¡pX2j„Ùµ̯&¬ÿG GB åÑ`€•]¿ýXï"¡Éú¸áy’Úß$ÁØŠƒŽX5¦ï¶gʬ>ß»AÃ$%£a;¶/ µ”šÚõ¯+õÞ·ë´‡ 0‹O"ókh=rÑÚ—J!ËÐ*"Œ!ÖB•)LÛS  cì$®ôÞûƒmC=cI ÏLæ�J1„Þg”îa~Œ¶’T!¾‹‰9–û󉽇ÅÁ¨Úõ€ªl/9P"Si�‡h‡aÇz=Æa�œåw¶k_¢OÓ¾ˆH»¤íØùxe»3×9¦õˆýeí$D%‡FòeŒ>òÚH·0ý̱ñ:vxoœ™,°mPgˆ´¹K(Z=¢Åž9VìlZMQ¤…æÉøÊÀ qße›ÆWŠ!ûù{kU�¸bÿí íÈX_L3Îúù:�ÁÇpd ’ˆ32`<'mŸ*=Xò­  ô]iûÖv=¯+­º@{¬Ø‘ywóGJö8i+‘TŸ=o÷R/~§æCçÛ\χ~4)I�)ƒûÛPÚâðÛWtáýùù#|~á8b,0ÞÅú÷qêø+’•½òà•Ë_ì-…ñ>;.·Ãòñò­Ë8¬± ɤ˂;±Î©ŸVÿ=V¯rgí¿Þ¼ÛŸõ.ígweGö_¿÷ÿ%bŽ\IÃÇM¿ÉÂß"ýNïïb_ÿYQñKÄê"06ž_Ë@/J%:PögÆ�K•)&"ò§ò yKdû—»Ýý¥ˆPI¤j¿/ʆK7ŽuCKˆ3‘²%qŽ$%ö“„˜¸§ïGì 74eÏö}[Ðiž4|Ì(¡Â–VÏ£ˆró õ_`½gSdõ`ÝT±ôœ*5ãÏ-Ë”<¬1Ìa8¯†‹ ƒ¢“QÖá•£ô#ËÑ‘‹(ÑëÕ#šõ²˜1yyÍK—¥!‹ah[�.ç)äëzÏE¢AdâãbÐÐä1|)m#)ui£21)À ÉKc4(À¶ñÀ‘è Äcʘ!v‰zÀ“±;�£o™ú'Ʀà C@®~!mB©C©Ña&½š„ßCL TýVÞÄüŒ5ÜÏOé1<Ï[‰ºÑ>†ö}X™-IB‘Éú%x‚¤÷0Ä â<r^Ô^�/3ø‹ˆ\pó™…ã�“ˆÎnà¢à÷ ΃¹dïá¾<”»«ÍŒéú~çxàæÙ"1ÏØfØ À1¥ú`è'àSúßëA :-E2ì:1rlhà—1È`l! épbyA¢Àa:ÞÚLc>u×øü²� Œ¬ÌÄâx°RÙ ×ãIé™vAÛÉ€¿É@ðÖŒ¦[ж Ò„ª‘¾ËmÀ™6lÏ-ÇóÅóÝÖ‹ÉV™d=*Hd*ã°Ï4c¹’GáÆ e|®Å4Ä8µ§?,ã¦ìÇò×hëè‰ ‰äñ˜lu<§Äúl ˜A÷ Ö|�9¯…çÎy73ªqýCËGç¡©I NÄ22‡[íÌ»d0-s…mVØV JSZ¬Ÿh›á÷˜™gC 3�SøÕ˜Ù#=£N_}^?vgnŸà™N KH«²_·™%Â8‰�g`†%`€ws=±ðõǰc€*‹ej@X®wXÿ 3ÅúÏ!0¦å°ïC^¯P1&Lo]W˜ÿõ¹a]$âŒ6®/6:J™wað)Ù °«gm?¬»ŒõÀ¸eL7§S¢p›úmcçÖþ¯…ü/`Üñw®/˜bà ΅yØ—z å&dt÷ÓþX>ØW€™bz°ê=/´­DÑêì§ig#cŸ>h—UÝ×õú €¤Ÿâ½;(@%ê2ð=‡ÇÿZ¦diC8�„q ŽGSž‡”ו[{*߀ƒpßx²g<NŒ²+0À0¦„µ8O‰ÂlPÚáw7èÔþª£!à u¿|±�?}Ïýú}̼¦B¸ÿþ˜d¢1Ϙ?ÊÃýå&í·à–ê?C;n C7æ;:|,cì[¡£­˜Ä×ö2F7P›¡}™@Fœµ[láy/æâ ^vÁþ0ô{…MÝ11|ùÝ ¬¶Wö{3k§ë”=åŒ>m—K*Ø­}„˜Õ èqcK { l¶KfÈ”‘ù++ñ8°aðDo¾Šë>CÌ ó@B{õbA•rÓí*b¡9óÍ£°ûH`ʬF¾3û‰7’‚!šiNÉJÜ—$ -ðxÿˆR޶¨ïç÷¸s9VwešÅ²s~0Ñ·¹24»µD�´­´~˜H9ö€ÂX®Î¥éˆt€÷”i[¾º–(sÆ ´D?1ÿ´ëT¶¹]Mrò ôWX¤ï—ØïJÖ”24&Tü.˜jë΋IvëÀ%£/Ø‘B?OxŒ~Ø¢EÒÏRÊÚ%¡$ßÏOL!Jø…÷ÉZxhûÈçп—EZ±J2 ž“%C‹´©ìl=Àö]”öí9(àjJìkÎ{`Ší*v>q®€Ofø ´c ó>Ö™^–¿^,a•ÚDÿ-b9¬ý<­KûÌG€W;–#+òØ~{× ‘ýû0ÛÓvm—Zhª@à0P¦õi—4¿î*¿ŸÞ/ kùËó2CPzÖ§ì˜ë�ó®œGýû€`y^ûö eˆu;ÄÚ‘q`iq€² U¸ÇÈçHÉCJ"vÿÉÊ›Ž•Ï8 ö+üý§H#�`Á–8<-b±Ãb:]¤•ø\Yö ‘íýÝ¿îòÂ[Ms|¨qË…ÝëB‰/.¬=h05ñ…Gá Û}x<zPt5@¯hð1‰Ý ­ æDÑP8ƒ!9®HؘT£ä³DaݰÒ‡ü•kË'ÓÊÂɶ&Øø®¯{½P/âøu÷¼Eíl•–c 8ª ¤iŸÊTÃ×$qpõ!ó§äâØ;çï ”ÊÃ_c–OdqžÏñÄ5ç6ðüð¯—ÿî’z6{ö;°4M ÕI‰u"�# àŒU3ÏyÉbKLÄÃ^2”Brð( ªlÐ@;)¿Ð[™ä×$mt\"Š%öM·Ì>†r<|c#ÔŠÐG”^4�ËÆŸ–sf’‘Xâ÷ c)µ 0”¬WI“4)Ð/dÌ©!þ&ƶæëHÅ"DŸ Ò‰ íØÅyŒ’'i¼ Hôˆ3bCÝzR†ÑP>°4â)ÝVÎppHF¥ ¬Tà…µ#0Pò/Ò=®„:#¥�„UjÀ=Z“g³‚q(" ÅU¤bQ>g®¥žÓòDƒ½,0Úª”G&ßp»÷aŒ‰FЀô#ûYGŒl ¼Åö"É…¤—“êî&I×óÀcmоàkï â6KKäIy+-f•ô<©õ»àÌÞ—Ö7$Vi¤˜"sõ<Æcöp^™†öe}`‰-ï´7Ÿ�øI’´Î`[¦ù#š`hO†µ‰ÍãS´?b:B2q¾?LV‘¦�Ô|Ç(õ[Ks`Àóƒ’�È&<×�ÜðíÀïí ; H)ò;Ï‹äïjð4o½œ˜Ç´<‚c‹ˆÇœu(© ª>÷çõ”I ’I¶Jë…­Içcgö³ôGz¬÷Î;ÀFûáí‘÷Õû# œ€»6â™_ÖŸ¾~äÌMÊhHùÐ�·î1�hÈ<¤òrZÀ1k˜QØ—šr鬭8c{‚}ÆïQšâÿ&)?J nSL¡maŠQZ-J{M,g Or¦í´üžûõ]aßDÓ -*Yn8 ÎË‘�c(‰H”È“N¶˜MØ×ÑÝ1‚f6_©ÉXI” Ì �—Öâ¸@옲.0fcF'©ë¾#ŲüÍL/±ë)éÇuyO’°\¯©JÒð·evU@)ðÄ%2Y¾ËÅ!òâÀøPiÁm14'?¥z1\‹g¾¤z1¦öÂgPŠT±Ó¼]’.ŠØ~_÷ÿ,ñ囕=Yâ‰v…«~>µµp½¼+_û* é×{¬²aÆcÍ:“Tç1ÚE¶ƒ�Ú¥Û)@Øö$I)v;3„sý“b·¹ÝAÚoL7„¿&Ê#@ʤêzvŽ8_FÙŒ€Iù~pŸÁõªˆ•9¦Rˆ ¿;|Oêø­@SN»¾ýå£Ü€OpL†Xþ®2–—KÐñ>‰ù‡äÑ»by ¬¬�…»â|Ý äÓ- €Z¡]åÈvŒ]oUZœ³C»¤Ïéê{°×cN[,:“è @w»¤ß¹8åñÒcÆYûd¦•Ù1Š% —¿ËÞzd�¸’=ß½õzq„ØÅóm®ïg·�srï«¿'ö})*Xl+!ƒ.Ç2˜_*dMä“§7moˆ´K²×½¦@obJ©ß ¦ä�_eÜŒ*…@J1I†ë èù~@Ôw\h— XؼLàÄtdeû@fPEÀ/:ö6$ÉFŽ®²ýøê)ŠÈøñ¸äŸ9   ©j} úõ-Ì'«t¢z¥Þˆ×–Lìϯö¥q•oµ~3à«ïp4è°ÊX\»Ú/¥^vå–€µ8žOb±ôO`€±=ØN±¢¤gw^ä×ïýã¿ öß~¦JL3r”똮#®?ò¾Ç=vd:‹€T;B"QðJ�Øàªýi�´4ý‡A ,2ÇÆbÕ4°‰(0¦çûËÝ 6æ‘™À4ˆÈ˜JÖÆ4[˜TˆÆÐÒ7b[�búÔ®wتWšb²²é.L¦¡Ýc¸éó$Ý{81ô”°XWøË ï�=Ö6ŒµÀëÒÆž ‰Š8ß2ðcÒ?uA‹ë&=ß^Œ-ÜU€0›pËsoßã×¹i41¸ú¸ÄÔšáù*ú’I“# 9¶Ýv€Žù$fXd‚‰b–Ì0f�—- }ARÏ€Ø×†ÇJ»Lõ€ ÅÑá±+&#)2y&4¸ £¦ÄräÚ-K{IöŒœˆK2 K¡x*p¼MùN`˜ˆ@šjæ—~é1–Ö¿TÉaôÐÏÇÐ.aÀ:fL²ôì1tš4™^lðz‘a)ŽÓÈ ‰Ì0ól-&“Ìlj+Æn RYºÚãJó5‰C2nPšMöØöhI-<&5— õØÀÂã»Íú€…1E Í­SÙ°=-žJ‡xÞµê1Øêóðv€æz�¢²gz4»“%œ€éÜ^mVÆ¡˜_yûÕ ÍÙ`á�¹å=2gú~uÖFú­2Ÿ·eÁ%‘¶ÆèĬU%{½ïo¦ŽÏUã(.^ã,Hwj¬5?·åºIÏð*qœÔ¯Ç$Ó÷Ĥ<'Èɦó¦õ^™Ä.b*8c±Ì f.ÖöKå²z>ó•3³SÌ1éÍ_Öœ·J¾nèÏyRƒú@W9†ßKŒ£›ŽÓžÁŽ5® &�é&I–¿Yº·7?“h_Œõûa’SLH)Ní9SqÉÇ ©÷yì³äpáÌÎ,UãÆê­WW)VžÇßÊ`w¤lHëÈ"!XFaqäÅó\/¾nÀÔ>rËÒÎ=É®G¬Ç˜¶ýùdX’Û°²„#™cÁ°_ ª\©ÂÌ«í°ƒâÃÖ/»`(TÀLÓE¬«7G0ctD¢Ýl¼V‘CçR¹¶#ã'p#ãë±I¨g�.£TV§U±Á�Å^}†w„¤iøïÕ/KÈŠICH•†¬iKÆ Ê·$C(1yœ»‘=‹!CǪi‘Â2‰¾b(¬Œ/¬KØÍñ{¤"ðR¾Ã:ó\.ŒµØŽdd÷üÝòú­Fò¡#ΤŽ3¹©E"}Oê1d%=¿¦ž¡†¬}´lÜÜ�� �IDATÇ!€»aÞ"S_‘’˜s„9„N‰J0C†cÑZÒöÞZ?&fƒPâr.;y(ʃ„á ùœÔvQƒóÅðK`f)™Q5Ö“Å(·ýó`ýéè«íGÇáŽk;'n€Û¼Nb{rݶ—¾¿L;™&Æ•@XFúÅàÇ-™q¾àãýªÀÍ>˜E €Äõø¹tlÀ˜ÙÆ‘—Ò} �/ö.ýH†Ó~ª÷ÜÚEc ĺ Œ¡èØLÀÊê:Ð>¥äŒ)óãß™</›Ô)žOàΘx|>žsˆßýüV”!4IÀh]Æ`»ä�¨¼‰L¶ íìú€˜YER»0¢vΰ¬Lò0�(.©;ȳXq+5©w “†[F;]›÷4Ð+Žeþa,±Àvkqƒ|\19€fLLÜo±ÅÈ*R¹nWyýüP¤[ã–ÀDeZ/ù7:Ê„~`;Uiâ%€ ާìp!Áqe(ýÆ¥q]Z¥ ˆãõùªž£‚¶gZ�a»ì©ã-bs-Ê÷Ò~í’†ø`šB‚1§ ÙeûD€bësœa[\6†Èä-ÀdÌÇþf[wµåv¨ù"6W»ä�®·˜dÅ^`’Š=`c;T†Y¬G8êïʾ¹8XòûC‡ˆyrÔî=/—7Ì•9·G ÊØO {ât‰ÛÄP³˜r œ:cSDbL”LÔ\þÓcRrÔu¿-@õ¨|£<_ŠÁ–±ëˆ!64}I¦XÄDÄcL'µøgˆ!&£€Ø£�²£~ÿSÄûow,# ÔÄʘ$bšÁFpj‘l±DÉIOj+Jylñš-¦‹À<SÓŒùÐ@B)ŸI¯<¾a×…Å*Iì!Rºá!<^s~¡’!€@VØøào RYcUÀÐP7¦“69ÚÀãçÇ[”H‘×{1&Ð^dpõ% Kû<†Ÿ ?.AtˆöTàpcQkVcåÅÙ„ †cø Š^9³¡”xΣañ¡€Ç ë(×�¢zBm»HÕ¨ç Å®P& Dˆ´©›ò4>·�¢v>=wU ¾Å°JF ¸,÷&¼ßQúËá5pXÌ™n™ ë4D6]¸RÚ¥³5Hp Æ&™™‡ý’’^ìUj±•¬}­åñ˜9½¾3p8xl)}Úçg8?Ay`~*÷y¹f6ßÕj’\ë52•®ÛŠKÚ1ÆÕ¶Ôw2  µ™ÁÀÐm�ȵ°U…”`{#UÆpb{x?h{bãÒÔ*ðJæSš%øB 4c¤Q2ÓëSk8%Àm<}ÿ(A)`¢�®¼–ƒ'©ÀÌ#ð¥G=ŸúxI±ß²áXÚ-Þ÷n€y;2~Ãq˜§ù¶ ’cÉ H‘¢_WCõ‹1'ȼì1çD‚$¨½þFÆf”ôTfi��n‚Ç6%TCÌ<c…ñÔûŽ)k‘Úi ÝKÒˆ[“våw¨ÄÃ÷€ó}ÀXß­,‘ÉÞv¦Yö`·qIÇŠ« ÌVfvµÇ2;ˆçY2¢“,9fáåÏ/̼>âzÑ"¦ù»ŠïÌÌ™sƲd0žwùð»k‚ØÖŸÖsÇŸÆy„|œMšÅZ_ÿ ¸ JCn pÖ“ m渕¥ ý÷Ü~ôú×֣۬Ćê3“EDæÈgíR©.÷�À#—[ˆæ†u“Oí&2ìà4dدR‚1í 0µç†ª"Mž÷Ñ¡)Ž·æèQË™o3¬ã7ÎDI °m)gˆ \úÙpÁ`iÏÛÚ¾bkû€Òc1]MK=ãÝ!@ Áö*±ž+ Xc®äó[0X&âŽ^Ú·Î�Õúq}j†þ l¡«Á•åœ&€„õÛb>§áfÚEZ{™ã­îWÝ ™}ÛÕz^ÆZ¦§ö´´ÓpºéU;¦¢È~úÎÀª€û9ÿ+ø{¹÷$îŸÍñ³^�üž$Ûàú#0ÈÒõëÈ x8αS/¢=7½"Ëú\´7™dY‚w.i®¤ÔödÆñ &T’¬1àŒù¬Ð®RgÊ@»ˆë7rÇBsÐèÍñ;ëˆÛ*‘J°Õ72äú AcŒi)"Òæú·Æô Òrö>t¯©ÁÌOÏ�2,¶Süž‹Ti½EÙÿ™A{d_ë¼Á÷©b3ÀFÙ@þ‚úf Â81oŠˆÇæZ÷Ë•ì.;{߯$ S HN<ÆÑÏÙƒ´ã -(ó»@fŒ¹Äßã:ÇžÜÀéÆpùØÀ}<‡‘}býGP=àÃË5…ä¡®‰0’¯Hœç³-*70‹;:Äï‚Ä֋Œ<Úßfßñ¹"B�˜¶ÃÞ‚´Ç Þƒ9ÛÇæ™"‘[òWÑý¥ ¯– ;Æ‚¤!A¬] `±d?@@UŒ…ÆùÖäçS~™ö›\¯¡ö` /ǰgÌ‘‰Æòe;Å�Uà"ðb�Ÿ�m=¨Œä_€­yÞà�“€Å~±ëbs¥7¦2µKí1óáØ`A09Ñ/I öcv%&ßzø{ßæPú¹jã +HJ^²ñ¼‡§ïÈ Dª1ÄÆˆ#.€áêÔŽ5öW`xYì6Ö¿X›çûY£Ì_ÿ�Äöz€˜ÖæÑÒˆ_V*qLêðQ ²/õœÇ`ž™ˆý3”àu¦?N‡�° d‘&Ç#ì?<63LÓ7äŒd&˜kù½\Êlûÿhûòxɪêêu»ë>G@�eR‘(TpŠÆ q¢éὪ®ª®ª×ý Eã�ŽŒÄ eP Èà€€QM$Œ¯ª¹ßg¯}öÞ÷V¿FýÎïG?ªêÞsÏtϰ×^kç  QzÐ¥´@Ü8: Òýõש Y%lþãü—ôZ,7%õ\ㆠH‘ÐÓ±Ô`ðùÉ9MÙÓÌZƒú$Hú|ë�X-·ó´¥¡" ÄÓY<s;„ÑóM{«ê†çI¢AFñÒñô]bIÐp“=³”V`äu._ŽÄÀ«@X @ÃjèÛaJþ¼¾Ìíê 6²À´k6ÿé!€0•ÄêQšÐµkL ÔÐP®ÃdX¥ãHbQ#xKi(‘vÒöËL�¾?®_ÉÎ,é¡/V€=4¬FÎ ¤ÒŠärì$•b\™®sc�¥£–_úC¥ÊFÒ.¥)·•6Ja™4ÖŽ~ï%ÅP¼t•Ì`KcF˜6ñØÿU Ì„Ëlú÷2 Ä�$³–2·†Êô²Ï01 ø)Ë›=•¢‡].S®Gµ å.%Î8Ô—m½Jë?²¹€ŒÐ2J+²xó8ZBïOí.L%XÕ,ÇQ�¾¢bÏW.1È"ðT-x�Ëð.¼A¡¤‘Æöƒ«7¯Ì®t¥q^-¤~¨ëÉ6ø~Œr¹Ü6¹çÈcý|ä©\a åºN&ÆU$!UòQ€.JJFAœU PU&]—v<Ðp¹Â¼=ã <Õ€0&‘ltZÞl ?Õ‚©Kj¯¯3Ë2°àÝÙa‹@ѯ†®ýÈ`\¨fãx*–rlF750Å£Á˽ß5}mO]3ŽOFãŽXÔùû‰Htè±óCY¨¯Ä¸ìž°e=RÇŸ#¾çºŽZÖ%a¾�Ä÷}yÿFÇ Ø,^`ïi»ùƒ©î=‰!×SÆ�,d ¬QÊx•8^µ5Vå8îg\â¾§?%fXÞeIÐ-í[+R×îÓŒ =eêeæ»+÷AÆlÕýì(Óçu´¾d(¥4¨3#¦­×wÏËû.¾ÙcŒeÐùP^ÝÏÇ}[(ü%¦ó€W&PCžã9!JHSbÝíKòþn¨ï——HËŒ˜1ó,8°¨rEú×ï;xÈ 2w8NKRxŒEâ$¥rL±nôÄWÔ äÖcÿNdþlÃ\2¤ÎKíúa^æx뫱,×�t”á3"0ÆRV+¤Sù{®;šÏ+0“zMYçd¿EF.¥G{”.ÔýËF󜺀QŒÓrLúu²Y«@“JmÉß(9è a&–XTdÏ̳\ ØXƒËÉ×ëÆõž÷麑žLAš‘)·“*”H}ÚÒ $Æòœž�Ð=é|"²@X[K¸ßÉ6î²Ò^Q”¡ƒ]Ûí[:^û"í }e–I}É0“r—°u1°Ãè¦ï™Ý_dÂRÿ•ÿ¸\=߀2èìØi¥v(Z&†S*÷(†„°ïµ>õg5 ¬›bwäý܉þ¯_ŠN’V-:ÚÎcíçÄ�›õëeš§:³ô½2‹“€¢¯’“)@O\¯sŒ&ˆXäL0o¢¢£öŒ(ÙÏ™k,2ÆÓa}M‚P™4Œñ{¾aÎ>b˜7r*�eyüž×¸õÜ0Ú„±d”tÝz‘ד(MØu�X£KO'U}þâ~|Äz›€ª«zž À™~=ù¶Gæ“]Ÿ‹~^(*Ò“üÌ’3Êwààû”×?¯už. 0”GTŽq—JÓŠ’‹ÚQ)+Ìýj.ar}tÝœ&Q¯ÉÆT ”ùU“„@�JËï“kŒ0Ι)·Àrɧ§ÏËLKïøa¸Â� óº’ËnÖ³†Ø^p@XG¬Eë…ÑÅõ „¹ú‘ÙStˆä$@™J ZGK2¬ª�j õDS¾ 0å|ØnÚ:Í «�¶(á¨å×Y¾ýònÖ­ï-=/Ì€n`íA@ íC˜-KV)IS ‰öÖ‘¿ Ž#ÇH³L8>?¾—Qú1vj'#�Z ­$gngÞŸË#€ª“ì$0`w'ü,XE@©xÖT©DÇ(3ßOK_ÙÒç­^Übâ}Óž¿µå\Vc€ñóaF ñt�AqjÁΆ“(lŒæ­3Ý÷‡ë'J%U¦1ÅðuVãugã¬�ÄI½2Ãm¬‘[‰Ô žGr�Òœ†C1!›<úÒ†2oH(¹ ¿[ȳ'G?Îà6¸ü¾”äXòÉ’az�¯yZ¦J-˜,� ¥@™…&ò}½Ï3ÁÆyã$ô`b… 48¶”Óõôè•û6TôhTÉÂèá<|gÃ_e´8D™&Ÿ¯x"·C¬&¦BLŒ¡|^À«.ñE¿9ˆZ™b†#ã/ôÇ—ïVÌ{é þØñµ"R›ò}¿9ô×OøŸŸ_ØþÌá߬¾eöã Ï9âðßôeàÀo>}çcf€7\üÆÏÌÞ œò‡Sûè*à¢.úÇ‹ܵì®ï:Àº^AE A€BÒïc5xö4V”�dÊ2fÄ«ü0*Å`Z · �HÊO™o̦ÊdÛ)íïŒõ%)Ž•A—�J»éBJ CÆ$ °©hV@e&÷Ñ.Úd†Ù YÑgÌ#úˆS :ÂûµàžÅHÌ÷4äË}:Äà˜¦žcs„xÀ!?W™/óÜ̱ÿQÑ�NíyOpÿE?xS»hëv)¹&ÏæÑ4É>)s›ãÎ0Gb?¤ë’Çó¸Ðñ' .ÞWC£¤/LÎb]º_%e<m}¾2œôó&[>]fNå˜Pn§ý¤wÕ�8)m’Æ\h`"·'b²™vç†ÓÃC}ˆ«@v#·´4“8†de$eÕ�•$½§%¥ÛR‘æºE$&¢IæZÌK|ð=ëŠA†13Ń^bŒ @_u J¸åqì Û·|¾¼_ ðó=Ã-„ï+ëÍ•j“) bP •ŽtZt•,K¾Gš´u>uí#óqö8÷Œ±Uðìíbä<ga�oxÖž¥c…üšb-9‰%ÙÍî{ãÀÁüR»ŠC׫®¼·˳©ô"JÒ¾m¬1èPÆcÁj±½£=•£- 92¤‡uƸ»i,ó49VÙ¾¶­¦ûž`øŒÎÌŒTøÄí[ÈÊŒ6¿?©Çʲ­ 3s—å¡"�`Àö–ëù}p@Õ Hm‡1¤YÜoÖ©<Ó.>Þ³}¶hEÝAMc±¹ýpKOå™è¾\ ƒ.Æ‚a5;îÍ: =ï+hØÓÐý_Þø>0“Úê>Œç‚ôÞÍËçh°÷û"öG)އæ´1U¶„i5B6²œ-yŸ:l ác2Ÿ¡)¿0óé-ó^×;ˆ¡s×7¼äg1h{ÏÍgÆÀ&íݓ麶�]mmOÿüüÜBŠ’]r7øeå“¶ÝŸ £’ŒS¥«å~(u”Æs4%‡¢´K†[8ŸR²õŠ@¡¼²2»1'IÕ �™1Tºñ4È£ô–+­ž•A‘ÏÕÚ_2nza\BkÏ~‰Çû먭€"`-0FC^f€õݺÄ~2À´ê˜’ˆú 0J¦ê+2²“=çÍac¿f3Û±çö ì«Iº‚æ¾¢e ¤sÉÀr&&DºN%ý„I–û×)Ðy7íZIÚ­êÊ|gc²”÷…E;Ûw‚¤ €¨�P´Åð8LŒÝª+1¸òúMé5Ó¹ˆœY¹Û1Áª†˜™®Ý[þ{+M×)‰M’‰&&ÏÄþ^­×ÏsÁîBÃo×~¶åRæ£HjŒPcê˜X^Ú?a¤eÃ~™ÛŶdàµàñíŸ üñ9C·š¤}ZÑ—˜–” lÕæo•¼)AÇC�ŠÍ¬Ü“üÓ~ß–’vîo…±…EiOûÞ‰>:îç‘‘ž(íÞåõleŠàK˱Ë ƒH[zÛ‰~n‡__ïT*‘yQ*®«R¾F&–ù‚<ÞÔE¯Ø`sfˆþ”EÝ)çIïˆÛ QÆOŒÈ« è “¬ˆL4øëõ+€b5~o…r8É>#É™Wf˜çµ2ðæsK $2Ž °ÃÙ±C§0±ò¾‰÷[†Ÿ‘¨œÂ0óÀ™[@dÔ…úÖR-v—Z®œ”dléüÚ5ŸÃ<C‹�“jžéÖÊö1yÀ°4NjR––?H"ªÌåjž#Ïuû=•¾Ãu2_ºaˆ"Pd˜ZL_‘ï¿Òtÿ´ë—J[`v-%‰øÜ­É'~?íºeÓ.~¿@˜‘D,„™å$}ÊŒ°¦_1#¿Ÿƒ­“L´±ÊÒß³CìlÂRê¨ôH7ü…“ÊÈRßxÆêQ”M{–!ÒQC³F]¢<5¸5=u!,M¾e6;ÃÏØx„ÒàÅú@þŠgI’ô«{™R§N³‡Q\€Tò&xWº.Çx˜u÷ñ÷¼€”NÚf]�†èIXFWØHåãTßZ*%™™îë#yÚÞÓŠõ\ˆ†”&’ëÛöh�”™X_Q2È=g•üm[f€õ$ŽFрϿûvÀŒôÄã<äŒ$¡HÂU+€o½ò[ϼà2àé7¾àæU�³§,ìø…3€³ÎùÆm?¾øÅßýïuw¼ ¸í¸»p÷û ~|Å-78åß?yÑwö^·ßÛû/û‹G¿ ÇH¨1ã§û1 `§’‹=•ÀcŒ9€«a‡Ö±ËäXýÂn*U•  ”²âótœÀ3'Hùe@"óyf�té‰_‘A'’d!–à´ÉàäØlú7k;ƒ‘ÝÌKŒ"HJe‚ñy‘$ £„�QYÍE»þžx`=1¹L$1'U¨õ™nI£�ÚJxðÈ’q#ªZ c+ÍÓEÛ!.†X?Žy„ÈRš‡€CUÛ(;iÂ2™`ù2ŠŠ¶n½3ÄH*`FS²~=µÏO¿kˆF›Ìƒ•ÆþÉG~. ð P¶N×+–ªç꓃ÞÐg żê)?>—ù‡|ÜÆW™!߃ uÓ€b]  8Z Íô;ûOÞ#ÃÌLO"C¬ ŒÉ:3W�ãô S‘@ߥ3$å^îºö·ÌH3ì_”2î6¥çÈчÊ2¼G¥óÏŒ¶yÌ -@™0©ÈÖñÜés}äërŒ?ŽúvÞ@[�´>fäÈÁùŠ€$ clõEeÖŠãÇ‘®í¸³©ãÀÀuԌɄÎë "JýžÒŸéM”Õƒïš\[�QÒ7¯›hÎ £ìˆ!€60íÁä°ˆdhé³}ë dW^>×�`”ÊÖý¢0×kô„¬ä£a('æ{ØéýÙ!ˆû­—¸¸ï ÑãÊBepÊíb˜årIî’ßûý]žD!`ª§8ûÏç/ådàû<*È×>Vmz˜4F•0×<#¯3Õƒ}8q@ƒ÷û5OùEs_[™jÀTê“ÜóR2JÂ<ìRjÚIvÚrm´ã@™`*Mîæ— ÊXë‹,cä‘ ×uç©üfÒ0ÙvÌL7"•>Zyþ¬t­Ôa[®ß Õ¹\ÎQ  ç qõäO©§žË‰qÄÄX‡=—ß0Ä£CJÖåC,`Y!*Œu”žÜÑü5’�3j6vL®œ< »^¥É�œ5¹¦ñä% ƒ$*ÈX#sªÓÐ(’_ÐU­Ð κ5MîúvÍ‘'µôjLMŽÑ” ƒŒ-ÍÆpžÆíP®†s¸qÁ€Ùu�à�³ÂƒÛ'eþR�c/µÚÊöΪ(c׃±� ]¹žã'ëô„!](jýÓ(¡¸FA³C�ŠŽÆ ËR\ X!@ã¤à©IA»ó-#”µ‚ƒ8T¼]Ƹ4ÆnÓc«%×ÿ±–?Š­E†pе°õƒÄr$3Ë2¯B*øôŒbÖ»ÕÌ3�–_o³”!™ok®±o;µuÇ1ÅíEVÂ0ر¦´S?'™çµ GÛ;ˆ0f›Ž#¹Œ†úC¬«�Ú&×¾ê .w—Õ\ÚÕ°]P˜€ûBJ"öäþ1'íɺËgÃ$› ÚÓ~Vß*ihÛ©%®F´&fÞpŠ1¹ß´8ox)b~±±äûj½®¿œWú2?9;ia7"ð.í%íÒ#CIêE< dæKÞ„ñ–Òr©Çò¼n ª£Ìu?Op˜Ñ“™k™™§í˜K:Ž„ñ¥’x�P¬!“§ÊÌWy‚gœ‘Y¦Ï!ƒ((K(£¨›ÿÍ¿g ¨"ÀØ’ÏÎ15áYòù¼º’H`jM"+ô“Ö;�kNj±¨ý¥yæiñ=Öò„ï[R]û³ß¸+Ö4Ç«`kL·xžŸXà´`H`y&dEÉÓ�,jùÁ~Ú§±U\¹˜¿Huòý¨ÙMˆþTÉAsߟ+l)iÅxÝWÂß?÷y�€eðbÚ2ðÕ˜–’2l¾ï¨ ‘Øœ7—ŠdIijÍgcé3™b”LìÊF¶¯3¦t�ñ±Æ:qŠtöè¤áE$74(¸[ððÞöŒ••0p¹a5áÓåùâQɃ­H.ø˜_œÐ5fLÐ̇L Ñ é �ÈÌÆS¥f4ˆ¸+_FNÏÖ°AÛæc.yÃAYö®-É;N4øz†¥2ׄžö'"fŒTÏ%†ÌØH÷G¦cC©¡×3ÃLl(Ô!|Ï\ÃÌ`“¿sd‚ùI} p•ò{»ÁÌÌ{` V'—pé—ï�÷¼UWŸöCüÉéMk_õº§~ ¸_羻߆<‘hô ÉB ~ΰ¹ 1æ ·…¤Þ—nénsŒ!ã 3¥aâi·î¤Ö·G”XÌåU)CØ¿ ”"a¿ž2 7è Ãg˜¥™Ä“?ÄSɾ®evéóÉÈÊ÷ Øj0$§ ·8›ƒ2È*E’mAßÐLŒ?ntL %­û‚)'cD¢/Æ~“z˜ò¨Ëö§Jª„£*ô=)9¤Øn™ ¤ž¬X¬V@#ïeÃråƒÿ–zLèi YàT$AMì©^*w¦r»Ò“H~_+�soWÌÏoŒÖå|…qåžèÆ*}k=‚¬ dG¸?Õ«Xg€i2&Gùþ¢“™“é€YÈÁÏîÕZ¹~].3Ü…T¬ÊÒVZ²9Ó¾%~ž#°—ud Zè‰ ß+¹/Üç-PS•Õœ%@Ù,J3š²¿n_˜.¨zfð™|SnôHå¸êG¦†Bê4„®0OÀ«è§ù§ê*–~_%ùæÝCš´Ô4ЫkGæzÄ+p%’‘¾=¤Ä ¬)ã&µÛª‚1*Gr¿2Å¡€R²W³ ˜-"C¶\!ŒæÜž=;ßiÌ­v d†¤¥Sª^8˜øÔ¦F–\ôÌzyŸVR~ÏÆÒ.ZY÷Dº®Ðüµ¦Þƒ©¤ãˆü:kž ³£ŒÚfUšç›çh¹“=ì[2³KGº\§Ðµ–?HI§væ],Wlh º& ‚R/y?P;0‡Ø¬pã¾®QBr ûX'T<ÈŒ2�NJ\êåc¹l1`ˆÏ#€Õ¿ À…q%£ÄÁ%2ÒÒŽp¼ã^~KtÇ(�lévìgÑ¥œŸÆÙ/H±ƒ¤»– %JƯ˱Ñ`è ÛP�!{¨Û}¥1c@G€žs,Ðg‰† [‘úI†ÎQ)çNFÎé½5’‰ÕJ$‡H t9ö®�r!1f™—HÌÏïiÙg\¾5&µ\— >t,ëúÄ}ÖDú£'2Œ‰p�� �IDAT‘³KùbMûEõð6QPã… °§¹‘d«ƒ².¥˜ö‘k‚åÉ£ÎaÑ ”cà¥üW‡çs”G%í2DfR¹9>Ø~².k¿èz²Ê`*ãù­åKãºï¾¸~ª4¢ÛW›ë3‘R—‘ql¥”e¼È|×–ý¬tžÉ†ûÐ(ï]O°̰ô<‚Š–[=�IêM€my3‘?Cg@7óehÝn˜'ó¼J%ž&¦/ÐØíÀ¬Úà碣€SK�þîË7Q<•{º ¨˜rTùý)ø @Äïgåsº?Œ#UèÖoc°îÈý­�,¶,ó˜÷›~j ‹Ž†àÈ#*¥q0½×bkùŒ”_E¦¤aøÉu)—2Ö„q¨ý*óÓ„Ìk‘ÞTéÆZorõ#¨deÕMëb‘÷§½�ðås”—:Í߀j}fŒ:)÷õZCº<÷œãGKÖÉIf¶`2}ø3Ž|Õ@óép¾†ØˆãPíìß™|?Œ½“JXk r?™MI¹e}ŒX¾ï"S¹ŸP”ÇCH}7?o΀L“ƒ¢‘bT©Ä°nNâ'W#Íí#*åheM2�âŸW4Æ0«²â2·¤~�Ð l½ø|2ÔŠN•;¦D×ãó³t_XÿàÔÏ€M“C1ëËù“°�2ÒƒS$}¬4;-J]¦k;lP5ögÜäÔ¤µvAw“)çÁ–¸rÌ0¶WÁñ«$›w@åb¼Ø3ù¹˜l¶?XËÕò°Þ{I@i)†îáïϽ‡ùlmyîijÌg¾$ÿwX‘bmY€,Æ;͈€J%òoc ±”ÌK%ž#�™e‚A>OÂNŸò7J#út¤þM¿'ÏŠ áªR'Pм(à#šÞ4„kðRgp¦tˆaþ(ªµ÷¬Œ=Ù,L4jòÈQ¿ L®îþ–x€RÒ%k<“Ñë•Ò@ž7ˆ±Àô¯08b<h¬0.Ûe0HÒc•A¶Yë”ÖOâhˆ1åHÏ †'¶¯ Ðñ9ª‚A„—è)nþŠ'1cL‹dCgàigF˜K&vY� µ?]}7@™¹"@߈ýŸ ‡1Ÿ±ÏïÎ}ïÜû®eÀü{7V'þìôŒ«žþœƒÞ cxȆøjζ«2-@›Æq– \D’˜#pe=–•˜`¨æ4Æäþ$iÙsÌ$ÕÊ/¢"ûk$Ç÷œ&æ˜ó¸ƒï*Pbˆ‚%Ù‰õuÒ"ø’áÔ–…Oczei3+ h™-üÖVFò€ƒg"}'6Á2žS*ÒÉè’–¨‹U‰)ÆçV{GÍ 1Zèoej…`½A*Öxp’!è6‹–µ ¨Öj¹ç„™Â f⹬ Ì­| ÕïÉÀr¿K9#€•ó†× _'’}ÒÜz:~ÍÑ0òzñ/0çɆª7š@èX.~Õ\¶’ç'¦–z:*0¡­¯õŠŒËTÿüœTïŠðÏ k×®”ÒHœÒ.k3Ðç%!£ô^mƒÉcè\0ô+ÓãÅmxKŽdX/ú xuR”¦ß²g˜\·€6 ÅuÌ1èPåX^òÈ,°.«¡Þ'ïI:¨H}Æi?¢ï;ç“Ò�_ ê:¦fžsŒ§MHR‰Ùëçƒq�ž%f]þ^¤Ù‘@ýÂÕ¡!=o>xÖÏhŒ±•Èóªö“œ’ŽLÍÌ”±ÝD*ˆÇX�ª¡ä³PŒ\Œ3À3fÌúAIDÁɺ» °6¥+e}Óòp¿ö#9_ÆTã°Œ Rç‹y·?ã÷m™)L”Ìô"ªLóEß~Ú¯²p’ƒfÝ’§z�lh˜œÂsŽI1 §í{¢´´Ô#>w¬ J÷CW'^™[žÙEfˆ:0U4ÿˆ£œ|îȾ2ž#:(Ëã¬& >ç}ª7œ—®£t>¯äý?� uß>侇ç½S$Û‚oÖ=ׯ )ÍóJy¿:PGÂ`xöŽ}†9 ç%2­hhëRI#J ºò ÀKÏ[-Ž­ 䩿 ÏC„}Vî#•ÐJ¥î»ØP¸àó:ï 4&ŒJ*#L’Vú"±×àlˆÒº|_§I*�G¦Pj—ÌPjJö“Ö‡¶ü¥è¤ñ9t\Ì€—7T­ÑçûvÌíBÄPM¦X'f>áþù`jËuÞ&Jjõ5Ö™J[5Þt=/…Áè.[9v®œ ؾ „›RÿÚ}‘JÌJ6–•aŽñœ.ã§ëúÈÒŠ p"ðÆÓö%ÃL€t÷M=6Ô$ëœ:Ù¹ùb5ü¾¦#ý°AÖO�µ¿¦žÕ$=¯šèçã6׳¥€¹0§s-·\›} Yf™ªµZ±^#“[ÖÄ8‹ÂÁÆnÑR©Û‘7¤bMÀ–[ÇŠ¾–_%¸/‡MFbëEt¤¨1åЦÀ[�£PÔ˜c À@.5P›ôª9ù‹ã„¶`�v´?s»˜XY‘i×’ñCÀ–L;Í3t³û®j`‚<39Ö«”ñX”UÔA1:ÖÎøÏ¨å}äJóÙ2S‹\Æ1¿×v €—$ûdv±å9,? ë-1Jy:é8„ŒÔcÛžÁ‘2¬#ŽOŽ&{./:i½ªD*ÖÆ€ªÖÏüLá*šö4v˜Ö±§ß§r/¯Ïÿrýȯi±ÃÈ ›ÔcmJýúVúÐ0&rÿÀ3ˆø<µ_tšÎ±™A”aU´èùK!E Te©¾èh.™dM€ö-ãŒóD-ö.O,ˆL2µƒ¬À¬ÏýU QQPÚ°Š€džÉs´½ v¬ZŒ–m—Èøƒw2N[¨£@h“Ðnæç+Ó¯Årºßeœ©ÆëL‹“Áêb™åþ 1ãæðáP鹿«i¿@-Yü÷)Æ;l)¦Wc¬1óyk·Æûk¿ÿöûØöî'T¾$@ØaX"50È€y@ê¨ðùL æcù{`:SlZ²Œ0,røŽl’\Ÿ<9´:‰áD©nä½ç$ ³²×a2ƒ º�Ï Ð3xJžeÑdXéªTb:°úƒþ‚”o•hŽ/ä¹&+‘Ø’ˆ<¨Oò†‘’+²‘NŸ»²Q ZÔÖ³.j<æ—ÉcL¦fÆ„Ð_ÁP=‚iÐ`y¢^7îc9 §´¡ªnƒÄ3·´=ûÒ„Ÿ¾i‹Á¥”ç « -Y«o ГÖjŽ™‘ý)};è÷ư›€&~î¹ö¡ÁÊ0ÒêP¡\?|o¿ïýá’ç¯9ámzßK°dz×o:|ù€Çÿç>xÜ;¶½c§;Ÿ\ùë+/ùÑï€çûüÓÿæ3À½Ž½×kïm˜*nlXɬ!% ¡ÝINÕ=ËpH KÞ1ü‘RŠ¡uL‰F^™c!) 19܆yHÉI“HùYcöåó*Ò†ÂüàóhxÉ1·º�ªWº! ²Z™Ìrb@ 0Cíâ;Ž>= $ƒx2xÓ\YÊ=|| #‹çÝp}vf‚¶ç©±Ë—Çæ²èå £ƒL³ h§÷ªR¦!4‘•4‰�øH˜;õ~6’‚õûS¾Å*pzé ’ÆQ5 ³+ß§�™¬ƒaÑåkÚ50P|}òÆLfƒ¢ç7ÈrW=2AùûþÍùÛÏE§ÐŠ×Ïù„ñòOõ.Ä“¹RiÛÂ}ÏrÔÊ«Œ²\o,J>Á oÁ ð„ñ8�kŒ›µõ~^ÂÀ¨ CøÂõã)ó“…: ï÷8�À†)f™e™yF FMæú‘\ÙÀ¾Ëïy6LÙ tÑN@s5 «ÀXË͘W”œsåªÆ¦…Á«Ì° ùêæ5ÎW}™Oíì’ò)E‘¢mcÑ™`_¬IÁ¹A�\ÉÈy‡ ŽŒ¡ˆŽ!•“Ê*N& /¡H@ ;@ÔÖ'í#ÃËÇôf \þÙ<’˜?™AÍ™—ÿ‹°pë¹è™õªlß/™‡kÒ{@r䆘s¬±Ò,VÚÔÓí§ØÞ¬][öO\‡Ì>Ð}®`ýs‘ó×K»'XM�«¬5&”ÖæçS@�5mÓ”2#+%Ó�h°$0FG¹Õòû@=æ5ŸÀknIÞó«æýeº´<éüCFTºU¾^÷ù>¦UšÚ æ9ŠçU¨°Ð`GFô »<¸óÈX ¤ev´c9µß�—ò¨á|¨ó„7œŽõ\'Ï/6èÉEîG ²^â@Çm‘T?:(– üIë0†™ôgO¾ïÑSœ€…ôÛœ¼£À4˜“óbéO}Y—ŒAÖr”L´R]c¸ó|Gç|ò†N¦|^¥ÄæF󙌼¾ä“3J*2QB±P¸ö5Ž1a=Žñ5kÍ(-&ëN?0Æ|ê(Èþˆ±£|yó{äû5—Ó3ÿëRw”m < ÌÜúx¬“Lœ˜qN`xÎÝçÛk¢ëDºzƒœX £2Î3*åKCîÜݾ^—¸Néx¬K›2€Ì±tÝQ5 �N–K�€º5éxùöšâ8›ßOaXÉ·,ÿ,« Øm\ë ^¨5þÎÝÄœ½Ÿ�%ùØ›øü ÐD»Ã|¨—“8ÔóÁú°NN¼ÃBÑñŸ«®öƒæŠ55@-¶¯¶—kIí÷1¶³ÿ&5F[ª× v_f�Ú÷)¦sÕ‰Hvò¾I%õÊŒ+~k[fZÑÑ/&±_•)V2Mþ¦=óø!þ'µùe3¸¬]FÙÐ-i<~;*‰šŸ‰0 ÔNÂu1Ré&r½•d;%ÆtOÎ=iÇ^l"ŠNrPàŒ1Ʋ”¨3ü[é8ù@IW›¡RŠÕJ�›€Ê�°]ýl~ÓÖËp^ì¸vl °1a;‘©´”=¦ä„ëæÜu­àà9‰÷ÐFÚ$qñ9z‡uÊ㔊2]Ö#8ä¦ï×Ê@ôR†!¦}ƒe‘QÒAè—ŽÌšÚÁŠæª.c^Róá÷5˜vZÈ„iýÇXq*A©­îqÊlL›’�¨V·>æŽVàÞ 3g—˜kr °?5E)Ã¥¾¿ãO¹Ÿ€ØŸ!Ùø\�Øu—<eÙ‚Ä–N,ŽH¿Wg§ï¬)–×ôt”û”°Ä#SÌc[’J̱ÁÎr�Ü+ì¬)L1�ÀøäÉyø�è¨'Ô"’ÄÅ’'•ßpÅX^]·—ðÉ<øÒ㢿ȱ$Ì‘‡OB’€Jù å;ð2ž¡H!#¬Ñ�óH#‘H�ï“|ãÎ5@”ô°uŸéA00L xѰJ ±úFÌD)a™c»•æ_“blŒ% /–b™\ ¨1V†äg�6'}ÈúE´a4¼LÝÐgSê‰n\hŒ9¶†—ö©Õ¿Gé¨êDàä£N~Ƕ>ø¢Ï|ñ»§`jêþhÅŸ?^±ñ /úƒädR†™¨§1€¶�^ Á°NC¬Æ:¡ ŽxÒ· ã ±9FÇ•:CPXœZnÍÁÕó’~¥ÀWª'û¢.É›Ui2$©ù~šô”æ¿(ý>“ÆM2pVi&(‹¶ztÎÔJ—¾÷y5|Ë«¢}bfÌ­R�aŒóIRQ6C³ñpžnÉà­@ÄBÑýAƒqY­@’r›‘\Ìöb$Ï3€]%Ld˜æÏHóNW÷� X%¼5T•žÉ‘ Þz§w”$T©?ÖÁ÷[Aƒ ½ú(h€ °…d‚¯Ö6.²Ÿó°àxi eµ'÷üçz¹#0Ê[ú ö´ü%FY§¨ljwØ b–jª•Ï€Å*ý‘Çi¨G�FË„5Ï#cÍxúΙOãÁ“öy¼ÞKf <nT%¿QbtaQ€xzv›6ÜÅ*8¦a±ÊÚù9ÙóÍÇðJÒŽÙá„í£Rz¥cŠ!ÏÇz?¥F­T¢öB,A2V]yÚSF ® �E3^WH}flq&à àf£À82� å³[O2»ªÈüƒ/ÆtÀÿÆÙ$0¥•‘êö/cÉßøM;Ç ut!ÍÌ;΃^ÖÃv˜8ÞW™uÖ®ÓÀ¢Žc×:ŽÈ’ýKt\Òÿ R„ÞñHöMc‘:Ì0‰®çrݬààÊè~¸s «åþÁtEæ}QìÏp÷S«Uê;ïôP&L')ÏX¾_òá~-ï§uí˲#šá5¿3¿‰´_«n€t�æPŸcðfW,+‘6¢'½8öȾVÎ cØçÿ¯Œ=(!š†–7åíÃ÷Ôu5ð&u`Žó“´Kd2åyN� i7π̀W4*ðC¦–0”zZΣ db*ã(rsÐeG0a )@'R}zž°-–Ç Ÿç÷Ý48Řã`Úéhl±-,ùé#J¹e`lò3ÇP«†hxô@LL|^¢„PãúÜPß¶|öù3dÂP Ç4̵#ªØˆ,‘Ù’~Ȱ¸7€wàöÃdÀcó;÷…‘‰—û»+ùµe~‰@­-Rúlo SÅ®ÇÖñÂÞŸ™[C{,w/œ«z®~")J¦%õ³•H-½¡^æ;:î&‡•‰Æs’ƒhP pÙE�üb«SÿWÃéëDƒ¬ÜjCf˜‡‰IøL +Ý×mf¨YüæRì±NZªnÝA"´äzHþJ$¦Òæòr¼HûŽäû¸»Ëó„dü:“™7¼nËÊ?¼ßÄè±ÀRÕ ë&Ð çï–k·I*­” ¥#ɼ#CJ%ëi,íSOÚ•±ÅjŽ}ê(˜ÒD€;S=y>%ïK,3AÒ¸÷ûëú$íÛ&uàOÆûD÷±ä×uEʰƒÅ4ŽØ¿ºŽÜgHy`_s´êË”Ì:` 'ʸ¦ã†2ÿÈœ‰Òn?°Yzf9šÓæàØ€ÀBÖƒª[sip ±ýD²/¯[ÒÂX€bËË9zd%`sl+š©Œ$žéw]ß&Mû¢œ*ÓK€—ª«ö#Ï�Ϋ¸(>œ¡¯°® à×õvTJ-Ö¬3à4àpbÏËE_”‡ 3-ÝG€J>ÖƒÒ“Â4ËŒ®4eT†ötL¬\Þl³ýbíÊAÒ°€F{À 5´/yì×ø\íý>�Üö™;^ˆõÀ6Ïœ…Cÿ¢�˜ûÜ�T!üù}‹ùÄô'�w[•ÿ®»< '€ØïÏM€˜>òÈ{p5H(>Ÿé>Ž åëc¬±-=ÿ¹þì�t¡À¿@Ÿ¹^bÚ4AGÆ–H¯Ðl†^�˜žJ$$Çì +Œ°p©y29‰”v6„‡Ø )-ä •|ã7^¤˜wdÑ_¾l#鿦ݸñÊ›~RÆ=Í LyÃc.tÄp°!SÁ“9%sL5h4Jé°w† œÔƒBÆö‡½.Tx@]˜âI­Ï•ûc„³›¢/¢. 2ÞÚ’¿JE&›d7"7}fº 4Õc¶¼“c'‡m~ðì/ö7¿øõ¦ßo³ø LM_k}~õàpà¡?yèy0RŒ¬è5 Œ½¦¥ÜɃ_Í“žVŒ” $’Zòk>áÞgà#FƒCj€Pé!û»a¬i¾3�VI¬!!`"ÊbŽR\:n£AlJ 2 } ^gôœÍL @1 Še¸�]8Õàäì’’õ®R)´(ÚaãQÒ`/´Fã’i®Çm9ªY¿ÐW£h˜§Ï @•j§ÒríjJDÈÁ9zŒê|¬ãÐÂ+Öeà*¦ÈÈj{`ZéuäkP‹š1¢h�ïi^nÃ(ÀKÍS.WìÇ‚Òe�Üh~W Jò-åúq¨g�¾Ìûå>G@È_§ùQÓlü=3ßb»ð~RbU®/Ñ<+ K¡Üc4nÜk)+äìýŒ]§cdèÛ?3Ø23«Õck !†à8{Ê51Ê(¢fJÞªúðwÎÃCJ¦¨®ìúÞš†˜Š~ÑÆ"c•ë‹Ì_ ¦UÂ$[(æÔ±` �A øé½ZE$$<ÙõÁö$¦šìÇä9z¬OÒ†âÁLÇŒ1¥Õ­ ½÷N‡Â@Ëû"ŽŒ¼.N–uý”禺ˆ”Æ‚ì"0“^µ|«öGcí¡²#QéÚAQ;æ К)ܔª“}™*Ì: -æß÷ë>&ÆÓÚúýcÞÐóûOî³y@5�•üÚÌøR³@Ø'v˜é>˜Ïi;‡(îÏÁ!ûôNpìª3\ÆÁ\ÆïÅ3›1âúÖ�ˆv–Â’s‚—ºÌãF˜÷ºŸÎ¡ iÆŽ‹pÝž±dEd)8“ê]­�°¶n°R~Ë£ag`�ä]?RºkÖ1ÁJÌ‹2Ƹ6ÚqœKÊ„’}\*×jp½'ð•GpiÊ‘¥ {ô¬–ü ýË‘I =2zî9ã�t™÷¦øÉíÔc~hJcL›­úëËD¥{ü{719úD†Ñ¬Ô£~þÜ`´o}èuò·íÊ5™º63¯Ò†øX t¥Ûoµ¥¸.Øìj¿Èz!íÝ­=gÒØ_ å­V"b”Nœ,5ñ~ÆH%›YiŸya¢Œ#*Ä$‹Œ3ߎ«¥Ý9Þ³a8Ý5¨IÈÅu¡À2ÆæäºQ¸n¢ë—e„Çòšˆ2nþšèg2ç‡rŽ•®j}cÚÕ˜b7`nµØ6,5%ë:ö>êï€,óÍõ-eƒš¢tëô~8&š1ˆHÌ(æÝÄ0žÔösR¾F†„yN×þ^ôýõæ¹}Ýùˆ´ad˜Éýn¿¯Ru�”@” )àp<Mâ‹ H:N$÷¾cJM ×ÐÔG/ŒC„”£WŒð!õ¡ ×#ì²´£�—ò~M”yìó¯Í¼S�?ÏLÌ å÷ y>»ñ3•!%åjëyÝ_ÇOÚ.n}cÊýO€m(ýÚæ8 ëC-&V±ÀæÓSæÝéÆó¹›ùv¥iG“Ÿ”7ĘÊÌ �.ÖZOd&8Rªý@€\TF>ž£=0“kP)ÍÏ”d?Û|õú:cÙeŒiežÏä$¨³£�h륾ÚüŒ˜RO¶ƒ2»"€Î×,'Û50Â|;ØñâÛ5gÚB¶ŸêåHy&S˜c¡¼úíHžKI[¦ç;ŽW¸Þö™;p÷;ê ±?7Ý j#l)¦Øÿ—DàîÁW71Ä3¬ˆ"ƒ¬A2@q„[g†Ÿ¶ e©Ä3§H-bêç”Ry2@ùœ¥·ßøäÉ¡Õä³zõ"P²¡½  |äó³¶cêX ÂyTkfÏŠ~hŒ9þÈøñÀ•O¼êƒ?:¸ä©—Ì^qpéïpÆO>\¾×5»ü:y¡þw|cŸ‹v½Ø×}Ÿ´ç›€O»ÿg·ŸðwÒþŸÇQ8#ôË‹� x)¾�ì¼ÿÎyÀõÀ_=áàžü7°A ]<}ƒGS)1Êr"\8ïgÑà ¦e±å6duƒÌÐi*½Ã¡^Ú!Ÿi€“=XZÏ`ÝîxI)®óT®•“WåÉ!†©ù€õ€£š•˜ i”1&QC é%ýì˜PaÞ´Í¿üÕCC?ô¢æjamsšyÛòO/û2pɾuÓ^”7̼¾¼&=WcpEÆRV@VôèyHi'¾g (X©+=w0¢”a¦zÚ3�*•¬Óv±Œ![Ø…yÀ˜(âÁ>‡`üˆÅONήÜ÷ªw]ýLà’}.9þÊ6pé¯pú®Ø÷šûýzPÝ‚w|ï÷íz°ÿ÷{Äžv<tÇÅíßàóÈ›JR~�ª3p€VñRœ ìò¾ñ€ëƒ_óW·<9-ãà©/±ºÒx«†EÛûòTùý³L#Aãê¯ßÏ”�øJ†xÆ,Ê$›Ÿašå™3H©0 5Æþ’ ¼íô\•Š£!b,ý\Ö�(ÿŽQeÞ·xŽC4Ý_¨–ðÐéé¸MßòR{ó7¥<á=¦‡Td–hì=ÉAú%3fá¾Ï�ÛsD©¢fà/|¶](…Y­U)L¶ÿ(’¢A*´ËT€­Ö?©?êÌ<–·QzCäÀäççò=ð½>#¿p¿l 3`fß3²Ï-a^'Y�*2ÅâÆ]>+ 6ìã©ø±0;Kƾ úgìòÍ�|9Å0Tª´YŒíQÚòkoô­ªšûRž®ün'00Ä¢ŸÏ²ÃŒüÅfÏ]Ãð‹RŠHù #—Lª9Y‡xˆÌ«ÿœ´“¾÷éþ츑æOqT±LOÞÉÖJ0ÊüÒõ¦=²@xÏ ¸Ñ0›ÕÎaƒL=Ë€=Y/aÌq€*ÓϬM=HkùO‚‘šãú$Ç4äa=ã~Ë3Âr¹<à¿Ï)̇ÑàWÏßå·á%׊©†RJ‘úö›³¦n¸·Rìù3wm4l…y×—ò¥v›f$ÛÓ~0‡s €c†'X%€Y^ßÇZÞhxKã¯/ù”ï1Ì8&ã+;tÌ:‡A2tÖ‰-*mdfV¢ý”ö;=鸱Zcª©¨¾ÉAªï ]Ý`è¢gƒ´çØ@½é÷¶�P4 zCeKbNe¦XOëa¥í†*qÅ»G2ÿÎE‡Læ€0Æ®é‰ÄdÖr¿êár�� �IDATyàlš$‘¦% „ãp]me­9|E ohŒ‰@eìq´ˆ¡Hc}ohª—›÷Ï…} wÝÜ7õdO휙`ìÏÞ”}xfŠ5*3Liw2Äh@]}¬4¡y’—Ä̆Ëam¿F&eŒ©¼[¯9‰•6rŽC™éÍü˜ ™1v¢�a3@ѪcÁñO6^7 g€¯ÎpE#ÔV &IãÍ3VTè…ˆ9À¤h‹¡r(Úv¾”i6v”é¸*Ñ–FÇTà‡)„nßsˆŒ 6y9MB;2†‹MS¬QfJg+CeÄÙ}‹ÆB›lõz8YFÉóx¢€•aŠ`i΀¦}âY`KÒ” åU�RêG;H]B4óž�sdеàeÌãQí9i<Ï :­³Qyj’K%ü«nôÀä”ùœ±Éû(e—7ö@‘›Wó¸%§gè¢#Ì ºc†2K•·2çS¬É ¾0q=#]‡Èøš&Á—®ß¬ßwÂy8Õ³«ýà€6»û�ÉÅÖ4«ÏìQëN` M‘ê«}ޱdÆÛ@ÊÑñ°á\Ö*j’˜ö©¸ó€Uµ^Γ,qhó7Ì'ÎÂКzÎU GŽk@¯÷ë°Jöm9€¶ü¹¦²E€ÎÞ�¶)�X·ÿ ºv}(å{ϼ«Ž¡?C{s~îËüÜMãà¶ÏÜñÂjsÄp(šÒR‡Rj�Ì[ì+áû{Zž{ZÞF&›ÄÈ#б„G¤ß«³cˆ¥¥)‰è§4â9zÝôÔÄ Ë’‰LgÕ$Sš*™XQ"bõ…—ŒâX¸ëúú=”^j£O Æ"åv�pÝ__·Ûõ;óo[xô©ßÎÐåÿxÓáþiýçVïñ’ £Þwäû�t‘½þÛ×ïñó¿ž·øŠ{õúêè/¿à÷û ´ß={Ìñûè$ú/Oÿå¶7¾øê³¾ºò[ÿ|ý¤owÙß×]öËÍ¿ÿ.pÈמôŽÝ><güì[žòqà¹C¾ù”ÃmvÙö“Û|;åí^bxè Õ‹0³®ûñõŸ¸á¿€Ã^ýŠª±œÿù‚Û÷;ho?ûo;ʺó;w>íŽã ®»à¬‹¾vÑ7>~ÑÏoqÑ?›øÌûÿêÞÏNzÝèco=xìY½tÏ÷¤^¤ÇµŒ×wüöŽënÿ"pÅó®8ðê•Àe;ý`ÙUÛ—ívù¥?=¸rŸŸLþçP 5Zþ%|xÂ3{í®G�Oúñÿú±+€'øIÇî·3ðè?æº=ï,ûX±C±S‚c)J%RB �¯[¼ü®ÿ�.Á%Ç]¾ð±³>¹ê?Î�Î{à¥7ÝØóhëÒìvozÁs·þþ¿ÛË^šËqÝ‹®Ûÿ†ÿ;╯m쇋^°y¿ßíÍ®zÛ;0ïxé‡ÝùmàÂ^ðÍ‹O¾¶ï7î¼èÀ·_ÿ½g^¿°ã«¶?æàé—|ÛãNž³×_Ÿú´‡û¾zßÿ øþ²—`O�ý� ͆ª6fÒuÕlµ¸îªëyÃ'€ùM ;œzpþ¾—}Ó«ÿì×jÉ´a·ÕOÉÅÀ‘GõµÃ>kžÔ”$ €ªkOëqÎè56ÑRÌ”ôI®—ü‹¶�!ä[ ÆÄ¨†þa]RpƒÅtú"ag &ÓR” êß̨ªælyŒUoZùäÛ`ó)|>ëDòp-¬`XÉ€wʇ+¶<N¶®�0”É¡jƒÆ4‘ &õŸQŠR ï © TÏ•C¾/V§çT4W·¸¡­yª‡~à7#,¤žy§Àll7Ï|óL=ë±H ŽõPg6â´§“ÔƒhÞ ÌÆ:´½œ:Ž‹l˜w㊱©„Yj¨t•�,ãÆ0Ì abU jpÄÜëcNbÑ·h{àÂH¥*ÃM€mÖ+yT‹¶�?b�—u¸$Ö% ˆy Á\g ã<$é¶*ÊÛżÄT\¬IãÚy÷8_´¥ÿ†X)S.÷¤XÇézp’çúPú ía1§�ЖXž ±jTºŽSË ‹@z[Þ,0eß9–ëû2¾ºy?ªµ÷1Á¶,¸Š@œ2JwÝPnsþþàHÔPßFénŽ”am†ÀnÌ'JTË÷&ækèÎQ2h @Yzn'xÔ¦|^šZ¾ïÈ÷:ÒX)ÂÈ«¸ØÈ@ÑÚ …µNê³6%† ²ÑÇ3ÇaeˆÙvœÔ •Sœ�fe^š¿…{uW 2% @;ÉÆIÀ$ÍJ½ÀØh72ÖJÞ¶¬¾ÜÝðÎ÷CùhÀæ8'äÔ † BL2Ñ � P3ÖXK^ZÒJÈYàj"P‹jìž=ü³pšs¬GR”¨“r¦û,À¯= 2XÆÐ}ó †ŸnèóëZ'KYJ=É‹@Ì43áJpN‘ô û$«Áa4–º#ù˜˜CÁV3 ÆçH+”T¦öÚ í5ÑùÓ3£ ŸÔ| j¡_´œò×3'uF˜&֑óÈ)+ ›[Ü9ì2Æù0k&•.$S“õH-cëH®[™96ÖÄ#  ?3'RÌYš…'èÅ÷Š þ«Òo‹pós̜ԙØÏn}šèŽ ïÖÔÖÓÈ òÒˆæ<nr2£!å5@gŠ4c·8)Žq•cJ#@æ˜L&ŸÀëÀ&î&8òÀßšT¯j}`€åüjW\§¼CÅDw |ß(AÚ æ˜`‘Á–™a~=è+ó*O”ëc,õÛ+™¨1Ûø9�g] øy,L 23°c�¬¢“ÞËj�ÆV¦Ô|O$ èµíüX r=ôË1ü|:}ϸ³V(Ëœ¶Œ9 |„Ó˜†yÕ­1ƒósèB66å›ðt 1Ã(H ¡ÑPtÔb2æu3dYâÙ|O@Å´[J›%ŸåùsH*µ©m1Å6ŽCi·ÜOpã&2}™:dôx /JQÀÀ$Šƒ 2I%úľ¡’‡Ø¡Ã+ë1-–™p¬ä¡\åcqå˜b5 ‘ífË¡±ôƒÎîžá5òíæwùùÚ/-Ï´SÆÞ@Þ¿N Ô%(#ÓŒõNù%û™‰‰6­ÞZ/ÿ=ÛK¿‰ý0   ùVû;ëuëÞw|Wbˆtb[ëËý°¿€ä!óiŒvOóçõ¾zK’‰L �TƒD"ÓQrý™Ë€W)–b…µ•±Çr²L¯#¼¢aˆ¹r7ÖÀø”ÉyÕHyzú >Dj jà—º±å+7 )æCŸÌ�õÛL¥¿ÿšó¯ùüŽŽþÄqëOz0pÛkî*î~ÿ=l§?#}v‡.{û³€}÷Ý÷ÊÇ? º¡;ïÜóžsÁñÀ?,[uãiÖï{û[_ÿÂg]¼ñÞoüâ« |u›¯¼óOV¬ëm<ý![ÿü§}gßv=8ééëw8á›Àý/Øéå;þ#€ ˆžÉþÀ.Áo=ô›ŸúÎ~Àqï_ÝûȯêùŸð˜7\qèÀ±û¼q»£w~¹ë/N»é {öºM§<¸àú+þx󻦗ïüŸ}ñ»~<�|ÈŽÉË:3AN6ÿÓæ÷lþ�pþÞß9ó¢#€õÛ¾û9Ÿ>¸á7¿yßí—ýéýòê¼ðÞûß¼õð7ÿóko�¶;tû£¶Û!ý– b0Ë�PYœ\qï+~såóu_ŸÀiŸ®¼î†÷þîá"é´½ûŠØ xêÆ§žvÐ!Pƒñ·Îýæ©ç?8îúÕ'~d}ý¾žü†÷z pìþo|ý«_ üâÑ¿¸ß/÷Úû¯=ó½}à{‡^}äoÞ²õåè^¿â-Ï¿ xÅž/ßã¨Û�W‹ª3JÌ$ /ù<Ä"k¾võSüGàèwwÅIn{ã]ÕÝïù˵ÓRé3?üÀ×Þþ,`¿OîÿìÇï@I¢,SB)7óHMj­1&—´EÎ3W]96!œaXc-¹Qª:åw†âîñ×FÃ@Í#ÀÑ:£ÊÆæŠiK@û9�c¥<g>3nD<3¬ÌŒ¹O�)tx8Z-ßoç­V@gä<ÉÈ|d»ŽÕ`.í¤€’J"HùR>k=`£šÕ(èµjƒ™U—\ 5hÿ¥üVçv&€Ú?m¸× µV­ä!7БyÑü©Ÿë�§>·n‚ÉÄŒad�Ù¼ŽŽCe’?¥œÊ m:ž>O&�TC€å÷;]‰E�IÊMà«+ßgø-åcb®)CW$@®L9�’ã/Í E¿àA{LiCÆhôŒk¹Y%¢kíS“º ã-2ßÓ,Ç󆿹Ҭb`V@«ç {õñ®É1É8VÖÈNÃjŽ’ˆ®rN•±•¥k—^Š�Ð%ƒ]ù4æ¨�_JMìÔF ^-W®rà21:å{i÷ž»£-Ò‘ÃPNÎK*]xcŒ]U«gÍ y šú6c)f—~©œ9oð¦¸]¿,à«Ì·:3ÓK}W‘–cè6”*+.˜ïEQ�CdðÎ Y3f  ‘±fŽì3�VI~ °ÜwL“v6ÀJ¿2ßz9ìšnµV¸zg&#SzßfAÂ2<­DÕj1²¤’:2P¦%cxÃ…ŒÍYÊ},1]#•o%Ì$ðŽ“¥cžeÃ{@“0*Ø;Ñ@(0uÉ)¦Fé)ö”Y6rŒ0Þ·V @"•„A ¨aêÊý>¦›ie¥¬&Æá� ýœëç<ìa ÁÄÜa‡ d¹v&p¶FcŸmS,æ×á¶úkN&ï ÖÕ*±9‘vd{ϹqÙ‘úÓ>ÁþÊfÖi’’ˆý+ùçz$ ‰ë£{ö…y‚�”±^Úê²ïàþ·«ð^ô¦ÍÿVAÆòýu“ðyXlŠ5 ´’crÕÕЙA:†c˜h{iűÄ&cŒ'á»k>³dÐ5–?ÏcTCLìºß³ý�5×w¤ÒòN€-g ùÔæ} Zl‡i@!)¯ÁÕfU Mìú@i¿BbΛhŒe—c]›XhˆSt�ð4Þ”}…îzº9vœ¤X× èø!€ÏöÖßd ™W-YWò:;Ç»Ög…¾rêiŸøõk¢L·Ôþ]9ïôÉè²óf‘cªA]`™Ou~˜KýA�KòS©RÞRîŽ<?§f5 eˆO™ï ë›¶ËÍv‘zõÜó[ºžõ›H»( "¿ ¬V+a™_“òùtÆöãz7rëA`¬Ù˜”:Þüüëb’™ßŒV%�ƒc³Œ€-JëeÉ<½~ËŒ¦ªÖ¹º"<'K1’AÊ)�RÅS=36@­ô=æîËß,95F{+Ç@ Œ1ÖÇg íPc€m¹ªns>Íù7_R?ŽkL6‰'óÀš@È÷80á|9oûÌ/@ì¬âl)–×´ôÿ…A†À‹É”i©Xd÷(1†Ø2ÓàGN½zË@˜»Î¤€DÞ�„þb‹Ÿ½âÙÂ#,ÇÛrz¾üeÐçµàÁm¨/N:hÑ“ezZͪáÁÆþ2-‘©Aƒ>a”©H_u"ð‡ þð¥?ü8áÊ5¾ï˜¥°7þñeÿ|Ð6Àø©'¼øð{ßu¿cW;ÝxßgÌüÇÒÍð„'íþöû ¼óöc>ýì3€S¿ûñÀžÿùè§íùYÔ¿ÿã_ÿììéùíx¿?¶ý sîsöÉç>ãžaLçrù»ozðî›7ÝzÚG€»gïÆæ“lÚ/t£Ä{l¬ƒkÞü£~öúéùïtõN¯Üáà¦îMo¸ùÑÀ1Ÿ~Óòùk—Âöú¿‡Ÿ°ý¾»Óµ;&`ËÅxX¼þ®KNùÌ)ç|äþÀ?ܺê'§øçaLŸÜïßï¼ì^@çîîwO~pûÆÛ»}½‚†ÀÂyvãoîuáãþò@ÓÃ.}ع¹PžÏ^™~4ó£ûýlÙôûvíô™Þ Üxÿo¾éiÀ±ïzÓºõ;Üs Œ©¿Û¦S¾x/à'ÏøÉƒ®}óËKÛÍP-ýd@ýÃA¿?óË€>¼æÔ÷½li ìØKÿîWÝ8ã˜} àÃÿyÒ÷m;ýï}ÿzæÜ¥Ëù„gïþªû¿xçÎÇ|íÙ_�Nûý»yãJà1û<æ³Ú –ÑEiD•NËßBc|Ñ0®ï+ M4 •²¡(SÌ Þ_q>*iHÎI$ e¯ï[ŠÙÕ¶OŠv¥LYUÚ,=ßHÝL9ɨQ†8=Ÿ�ˆ\¾•#'„Ç™x6H=ÀlPh´Þ #¥2¡J2ÂÒ¯dx<e L�…9ÉŸ9; ŒõåÏ+:Âáª\º!\[bùXSæIŒ³L@.©^¾]`¤¥ÞYÂÃ0ƪ ÚÏs®_¤Ý#0aÕ2×ðªõ7ÛA6€ãÀ‹žâ1•6?e€-ä~ÚTÎ…À8%°Å˜x©üEfÄÀ^§m¦¤¼¶ÍoÝõÙ€(L¯Ú†œ °±ù]FêÒ…zÐ1—jÀ6 º+�Æ«ºÐ_ ”•H±È6™ò ‹¾ÄÄ¢dY¨_Õõ±Ô*2-@IIw}i˜×‹�ú:þfÈqíÖÎR¾dHëx\ÄäJ#²§ý.ó÷s[’»éyƱÀÇÌä<)oç;ÝÝ ÖIE+ f™c¡9†¬÷0§Ùa•¾Q#a>Ö“–'î7syR~Œq™xÂȤˆª”²äô"™RP©jDò—וd,f� .åh•"É~²v’ÏÐ_¯À––3¤Rúƒ†s֮Nf8©Èu!¶Ì8±Ï][”Á é%Å×ÑÁK{¦O Ì1;ú{6Ð'ÉAæŸÚ)æ` ŒèO} ZgÞï«b†»~A€ ¡ƒ°šR×Ð¥Ö“žîY’Y A*®¯ï“]'iا!žžÿf a]�°¾œã†¶,*%¶Ac•âñ?&¦†>ûRz’ïo_�J8𤆹‘koUfÎ%Àž¿¼¿ê¹üò¸Ž ä?9 ,W]פ½FÒž=‰AÕ ©§Ž éóÄî L~j``%õyŸ—àZ£Ÿ‡.¦aÌ·Ø`uŽYM`@’¨ôåJ9jRÞ�€¸¿uL@Æy9•Ò?ì§¡ôÛÛ‹ííÚ)3®5)ðkw¨yÿE p)FfÆ–ÞÝW@ˆÏµÀ1¯˜ªÜ/ý®sYmÊÈñ/Ž–\×¥uøÞ’‘CfeŸu*Õ™>«tgÌ_$^{Nª1§I` ¥2u’„bµ>Õ·êªT[W—p +JöMM 0Bsš|È‹š#4çk ÀT0yÒUx*:SL¿wëJw±ÜjÂglJùèæK¼¯X£ÿn&%9fW5È2Iw]˜'ð2ÀÛ1H«Õ¥%͇r)fcŸa"ó>b¹sR_îõœâÊßB«Ø”û£€ïeÞWæ±ÎW;­Øk²”µ”cÔäècòόߑü ±ñÈj ó¦¥ë!ûÍ3[[6–š‰-ÖŽfYêrœÛÑåÇqÏ}cb²ÅXbõ4vù+Æñ!ó’côèRÀÙ0´ÍVz Cþ¶¥_à€0¦žüMå_.õ\^s´pÀD5PæT~˜-V[HÝi?Øó=Æ,Aª±¸Zv=$pãèÌó“zrì($±Ý[õ{€‹Œ«(¨W÷]ý[ž¹FiÆ|nS€‡öºü~?Ï/•­4ºÝL¼c¥arµÜø™ÔbrÖ€ºTOÚZqßÀöŸÂdíö1EœµžözÆ~CKêQ«¿¶ƒH†V³m}í9“iãD~_“¶�$E� ö:Q[¸¾ñ~sß´üÝï °iL°¯Ü“|Ê�X+•ø§&2ÃŽnøL†X–KK@Ø9 ùl)vXäÎ ŸÔ¿§»ÏgMe†5f¥H–2áæNWÊÖó‰ý<еspW�9fƒzH#jƒ'ƒGW(ä²9ï!çíuá2àºÇßüÒ[· ùúo¾ägOúWàø«W\qìÿŸyü®{ÿ8äQO;ÿà›€·ŸvÜ›Û ¬tãÏæïüÍÀ1Ï;fߣŸ<íÖ§~å)ÿ l»f›lS§úWÁû±+pÞùçïòÃïMÏï?¯þúï ¼³7<þ3;.ýü¥Òçw9wáêÿ~úúŸ>áºýa“cZØÞ�Píw÷ç«#¯?ï[w]þ¢éù.äòã—WÀ`Åðˆ9¸áÓÛÀêo>÷ìbÿÿЧß(C®¬Nî~íÝ+ª—zȇŸñÉÕÀ¿¬ú×+/|ÛŸ_ÿié«¿ºè£7\|yç/íùµï#°DŠ)y²&Ïøê»wŸ‡—_ÿä·Oüá¯þ̇6$Æ{Ї´ÿÎgC˜êIÕ>ø ðµÍߺíòO¿¿ø2þ¡ø4°öß{½÷0à†_ý¦sûÏþür]ôÕ‹~rɯbÐ0¦  9Ø�†I‚ë¼SÏÛíµÀu‡Üü¤[_1=ß×ÿô%¿Ò ÀÛ?üéǶÇ/<þa{ß ò¥§ï{ðÍÀÛ=îñ‡—X2m¬æ;þÕÀ1¯=öÙ¯úðÔÑÓ¾}ðj`Û?nû¡mîœçGœ?ŒÁØ[Âh)µt”ËßFJ •L+úb¨Ì€Wî›M°’iÜÀ«¹ ¨aAƬ+¨õO nC¢ÌTêp2 ª a±Ÿcð^„ÀHºaŒ±5ÎÀœzª¨6¨AºŽ@‘1عûk© “jDF%+­S 2ð˜*kK€­¬~¼c”€¯Âlìä¯z~i3_yž3¯WkÃc¢yTb“Q¢Ð~Ïr»vUà®^Î-nH-°à¾fIÎ�”Ù˜d<4•¶žÁÐÈØznœè{G¦_ICTz«a–¢”Ï:ŽkÌ!/ÙUÚñ^‘‘U2¦W5�º_­4@_®±Æ"s†®ÒT ÆjDÅX§4OçëÆ�Ê¢mk•€ dþ‡ Ð]”š* À±Ñ}NHeÑç:b1±¿“dU1OÀKc\2Ùu’í:`k•\_ÊãjNü4¿ÎéÁÞ2 Ç%ãR>•~ŸÚƒåf¬1J8 ­-ãÍ8N¹ró=\È3Œé3¾‹^"UZÐæ[2‘¢äõÃÜ^”†L÷�d 0=¸%C–H½A›¾–Æâ AóI;zZ V Œ"y˜kÙŽ×ó9Ž©ˆ`p p¦óDŽéåRX@ãu|.µµd†EFÿÎà¨ÀÁ:•V‡�5>ÿ,ÙÄYb–©®VÌäoŸžÁ › ’Ü_¤óJ_Æ;a}RS,¾±3ŒÕÇl³’brŽ@©†~‘<Ïõ ’ñ„Ü8_§z¯iùRÛ/ÌÄC^bdu]Œ²“¬+†Ô¶HN‘Y2+Œè|t’«Oj¿ a=ci7€sŸËV¢ô j~&ƒH)µÔÖ¿cQñ�LvKêI¹÷+5†¸â>­-ûÎ'\WÔP$Œ<V<Tä=çðMEöG #X­Lí˜MZ¯p}fšøuž†¶y18©)zÈKþ(fL=ð¾b#€ Y­¶?ƒwdîI¿ôÌ5) ö­j@Ç0©øá Ü)­g0�ÀR[÷ã¥+Á¬Œÿ¾¾@–xl›}óM€xW€±”Ûj1ÀÛ}Qº¯]I¦ÄKÏ Y ‘QÖÆÌÈÖ«di¿ÈÔ´1©TÚÏ ML«,å—˜è-iG+¥jûÍ<Ï¥ì�À4 1éY'MXtÌ|c V®‡Ìóóq= @!“ü]~u©Èø×ÇêjM�&¾]mró§7{t!léó\lÌj  µ˜_fpyG…܃põÌÉ7$ºµüËœ_€G;àœôŸÚ Ì;´|¬2˜Y–qL@—La=?¶“LÏ©Ô'°¤ŸbŒ¼¸T�I€?y_¸R‘QCæ3%Ì3ÀLÇŽq# Ìù{έ×YÒ0;ˆP2²„*±Àä&ésZþ÷¢_sÉQH 0{úó%ÓæÌ “¿·nX—˜ï[Þ‘£èÔ<ê1`¢M5HÏ)Öè@kö¿0ÞB 1n2@åúxà™Jšß$®ÿµØ\.ôCÕ æd²›˜lM€’eziÏÁ•[�êb ÓŽ€lÿ\e¤±Þ{?E¾ôÔ§RŽp#ãM™k.µüÇ¢£û£–+/_£ý1!@É~"à+¿N|ùb»‹½/ýÆÚx�OÛÛÏÀz™çî#,H[!IØPmá>Æ#¶År50Æ–J®¾Óî_Ö„™˜`d†1vXC ±ÌôŠ@“¾Î‘b’?G3ð5-¦z¬²:#ŒL²­Ie– ’Ò2ÑA[¤¥—ÜÉâbºðÛM6ØtkžEÞ#2QÉwÁ± øÜ}áˆo<géb¿ì…/ùØásÀòw,{ÛòßÃmdàAÏ~ð;w¾÷ÒùÜò½[Æ¿û’ûÊ{8¬Kùþî=ÿ×úÝ÷K/ûÉ¿ýÒôü¾}Öe×ÝtUþ|Ü{^ñ¤ƒ_|áuyÓªë³vú†ö›µ‡¾í‡o(‰éêï^õ9fc±µUâÕ‰À-_½eï[î�®üïVýîÀéù­úÅúcÏ�ðÍo\òö_ì³õöQ¢�� �IDATåxÜÙ}ÜwÙ“ ,}ëÂ/¾8募Üîü7.Ï>»=ò];\¼ÿ)óÏ|íÿ8àš;øÄß»í›Ožú¨'ìð —-ÏI3ïûä¯îÚû®3îJSøH=OŠ?ÁS€³~ñ¹ýNž�WísÁ§?ü·À¿ïòñmÖü×Òùï~Þƒ¾wßs€ΟŸí\µÿŸ>õâ”Ï©—}çÛýnfv¿×÷zôÃJà–/ÿö)ÿw"påµ7œð»¦ç?ûO_óo/.¸æŠßÞü.`‡¶}HkG`ÓszǾêràœC>õÙÎÀéÊßú$à1ÿöÐ Û·t¹¯8èÊùk’þ_ »4ø/R²§Z àÕûðHàŒs¿ð¬o¼fé|_öú—œyøåÀ²;–¿ìg�†^CøÁ{ð=ðËKçsËën¹óÿ.„J£!kûgƒºäk¥Õ€dÎæÀ|¿Iö¢/A×Ó·«’$[Õ5¿Ë_É/™EÛUí¸ªí6ë4â@@–b#cÆHíépþðë¤2°åS ðŠTtw_±N\s¾ôF$Ì2­2PW€FJ/´Bbp € 1S‚Ô PE@IÌÿër½§0ÜX  ÍvL£ó©j×ûöóϳùñúf (gS�ªÀðËù×A–7]W¨Ô¡ÿÞĺØhÆ�Hæ0Tš `è[õ¿ÁV˜+¥|=ö?ûµyãžc›y�M¾Ò1«ÉûR´ƒç›6ÕHæ/æ$Mõ ACæ¢Hé s3*‘:M"‚@…|®LÌEǬRIG¶P.æAËÆ1÷)`HæÄ*ç+u�0L¸1 SHKOÆ¢2QÔ@ì m™1 ®þd†-sLRê@‰Á‘�VÂ8ÊãJç¥ÒŽ?a˜‹‘f”yÆçô|9ÉÔ2#€Çc‰<s|ÈøJ1ÖègCW4jû[À äzC};K0Éþ‡­šrÈf>a ³šmå=ãmKÙÏ”8®1µÐÅ`ê°ÆõA<ÐE¢43к²Ï÷�=t;UX#€@–”£ âär‹ÒD¥Òn’*j’YT® ãIq|^¶â÷ó:G6ÇvËÎiß@~TúÜÅ|`,vEñBcí8Âü2×5F Ô»+ã ¯€Œà”a!@¼ÌÈmiï±lH&X~ ~Áó^êÓwŽ�-™‡ƒfÈØ€fþKŠ(¡Ãcß0˜,ð– 'ÊàrÌ­¼žö0% ð¢ïm�&È$Ëù$K2‘rl1�Ø s¬6¿ŽSª¯ Ò‡ã,9$WzäÃhÈW¿wŒ&‘FÆ ÌÖ9Õ ÖÀÕÍìaiwù}¾q½ÞB,³ài®R…ü,ÿÇqŸ÷‰ÌŒ^Ì·Z  €±Õúwâì Pú³%Ò‰ã¸_{SßükŸí‘i⣷ëÌ íÛ—u°«ïŸe¦eéõ´Rv0јw^Vø|‹M@‘ ß¹ÝR¹çÄ€ÎäL“Õ@\²Dbk€-¦$XD¢Y úò´";>7߇¼HÛqé¹3ÍcNâÐÊýúÜfJNjŒ_u€|º–� X£°Ç´XjÍuêX(YŠ @ãzUOp’õ¨Xƒ¡¼'1xç÷Ò2ÍØ.`ÒØa‘ñl%‹N’†-:ÊX¦=ŽÒ‰l Æy<0ÇòI£”þœƒeüŒ¤}’TîDs>¦£×)ÿž25G@Õ•÷’˜cÕ�mJ¥IùÛñ=ÖuGÖ=‘f„J òyÐcšÙ}q s’¿rÍåóÈÎ–ÈØk8Îäw®‡î¼lŸÛtž4±Ä À`.!B»û�“?'ëÿö›~7ß»¿æ>2 GüžŽ}�P­Ï@XT6 ¥šsí¸^D½Tã$ÇÆ"Ð!û”‰U†AŽEèbFéÓ‘9æ"èzžc€f¾©µgMI„v2´±Ÿ¤€TM™ ­Ç^ú¯ÉÞ ëv'–G>Mìߢ/€âz‘ ª1áZ¶=sýô|-€¥·÷‡…š´búÝ߯ ·�¨çÝ‘[o:Ú÷~é8ŠŒ;=÷ȸÉÀc±Àϱ¦:5iÂx™Ï[+A8¡õ•%®_*=×þÆhk(ïs—ȯ1† UM‘ÅÛ éÄ£B ±£Ü_›N_â³eœ- °³qdˆ!6Ö3 ϗ│ßô#&«/¼h΋ÌA—´Õ‰Hë¡g=Žýµ/8Ýà©’�pëº[o»õ@àû¾æÞÿsÃôÆÝý+úÎ}ÿxø»qþÃÞãž“øòºŒO[<{r4–L›_¼y§Éñæ z¦ŽÅƒJ‚zߨ¹éú›ÿ~éü˜ÖÿÛêG¿øÀŠ×űG{ýbï·?¦ <jŸ=_¼ÇZà}åÇ_¼'ðêï½àÂýïZ:¿Ÿïýß×Ü´rÐó¡@ÃÜ�pãî7~èW3KçÓÞý%÷?øÈi'o>® \¼ó¹›þù•ÀÕ_¼è¥§\ö´o~ãý»O>ú ÷x/€Ñ/»óûwl¸åŸöùÔ·—~ÎÓ¾»ïGwý8p긶Û}ä³?÷ŒðèG?æð=> <ùSO¾áÀó€uOí>ç-‡,ßï6ß~Óäà—üå¶7� ]ÌQ2�ðVü+åµüÐÖçåû/ÿNëÀ/ùåónÚŠØXûƒCÏxÂGòÚÖ1å5Àò'·ž»ì”ôwù#€åO^þ·Ëw@é&1ýßøˆWÞ4X:¦û|ð^Ų·ŸÚëÃÿ´æ[Às󼓟ý^`½uønÝ?~ÀÙÀ[ÏùÇ—uãÒùýþÔ?¼óŽšCi¡U±øãì­«nÛ ¸ø^׌ÿç;ÓóÛý‚}ÿ¾ç�ÿà#¾÷0š•Á@ÆÖ"°xÚâ˶ê½Ûyóö›”© UY‹Û0(ªaåbd†d†H4t“)†$%²PÌËAU å™±!I'Ó˜F ³Hbze N€Œ¶C(� b±Ü Eƒµý½¶a¢O™"ŒYe »@2l§ü8³Ì ÄDæ™id†ùa~¼¤!Û'3Û¦Wz½3ß›à¼À{€ôÉ\™!Æú„ö4ãó¥€Åë åë Æ–�ë«@Oìw¿櫵jàsÝuíLúY¶Ìè @j¨çØ—K%.µýdƒYÆPc¹ë ³„Jûõ­HýÙÎ�—–{QrL±Çòþ€Wç¹1�eª)p]3?šyÂÆÆ*sL1íw?ÿ ½£OœOª!7ì2ß²~iÅu{(÷µ«ndÄiNV6"1|Òu3Õ€U…Æò‘vUI\q˜áînFÖ'­™Ãy"KZuÃ÷í¢'À@i КSûFŸ¯cú•l•䣌¸ÐÊÀâgJvë<¦æÉd`«(‘<rˆªð}[Û¿ç�°ìÇ߃KŒ!V©¥pØãIëSu Z&�2ÔßH ¦üôs*ÙBü]Û‡Lç¾|*7:þ(Eæ¤(Ë� Ñáj ÀÞ@òKTžiÐ ³„–fòIó“ç+°�7u}vj–ý–ÛÿC.8/Ö¤úsËJ€‰C•Líä¥$ÇY*ÊÝߌ*3.Ä€ =ÏP³Œæ¸èê•Õ±<¥»®[ö,ÀÉÏ™‰åß¼æ5¤0´<¥´“@„âp&ç|î£Rb¨Š§|§Æ8ê¦ßûbH Œç°‰”w˜ °ˆ�ZV Q‰[a`r?ÔsMŒmT‚gÿ(?!•D®£G4¥û|bù'™Á'í«RZrß0ÜG‰à<ù}!×—nÓ>Èäc`vÅ3;îwkÀ]�È”‰âî3±ZÄpUj¿¦s~4¸¦vn‡Ø7YÒrB@)ô÷-‘üL52€“PDxß8êŒã–:àZ¦Y6ã9$7”üÛyœ»õÎJ':eüÛR¯–”'·ü p¬„‹@C c hˆmQÚG˜¥dàh ¥ÄüÔ˜‚Âðb:)WÇ,›3åiÉúÀXQz> ŽÏv<1Fç aƆØgÉÀ¹ºÆ€Šo’w$Æ\Ñ©XÝð—­4o¢j}-–˜†ö°_2fYCL'¦‰´ ¬EiÇZþRe ;©çz½¢ô`Êo’çu°FH1Áós«2¢²#\p:Vj±Z‘ÆÌ›3ÏÏí> ð³<�Pue\“1ÖQ¦eTßKªëü íJf¤Ä,9‡a Ê—o¢ãX¥ó$6^fþQÃÖi¬Ãòú%çò¼˜8éo2¦äóœÌ—]ÚXªõèÅs”•RuçÝQÀ´ß›íûÉÍßÂ4VÇÏÙü×1¹–×Öi2„œˆq$mI;&äjPÜ…©äÝò°h‰ä ‘Ltu¨‚ A$;ªÊ1½<“1çÞˤ|A» l0+x ¥�Z^:ÒÏŒéFà™öžÀä«9°µ,ÀVô£”"_sÚÊ€’|;‰Ì¸È¨s@W¯45;̦Û$(›˜ú…ç’ Øòã_ï› Lý¦v•NLã$‡>h~®—ÕzŒ°@©ÕðÙKÓ˜]ųî1Sk©ô•)Ÿ—bŒ-•Ï´ü\ù} 12 E`Ì1żÁ÷L÷éððùœ)�Õ™S`[6 'ÀŽ@œeˆy&ØYµXd[Š%öüü¿ÎÓOʼTƒKóÂã6PPCC7|æ){jŽáüߊpÇN·ŸzÇO°d:èËüf÷GË>Vl*Î0?´%†Àê´üßøâ›N½y+F÷ùî}®Þvoh0[pSêß.�\ÿËëwúùIKç÷¢oýõ¯ûOÀ ¾þ‚«ž÷S�//®Ä™p1%ªâ8üºx;pÀqûÿüq»,ïwºõÍ·ÿ¼¡½ƒdÐuÛ]¿éçË—Îé9Ÿ?èŠG~øÐÆÁÚ—õ¥ƒ_ÿäÿ¶;dû—nw2°ì¡Ë6»Û¼w›½÷!À6ŸÛæKÛ|j@¹ìu—^}ùaÀO?zã¶·nEì¨5Ǭ<ù û;»Ã²í﨡ªí7„Ùñ!{ïú*à‰{Ì[ø¹¥óýí‡~»þw+‘=ÃiP‹Ç;cƒ”Ũ:¸æî}êºîÒùî5xÜ.{ˆt§e¥“z4˜è†¬®»Ïu—üüU[ß ®ýÙ«?ì±×ßßM€:éb8KÛ¿eûÉvg/߃·Ë6;°¼ö 5fìš´@ÜñáÛßû•KçwÐùœ»ûóe[öÏËö2€%†-‰rãßÜô¯7¿héüîó¦û\»-™‰¨‰ôš˜2äoi<g¬µ,úŽyaýØÆ@ÑN×W ô •1 ¡\=}J2Ò¦1•cj\9À"K%"0Û A©=pTcИ'Y²Ö¸2¹,ÐUm`,*)sf: ó†žW:»;‰¡Ë3Ô‹+5ø–|‚‡Ö`í¤R|âôyVB!—ÃfVÒPhɱÎꌻ&.ým0� ××óµ�VίöœÒ¶»Jåsd"æ˜Y0ù—lE†˜JS;dÉÌ4`2ãÊ~Ÿ%íâ\‚ROýåî71ËB̳æOx< V¹ñA€¬è$K±®ê‘ ”�.K°˜hm]ù#ЊRæh1&™K8ƒ»ŽÌ°¶7+ãL¤ìs½àuž!fz€7[ž~A£4o.`É€f–a5bŒD•”Måš ±_뀡Ú†ùýÒv\L ü& ®b̲9' 5ƒ¥à™Yeøk“0É´¼–©ÓÖñE©¾‘Jr@_€¬¶�*e¨­ÜsÛ\×ãû^PzRcIRéÀJõæ˜it¤¿ÇÙqC×')¤ÛYb%�]œR9Dò°Ö~ÂêAÈ´b­™%µì[Ü÷†Øb¬ÄŒu¼û˜iØjôl×ïÇðùçëâ_ÏLc¬3?qL©H}7¨.&þyò!—ywÚÿ‹HãŒs¾’Kc(éL*pÈ·Y"ÚïJÝ÷' iÖ埙 ]žß‚]=ä+ºhxÃvÞÙ&dI€Ï2L¹úº·LÀ᜛hàÜ µŽÎÌ=¹ª'ã`ì˜Sê· «VjÇ$: ùzÐQd’$½@fpdÎ’9– ל}Y¾‰\—fŒuq_X“î‚ÔÇ{>«™L)Þ×÷Ã÷\ç»î®Ní}P `ìºÒÞœ‰ÚNZ‘LSjÞSÓ˜¬5=øu—ub SŒ)¦@€<O¶Cûe ¦rŠ!o¤†³´Þ’™/dâ¥uÎĬ.,s#0§y¢v€Ûáº!üù£äz Lª :žŒ\¹ …E h¥ØJÕ½t~Ð[½�ȱÔíÀ Ì†U<Â{Ù7s½|ü|ÀöaÌ¢YW¯&&,à™õ'&€F€‹V�vø×KUw2sŒ½.L¡›Þ0­ç¥Fæ°axÅØkʸ·ózƒ´"¤q$À×·v£¢S‹!-œ†Û{îsë•®mì0÷Õœ¬®¾ryRÿŽX?ð&’ËÕk’ú³QbÓ¼'š_KÆwfxõ(ýK†¤H2õd|¤ó1¥‰³ù<Ijö³4"% »O û¿¥´Ë85š¿�\êP:#÷§vàJ0'ý=�€„\&:_F&) ñwd¼¤sF^ßjIí­é}îhêI-§IÕ¸bÎr~ Ϙ—sܼ̫ËeÜÎÖÞŸ ½'1›ê¨àc:òÚ)Š+¨3ëôzw^Ò†–áÿò{Ç.Z |¦óµkábhù;‘ ß(¡8‘zÇçŒl½ƒS�;éçì’‘žÆYØ1N‹NŒ¦9' ¨ë½y½•F84H °¬R‹hTÉBŸo'Ñçfn¸í¿¸ˆ… ëÀ+=}½Èôê‰IÑòë¡ë‚'êXÚû yþv/¶ÂŽ¿µ‰@ÔV0ʶ*Æ–Ž¶µ±Â\ŠŒ¸†ü�8@,I'VgWg)0f$5ã#,§Ä�;G€‹Ÿý}6†Xdty@‹’Žùo¼|ì°”ž¥€¶”¸0ä ÂÉ”:Ð |ÖÚ^!m°k“4®Ý`j ÙˆõÅDµ ¼¾Z_»ì;Ëþ{éâÞçy÷ÙûÞbÀw{ˆÙâ$`òë͇oþ-ð¥Ù¯žñ½û-ß.ìüŠ„9ÀëOôpê'WíxÕS¯ýÛ¥ó;ú¯^Ù}Á/€å×/{ÍòSa$f¢†l2H,¿aÙc—Íÿ?Þ¾<N®ªhû¹Iß²/a—£à. ˆl¾¸�a^EQ4B2ÉL÷LwÏtÏd&Q"› ø*ËË*ˆ"* ˆ    ;Ⱦuw¸ß§ªNUÝÛ3ÑŸïwþÈäö½÷,uÎ=K=õTMoº°ôÁéÏ©:¢ÐHõÆôεîüÃ}'LßšÓV^½´>0xgõÝG<�¬¹lUÖø=�K‰]_6K’ÓÏŸ»áÅ›WÀ9ço?àÑmÏÞºåÛ®³>¢"‹¤MVxRyO'Gb°ñ³¶ÖSçßýl÷°Î¡-È+Ã$cçRó€ì·o\›Ý\ÿƒ_Ôî:hê|7½hö™›<ê)�UèÏ–±ð«&dÁšUÐî\õ®·ß·1ÔÞûáÍߺΞÀNî´ÿ‡TòЉ*=¿Çs‡¾°® 7;}³Óge�RVFÆ)2k�0íþi¿öÀÔù­2wÕ¯¾é>h$U�HªAá»ü¾î'— ¸ò¨«Ÿ¾y©ó[ï¦õïZï}¡ú;Nª1ˆ'+þÅÒ¤ë-1~,?&0KRR”…–ruÆ-°ó'˜ ëÁýÀL'ºês€ÜÆ?& )'�u# „e- Iù†9¦�VDPl&R\s,0Ü0ËÏ|*À€H-.º ´ÀWÌ_3‚Ä•�,P˜“cê7Љ�lܾþF^üÿx0({F›¨’ÁZ ,–çúmŠä™sYärõ8)È?õùÚç9¶“œ®,#Æ€Si—UøÐÑÉ•®ÈbÇkü=Ê» Œ®4å=ÅèMª®œ¡˜oF%¿_1ý]•öÆc®¸ÿœ+ fZÊ8ˆLU_¾(:˪\àSHŒ®kV¡ùËXø* GÍTiªù/|Èüh]ǰ!]Ÿ‘Ò:v¢&/¶x'ù«ã±q‰ÕHê2£†õ„cƒŠbm!Æ4ÅZ ùVÕw«ž½ÏW L±ü$š¹B-ÆÛÓêû ÀHG�€;-uE<B½š »x¬Ã§¶ªw.ô¼:¸öˆmb�HjC©ØïÑ€Š€œŽʸOhX͹Htåç])’œmŒ ”\)¦5w<mªÄÀ_´ €[& ®bùd¬6³ ëÔÉSY–»ë12B½ùÀÎ@C‰Úc“j y ç²±&;+G}Ç´_bêMýGûr ÀW®5ÉOïïÒxÞâs[£Z± V@-†€Qt^‹õÑ+÷ bÐDÄ’Uù!·Þ° Шðc`ͬ·r¿.¹†ñ£2õCp}çeuàê¢È µ¬‹bu‚î—puó^\/­Å=+Ú¢â„÷ïuj]Æˉ-Ð+Î%W¨Ñ¸Tì*é�¬¨ñ.¢3!™@pUsØ0à€2Ëx‰ûÉp.S1V ׫Èð7±BÑ¥÷S̬.w1F¯_¡Å5 pØ"ù¦î=»©Â®óUK¨&ëlûÍŒ³AøÈí2“] ºv6(&Qü^æ¹ ` í@W€ÑwÐ_qÅFLEÅ;àbƒ×û Y„–äX¦ú:—Ôž`èÓ…eH3³b¤%¥àz1 .éDÎÌЃ�%uc PRzkòÐa€¡Çº• ð4¡ä@ó¥6Ê €Îa [,ãÆÇ¼i9@Š÷ 5aøh@i¬˜ÙeÆ­5¬à4ªKÏÆƒ2”ã™fžYËõð*á’y®à¯fœIê °ç6–(ØÈòÌÛÍå#1,�q»Jt=Hù–(«)*š©¤óÓž6t¬9:ßµ49Sã&?ÜêÂ�VõLQ¢ûË—Êeæ[—ž€^?ÌÞ* ß?3ÁXâJS1³ ʾ—¤?î¤ÕDŸ ó×Ò¹Ä T®ñô¢êÁß8g‹Ë;gPÀõ逨fÖ2„ÈFT”_ªÖ`9ý¸\�²šžç•+LRâJ¤]9ùq�õd™üb½+De0Ëõˆ. R½h2²!š*‡ÖÁhÂiaII3ÏØec2cÑh±¢+¿®ëbÂI æ®÷LC‰aÄy�Î0)U,3_^t^ìºûy£îon/žGµïѯÔþ®™­Î×]õ/ô.Ø÷»6U}];M?E NƯ�iôû=Î1½�«B É3à Z+ê:q…Ê+H+ú×o…�´ið ®“¹É¾šVà:ñâÜ/xÚSaŸ”ç‹�´= Þ/ŠEÆŒ0®Çå|õ†!Î…v‰®™v™û«,:)©#� )·d)#J¼\/ƒqAÂ>ýE1’"l?;êýZ8:­qÐꇯv=PþÚô³§]Ù»ÃîÜæî·>Ø�–ûu–Ÿòg‹!�¸i‡›V¿ù¯ÀíwÞ÷Ø3¿ïÏÜy;íö¶÷k_2s˵÷P­VjÇlÐ=¼{g÷‹Àåëýì¤?ìÜ;¿w>=ë›k|xû»6ßu³ý�,â ê~ƒd'Ðg?ðüÌîÇ”iæßÖ9n­aD×6NáÐÞãõÚ¾tõ‹w?9u~ýcâ“;ëݳÞß×½GÝðžë•«êµ�¼~Ök§·GsÊ—®tÇǦ.ï#kíºÿöÛA»&bˆ•»s±óÌõÏÞùÒÓSç?c‡ÛÌ8*(6YÆw’ŠVH>óãg¶xvpÏjM<¿1Ä6:~ÃÓ6|…Y´‡´pµ§½{çºö3À…O^ýÔÝ+0erÒÁì¾P¾ª|c\QÒA‘,éÅn4(ï¹äÞ­ÿ2u¶˜sàœ 7ý)bÌ‘¹Ö‹ï à]ýÀÕ[ýã@ùëÓ/˜6I쯻6ÿÃN| xãMË¿³üŒð[6ÈšÙ@Ònºì×c7¸ý†ûîæ¶ÞùÌÛ逷½˜¹ù:;¬½'ÂxÖßÜx"7¶<áUÚ kÒÁ[¾ƒ`–5ó@ŽäÝdã̘ƒxj˜)3 ó gAƃ0€°å Àâ,i5£‹Ÿ'ÅF8@D‹aëH6ROÓÆÅ–Y” D’_îo€Š_š!¦ËÑ�e ù 1€˜Ñ• °'€ µýëcî @éÊeæÞˆ\³ºÅ´/º:ô±àb?@&`³ÕK®–Ig°¼+É�ŸÔ/ÆJãú8 PÔÌ(3rs°o¶8ÊÇÔGb{Å÷ oÂ4“ëT½:všgšŠ¤I]×1gùfFÎj`W‰e€´ªÅuÿ¼�M!¶…À*fƒ¯�yz3ϸ鋊¡ÈXKFSU,ƹþìzHÿOçæÔì/ºˆëñ÷ÜX #¡M VP—EÞ!q­XŽeêÑQf„�ä’ KØEš4‰ÁE®™‘›3çÈ*�ÆÕüTúž“ŠQè)F˜¸&´ŠHj*vÞ"¥ÞW´4É Eò‹À‘¬hÝm¸ñ™Éò»0ô™)çc¡äý²Ùÿɘ®¹ÿ¥ ¼³m€ß ùGfš“WÔŸ‹1ÆïI¹ìL‡×Y®ø¯ôNÍçgòæ–Ù–z…]Æ ?‰I”-�0ìÛ!Šøð—-ÅH£TsùÙ~XŒ�� �IDATX$ÿë0ÀH®¯š¦¼*¢b˲%›tÞ‰óD`ÖYÅ*däP¿tÌó)8¶©e.¢ßS“lDî1v+èC¾Â2±8öÖHdœÉŽ»Cõ%€Œ\6¦âzÐ 6jP&ÍÏMv…jÖE#-¥þŠó1ÆäüÆçBF h]Ô#†+šÄð#ë£ñªÜ/V±HL1®•óŒÂ 0~žU3¼>qÌmX\½YqhS¼fW‰üÝ3ðÀŒ¢pÞæý”Ò' 3~Ÿc†q¾ X1�7J 1–O“f�xWìR½úò®Â*2##)È« »Ÿi:¹3¦c¾•4è:ºRl2¹@ºÖad6Îso“õO•äÖå•'Œ\ØÐú’j�ò.f@FýJ±“êI Ê¡–%ŶÉFÂ|¤\]u…1C±–¤Ü2 ±gy¦Ó#Ê2Ábì«y¶^Üþœo‚`à( 9æ”v5Fpõr ~Ž.ïP’þùŽjÀ¬ˆÆÏSj¸|s±“XΆ9UŠ®ù/3ÙD.*íR/HCbÖƒÕ·šÁÆû Ôƒóqí)tÙ˜¹* 5îÏR%¿1ʢԼ瑫Ýÿ pÎ[c´ã,…y™™ZP1ôÜwT'`®.±?ç!ÄcƒJ¬X—ù€]W`ªÛ#@?¡q=e Ž aðhOÙ˜Üoȹ½ûÈŸ«p6'Ø \æfcô72ŒâWäÏjv=©@Òçš_æe³þÈ8XnÏÙ`/RÓ)ÿåâz’.Ãè×\3Ê0³Ô8Ôãe’˜Xýqž%ý‹¥Å±§ÂxýIÃ(²ŸÈd*>¯©Ä1È89§ß‰È™dúå¤ßÆäŠååV+2Р‹û‡XfB1�f™q¥ÌÏc9Ï7ŽÙÅý“·¿ë]F†XdŒy My¶P¢Û ìâ12Þ p瀽"€Ë1ÿ\ 3i¿q]™ Ò÷Yò!Srí—òiŸ °òL¬O�&˜r©øïÆ›4†™OS¹fœê}¬ °7-»<0ÃŒKDÅ cŠó 0íÑ3ÄŠb‡\˜OHs‹ÄXn¯ßcòL³©b‰…ûr�KÚBðå ºÁÁ­‹ÅTYb±EŠ^èò� »ú KÔp�,¿¥üžòÀ‡~îÑ'‰Euë÷¦O=œ9ýÌSÏ_¸ó wnÿ‡pñœ‹_½¼|e³¾;Oÿ¦LŸÛïàö¹HŽÂS°¾‰95�àÉóŸÜèÉ­§WzéööÞ½óÛkb÷¶» ˜>»tÙôÓ�Œ¢c1&M÷®yïî‰)Ó&ïÚdhÃ'ô/6VÄã¯?±ÏßÚ'.ÿô{L߇~±ÃåÛ…º¥FÒŒŒŽ•P„üécŸÞë™ßN]§·|aöج`,¯9vG(‡-ÍCê\ÑþIçàWÛÝyÈ£;OÿjóVzÕ ¤¨ Ø+Ää ®¶=ñÑgÛ|êüvÝý}'nr7°ê:«½kÕ1%q©ïŠÉðø+úÄb }üòÿ~c÷©ËyÏõï¹w«#ío¤ÐfWŒå¬¼ñÊÈÎ~Ú¹î w.Ÿ:ßY¿˜uÛÆëC+br.N <gÆûÊ{GT>÷ÊŽ¿îß-é½|êà̫ϼñ‚};Ÿ¹ãê»_.¾öâí/ß8|yßŧß1u½>ÿ»ƒŸÝû �Gã pe­˜gfœ@XQШž³€+$s–ýp"|Ç3¨zA�̸-fE C+æc¬-!vA]òp,'Þ8±zʸF­³€M>&—g4y@+¶ß3—ƒÆ�~‘鿀Åñ>ý¯åêQ&¹—ª=”,¯¥ã¨ Èåb\ "ýA—2É»ì€6Yµz¼çÆCx?[̱Ø"PÅÏ€ÍKíJ’Ç ËÙ”ëÆ‹´Þõ¦ ’A7ÞRÏÔ“c€e;@sØÊ9Ž®H¦v3pÖ!yX ,Liîà[íÊÄ< 0c9§j™YÎÅŸÔ+MZáy*g”Ú1cîY¸)®t·€xœ±d)va'‰(æT•æûQc/ŽµØ¥b昽zt$lP,1fè3ó‡]0VѦòÚ¢ €W›™P�TL/¤ÒºÇ@[Ã]73ZÇe—Xaׂô\‡�3þþ;Æå§èR+&V¼˜ØL;L}_eÄy¤“:ï32¦Ä@Ç3ß,0“Y‹ûš3Š®í~©é®;ñ¯³¨§Ä@–ìï:99„R‚"mÜ]Q~£®¨S.é:|âÚ‘j$ ,ŒùäòcæTœ?øcÆA“¯ ™ Q-äÁ–ñ¬Ðì 8ŘYM:¯ŒRÌ®ØEUl…(Ž¢ÎZÀ²«Ã†s­ØÐ;ó^ƒ\'²«µ1d˜yf¿ß‘\Ž P ȵÃ÷Ƴ`™óƒ‘‘ÆõdÀƒÇW6ÀýU�‡ôì€&¹ºò�kZ>š™Ÿ"2µ)vÑ HÂûuq¥å˜c~½’þ°ÀFþò|ÂêÛ0Ï6Ä%^êÇŒ³g ÍÖcPò­«:k¦™ô›ÈÕ¾]YÚõVƒ˜A¬Pòó¹0–Øs‹‘Ã"’ËPüÉ�‰#ŠYl\ï¢tŸ“5ÌP�¥©¯Ã‹¤~•ÂXoˆ€d®?-Ó­.Ò"oÂñäD. @Ë YŽ‘W‚Õ qËë/ö|À�Y-º´£üqIz‰AD̉=ô'¡q €DýUÏ*#×§u”¤~Ϻ¸„ë1Pæk¯Ø¬00&ã­VS¯‚ä\©V 3ΕŸfÖZýIvçÃ`uŽ(ÀL}ǹXô¡U¬�Ëç[ä+¡˜’*v—Ì×Þ/Õ‹õY#œ¯Ó $×%¦"ï:Ñ%®?îÐ.^_Jò}Ž  YÄl @-F Ê3=é=–«czÈ{]jgM~Š9çÇMtíÆgì/þÎÃ÷Ó"FëwZ*õK)¬æKÂdãšVÙ"õSÉjXÀ1ö4»Zìƒ1˼‚†²±TBNñîÏ/\:w$&_hŸK™!æõ®>Õù/NÞð¶äæS^8U�0Yg˜!fô�C¬À/‚wYk\þ©qÄÀRë!oº`LqÃdcb„˜Y“ ] e5»~xƒë/Šï€Ð™¸ô@¢÷ âÛCﱫJžoE"ºb¾K;;Ð͹„”ñÏ�–i爸Óÿx‘ÑgB¨‡™&O%ÝêÔYb€Pl$sLÅaÖäÛõ¦ ¬e9 ´r~tÎ-éñ!ýª9Æ� Å&% R€ÿëÓOÓj�¨I]$0̦Š6)€¶ µÂß}¾Áe¢¼8)`ɸN´@3Æ"0v.Šb‰åß/b„]®\" ãò.—ß/OOr},S ØîsU>¨5Yq”-�°H,k¡Sœ�Ãû9€ÎÓnd:ñ`†p@{ÿç~Øä왳ÞôCôLKßÚÈuÇ}é+Ç|ûÍ@ÿ™ãW_x<¦L‹ŽüÅ'6¶Zo«=¶p5µ–M!È÷#—?²ýcSç;çø·<¹I Åàâ;žRî¿Ôyé/\pÕgþ°ÛÔùÏ~eö ›¼¿èNPˆ<ô‘‡vxdáÔùìöá펞u °î‚uO\§QœŸWl—9´-~á_¸æ…NU°æ´•7*­¬µhíï­ÅÖš”³(ÚX^Ê"íÑÒ£µÇV�Øä´îëÞ3ó�ìK<Ã'âJ,i^ÿà_Únêü¶_öÁñ-vG�læè$pOxa‰ÆÅC»<ü£Ìœ:ÿ]÷zß/7ù_`½ë¾6óI@+nƒë*YJÚ�ðô.Omýtx`ÇÇ·{iÀ³üõéçN» Øp|ýËÖ†±Éý[diö©Õö¿wÏ?›\8s³7×;ÿ%·véµïúþWöúö…@ÿíã{_¸.¾÷µÍ?±°Õ϶ÚoË#€data¨˜YMbÜH¬¤lTÃA6k&£¤�çØXÒ+©ŠË!çz.k&‘�/JqJ�™gV1ÀBWõB…Ø‚ˆ]ïyf–(\½î à¢ Çp¨§r˜Ú JV÷åj9xŸÜEÌ#c)–Ú-p+®‡-?ÆžâÒ¹V?•Æ[¾Gšm³±hï›$,å>3\*ºÿ¸ŸrŒ»3¾"€Eù´uû“E¡žÌHKƒü³Å"€Âò¤ü“E<޼<ä½²ÒîȨr/F]î~ž Å×Îr0¾QÄÜc«üÁx-À1¨'Â8bu­‡|7Ì,`JæEÏL&]OÕ÷UÖõ¤n¾Ã”ƒÇ]wx\æVl‡Ô#’¨îug™í߬O�z¸JL“†UX ¹Œ ¤Ñþ*k:Æø€¸´ R¯QŒ°&ÅXµÌÙ¨–ñD®p™Abë«Cß_“Æõ8Ê´X5‡¸rLFEöEáùq’ Ñ#@ûAñsêl `Pc„çÁè 1�„ìjŽ�¬{)¬5�ÐÉu�Èß2€ZÖ²@–y T=ET†¶‰µÅýªÆ‹Z|ì­8š˜Z©saÈ®ŠbÌ]‘[qâq$Ë&1ßRLš”‹Î%*ÿ4Z‘AWJõâýZXJûAm€ÁÌó%�ݾ—û5•˜gÕB Žš#œˆœÂûCt˜FFƸPTÌþ~D\¥Ì€ð.§ ÀÄù6a\GéØ`ôü¨´«Ï\7Xj˜ï%2×øüU3@U_âJ¬Ï\‡ï~0ž×Œ«Ñ‘£ËÇ>Ó�Àb+ˆåév†A…-Ì?‘IW¡X, ªO*€‰¡v]\”N˜ñꑼ^TüóÄte�ܺÖã˜,©ºn›z4iœØ”’¢«ƒªßÇ2ÚFÜødŠýôû˜Xæóú$±¼èºi;¼/\L Î4Zö»~õë®yNì¶{*,«à 1ÇBŠL?cÕ]9eW¼y†¼ŸÉôŠÕP®ÂXÚ×*È]ƘoìZJb¬ÑxK‰á]² F®1)ͺ³âá#›c@A±Ú­+ÏAú;âbˆ•ˆ17¦ú©E’n›~ñ®ÜÀ[r@kÉÍ_8 ††ƒ6ƒŽuDùq?çcKÚò ó:kF…/í³xýìZ½K.6—MÝ4õp}=´ÊÅô*Á2”ó.ĘqÆóú ý­øñå€À–‹qVsm*‰¼™‰ÂõMЗR{ø»âþ‹ 1{+¦†Œ—oÉ@/¥œ : %v$çÃåJ,JoLùи©ëuŒ(É<Íí«ƒ,ºÎÆä:¸Bl(@–] �Ï-‘z°Á‰mg#Y�Q‘_¯<2x`ß,]Z·‚Üj‘±¨Ç¹‰•e!-þ.›æ÷®�|Ì‹.v[§7@“kš¿ý|Z1ëVü=uëCHÓÝzEFÖê”Ùuò•ØÔîA"@ýc˜e˱ÀSŒÕjQÌ<þ5tÝùUJvŒ!N#ô|W3rŒÔnÏõOò±žd"SɵK eSŸ†ý"™y•ô Óm¤¨|qY ç‚Pž7ïgcÖÕa2(_t8r9¹r™IÊù¹gnW¨ ¢³¯ŸCzˆg§’•VŒfÅlc¸%þüO^{ÝÕí ŒA6˜©ž°7Ó‹2¸ß¡ÿW]$ªü¼kÄ+–ØTå¯hÌ0Ÿ¦ɾ*¾83ÃBÚÓýe¦ØôÞÔ, }{\à‹]'ò_`ß�¦ëà 0ý×>=_¥ š¸âð‡æ€ k™¼%�ÔÂÄ<NÅh?Ù4 ’èê#E ¬Û·îªëœÿÐÒ¾±L§©Rù¨éçO»XºYõ‹�Ÿ=ðàwð�|GâQª‘MlqÛI–�ùõ_¿ø÷�¬Ö8b×VçOÝÄ é‹©Û¦Ý¶üŽ3¦ÎwM¬¼aim`Ó[fq–ãê Ó}?ºoå^:¿ïÿ¡Ã·ÞJ×3ç´®3Ž¡fÛCO½vÜë¯Ï˜º¼·_5û굿�Lûá´%Ó¶Ó¥9„Œ\ÙïμmÖ{MÿŽ/o}öFç�k=½æÊkþ1ŠŽQÂ-Z�Ü9ÿ®÷þyþÔùnÖÙìÆ·| ZF1<”exPTÖ5cò¾sï[ùÁ� wùÂN{Ï<�‡%Ï%¡7ÂÆ°ê\£Qz莇ç<rèÔùî¿ñÇ7Þr} ýàŒ]Óoë;^¡›ÕôFmÝîzëžÿ¦¥÷}cä>U*cú¹Ó®–¾\}ûAÛ�ùÙ¯ð ùGˆ ǮŲq¥˜–ý¤`®Ù’_\$²§¸Ê£|šhÓÁ+•Ø=€òq¯bf…µ�*2¡ ßµI\-2 “8�Žc<¥ô{™/&?Rçb‡ ðÊ /ËlÓÌ4ý»Ê¥p\‰YK†‘Ão cÊ2â²ám«A‰Ñ€§Å …kAžã˜^-zŸ€3fî0°ëK@[JÑñ‚€-n„ñ%ù´=³Œêצö8a±�?>È.ÅúüÛ†ùGóY2ûƒöhƒ:ÊãÌõÏ(ªgÛÝ—qIùÃL@9 Wç`Æ•sId ÈY,ã)ŒëEÑ%¡ËÏ�HÂDË«ãÓã35åZ—ñ»À²aÖ‘Ûd¡w(µkÙù³Øß}ÀÏXžò|ã ^"£&*FYa,)*'pAÅõ!·ßÊOä8˜I•æ3v¦*d€xì4„™eôE†•24ß«»xcÎà€Äîbƒf%†‰Æ1¸Ô@Ä pqÍ&ã—!t�X˜ºäÇI6ö”BÇ$k‰ËCŸ:q¼ %ØBR·4ã¾Ã¼ÓTó)ǎѽŠ-Þopû;³Œ ‹b SQ±"I¦ˆÏÅêò€™ŠñJû³Žeˆ%ŽK–š= èÿŠ¢Jö̲1͸¾#‰±ÐaUt¡8ÊÌ0zš£ 3Àˆ!&.SØ:ìr0”Kç‘Ű�^Š^è”B×Hž™cñ{Ê)0½KF“ÄU·ä'—Ød¦˜Í/Æþjk¿µ£É®þDaÆ€Û2[a’‹b &ß;3XXÑIï ÓÊ*ìF³y�Jø¨ý³(Î ˜b‰Î…1i©<füD¹òüÊß=Pu3/D€=òÌC^ªôL^ATùjƒÞðµŠÅ@»rä÷m>ÃQñJõã{b‘g~™uM1±ÌKQAÅŠ­ªQ„1#¬ãœ©bæL˜|›²® GbrÑ_fV5âÈ9ŽRɪ}K{c‰±+âÕ»š“kŒ%d] ×ÉUadæ—Íó9¼ÔÊÜ¥Œë]}Fà(|'5ËH—|Äc1ßY®.SÃ|gUQ°3ƒ5•u›úîWÉ•)$ÆR`RFŒ£r¢Üæ…ß…Q¾®E+iA3¤ª&4EÉÏÏaÞLa\(2Ð$Œ¤8_v(6÷»¤"†¯Z…8tD‹ê;Bó‚�9ý’uùÇÀTÍ”ÛU@JÊ=gâÒÖœÔ1Ý|¬Ï3¦èöˆaªEF+ò¹=ÌøÈ¹8›L^\¿¤_�%ÑŒhÀPÅ„2€U6¦�Níò°$óÉí;Z$ç.Ja`QL0(7#+Ô‹�#–—´—\µf#ä º¼­ä˜b¼.,#)—¨MÊ?MÍ{Âì’ú“ˆñh…ø½Pç]dà¤_ú‰úq¤±‹Æ>cˆé»X´ó7œ amh¢ Û’Aä\ñS=êô¿:—«õIÃ’03p€OÞË1äKe…òÌÂõ³¸úÓL-‘C׺\ôåD&ÇœŠ�ç@Ï(&2²ø<"û^fÄ1SmË× Ùˆuݧô&†AŠVâòå|*ã¡PâuTÇ@+þ]˜„f)—…L&-}_õû e^‰ÓÝcøëc¶÷KlqS¿lL\D½~^•ôê_ï*‘æK1ØsáÊ0o–§L­1�*yRÊ3Âø÷ÌÅ,£ù1(­Pb�­€!Öë÷Â÷¸|¾î•_¯Ä ³^À¦`¨õJÓ&½�¤CX€¬˜¦]&¦XÞua±«D |iW‰áùKÐ+é|u¬0ϳ)0ÄeCƩÖŸìòÏXðtr–bM$:2Àª´ñE€x íÈ-ä?ëbpë¾·^{ûãÀàIõ Ny1ßÔ÷¯óö¬û?À{·ÙüµuÞ ” €×fÞøÅU>ûƒ¹gm½p\£¶ÇgÖ®ßýÒoOü˜»ÑÜùŸ8˜Þ7í™i‡C/G sÀȃK—[fܺï¯Ã”©sVç€Îöˆ1Ôï[v5™-�^Þý¥¼¼3pÒ‹§~à¢?NïWß|È/?²°ÒßWúÒJŠR.u=%[Ë€_|èÆ¾;WÀ…áf÷oöüœ=TEñÁ1Þ,0¦šäj ›¶Í´7OÿÞÔåýsâù·¾ò{ Û"Û2û€F´g—‰�€FPX=÷çŸ}~ àøßŸú«Ë¿8uþûœµW{§=<<É®/Xà*ºßkŸÑy/ð¿o\»åݯLï&o2{cã3\/6³º¸Þ®ŸÂAæ”ìd,~±Ýß½sê½Ù!›}á-?ÐÅz]\8…RÙ…V9™�þrù_ÎxðWSç»Í[?ùömC›½ïqYøµEÖ÷³u3�·|ñ– o¿<¡¾ì”ûóù¾³·ï=sðÞ]6Û:ï#Àë*`³=6î¬úqà³×îõüÖsãö­ýü3G�×^zåÄ‹ÀÜÆÜƒ>¾0í˜ðÝeãT'²ô•X>)AâJ/(vÕÁªCïq쟺ÚSX—k4ßdJa, gãú$*è‹-}#Æ×�$––�ka"²úÓX$'ÃÂ\âçZ̨a�M-³±DÜhÚy×"ñwS?Ť1 DD@�²!®Êú~2Lj顜£r9(ŠË Åóê§6Ƀcµcj@˃7:ÙHø=Ž 4ÏÈáú+K®¶³T+Ûþ´®#Â�˜0žX]6L*aP17tf<qÿ.öÀ´bÈ"ŽÛ|½D~!ÏÅq£ €Þ7Š@i·šÏs®>PŽö}‰ùÆã[˜‚Ü>ùŽZ¸0€Â ÛcÅŽï¬â7´>}—2.Æm»³qÛ~q­rÖ‹˜DI5F‡”ñ«\% }0a8¤™]¿*׊hÉÆ=ÌË0Rl°NVóíNž6¦¢f8�Æ¿[F‹JZ¿Âxl&Ì(®ÉhPôEf+¹€‹ùÃ)sQ×!í3ªÑ%²éçj˜ÖÕ¬ÂÌŽñæwÖ 0òiÐ_¢"¥Qg—U”dŽu�4ÅÕb‹;k�Æ@]t(cOtըܪÔ;e9¹˜T§pc&šyÓq�X'ó1qxd0ÃÌMY08 …€"û‹þ6-ó?ÖO�½ɇëús0X2¾éoa,³ž|5*§“YE»È ɹœÂþÔVìú‰Ï5¡&%Ú÷—ÄI =£øä]~Åï×ÈW\u7å»Ö±Ê0†_Åô-ïÍxkä-ôËÀšqM PŒ2Èþȹh4ŠE®Ã ígæºvÙX‹~qhÚÅ 5ž:Êõ£VcªÎõ 0:„ÖÕ)M@Tl,ŽŒ"éf„¿f@®äRpŒÐ:×Ã1Í`~ç}ňµGGìbˆ-”k…ûH ú«´®gñn©üþ°0Ãì¾`‘Ä”óë¥äŠË늢…÷#ÃÀp¨Ø]Ä€ í8Ž[“gü¹zñóÜ/¢øbÅ¿�»:•â÷ÀŠOa.èqYRL:­ÐÄ€�Sú5°ˆäÏ¥U!ÑgÝ\æ]’zUwSb(�霟w„1æ\Ê>„c�ÐD¿ž²|0óröŒ¯lÕTQ X³®â" •3„p†D‰14ãÊe]Ö²¢—cuåêMÀ”ežÅù;öƒnkÞÅ í5V§öç8‰…µÄ%ô·¤ï£¤9È…É»N,fŠÁw‘9ÆónUúƒ=9Ùï!Œën8ô%äb †>e*V–adêsˆ„ù™c—FÕ˜”]šZFX‹]Ò“u³ÏQ€]W‘Æñ‘ô ðf€� “ö– PÛbýÌ„©3Ì›$ÆXy¡½ ª8l,L=„u ½ŒâíQ~ì‚6Ê'ÔŸ¯»f¾ãõK»Àì³ßÜÑíçܦӼ=]ÆÅ ™×ÃÌœ§»$·†¼Ç.EnžÆõ¢óˆpÐ͈Æ�Ô6~ELpÞ–B½µ @’1¶€SÀbÊz3ïËy):(fÿe�(0´€ZrÎ2€NŽée\6æ�´ø¼<þöbª±üìY�¾8.DΦ,í‚ð®œÂs°�Y%4 s+i°%Ì1«Ÿ‘l ë¡…æÙRbÆ/÷—÷ˆÃÀd`=ææ_Ϭ múy1€4Õ}tùr \#þT¿·¢‰óéõžúÝ3Ò ÛÃI\&f»Pdˆêwh€¬Øâ´§Í@ÞE¢²�Ë»n¼„�²©aE¿_¦î¹jÉùPNÉr12HÂÁ*º:´®tªÎw®l…Ù2™-¯éFô¾Ÿ-�®¹òàŸ­ |nÁÑÇžx p÷cxnVÌ´±ó1Ýû›À~væ[ÆöÎ[ãìÿ^zp×ooÚúô €Ë¦_øÀ ǃgTß3ïL`÷ëw_e·½™ëü`íkB½ 7"ñ8œêûB“Y`�� �IDAT¯Ž¾rÄ«3€«ÞwÓôòî«Òo½ù…;²S0‚«îœÓysçÝÀé/|Õó_îúÍß~öÒ©óÝí7»e;ý´¥©ƒO–�/ìñü%/ ܼÇ=>yÔÔùÍŸuòÆ[ ¹c¬Š”øF!Â×MZ h¬yËš¿Zý­S—wÿu¬üÒÕÀC§ý}ôំÑb‰(€¡ ¼vÙk[¼öpRù¤ùg¿x¢úü›Ú“�nåùýÐéÙ–Nä‰\ %-²Ü:Àã#O~ã©ý€—¿ò:Þ8¹w¾«œ:ãõiGëO_Íu ];J¬­X#…ïóŸxþªnÞåžw=9†)Ó&ÇÌzøÍ ÀFL3‘G°H.½�üöÁ›ÿr÷ Lšsþ{Ο7]EÔA+”C–Ža¼ò™+_ýÙzÀç~rô'ìÜ}Õß¾ùÜ{c~ËyeïùÀÙžyãâWó¶;çž%ïîšqÓ}§_\¶åE¥ã7†¶«®þ €Ý7ßýçm3›ùÃu>½âK_Sš‰–5É…÷_š˜Ù$kŠ¢5¨“#`XA—xŠQÀÿ2`Â� f:å5&Ÿè P\º‚�"TVYEKê\9¦>”Õ œ ~CŽüuT¨gHc€ˆTrìŒ1¢ø�"Œ/]>×S¹Š¤ç@1vëª~ P±åX/ÕiÚé6^´qŠ×YÍ^KýZ=òå績6½bd8àŽKò/ã6-*/täòQÅ”³ãCƇ9�°Îò$ °ÎŒ.ÎÏ�p4n’EY…TŒuçû=üµ±Çbÿ¸XaùÒ_ó='ƒTÞb¶í8+°8‹�8b¿d#™v-§¿+  €FÌSͧI&h~Qᤚf6] ³©­û“ÆçxÌíp0×¢ÀMF³y@Ö¤™-MÌвê+B£ @ @—Ãunh28Eµc°ëÂàZ¦š „kÊ8†K3Æàd׉+,�K,8šýáxÜ?0³„™g¡žd ÐLZ&¿…°®±t¿êÇ 2bp‰ fb¨“Ì8cƒ%†=Y¾ŠH@FTüš}#ôtH �Œ“a€bz…¿ƒ­W~ yPˆLÃð—×ïxŸ€Ç ¡jT˜™z#á˜XËôrÀí¸*ŸÆÿu.³Sn—‰ Æß©Ì Ð6j\æÚËã%¶“b)»Jt.´8ÙXL¬°íX…®ª÷€{Ï5Uóü¢¨ˆìÅä ýhò"£ÁžR÷¿&ÇJ#WòUqåT‹¼SåJ¾ –sÍÖ‘œ©}€N)ÿa@Qñ‹ SÕÞA‘gÊ. |J;¬+̸}et%�ùšœ@\“ñÏ�˜í/f¶Å;Á¤00°®ÄY1Ø”¿œêô·BÀ 0—ÌýTÊ ×ƒNñÈ)Æ©E` -T²ã”Š#¤PŒLŽQHt*årlÒû£TÔjæ¯ú˜”GÞ1&ŸwÖÛ±ÜþÖ[r‹c²¬@U\lYà„~MåÑ%ç±ÁÆŽËòxùFæVP\ÖØ2û ¸½,÷š˜IÁ1i»r›ô–à«Ý ·Ï¯ñwL+òýˆoõ¼úît,»¬aÌØÉFÄ…Z�l" Äre !2y^ÀxU.Ã3#BCæúÛ4@}‰ê£ Áyìÿ¯Š<Í󴮨˜b‘y¡c Úktsú>tÐ1̪dP®›Tÿš+×`]iOõ«¦Å¤Ÿä× ‹rÉ1‹Þ-¸J£•'[\.ƒÔ} ”cß™úæëî)ÙÕ` i�YÞ ñ{󢜲™÷KجvIÍŒŠÓrâu“™‘u'ç: âÌ ±Î�a¤ui¼ÛX_]5O«˜u •ðÒ?x}.÷úå{´.»vÜBf|F· Tò$±þê”_/Wòá|G�ZÒ†3µÌ¹.!¶]8€@þ[1óëô|ÚÕ\2è˜È}Cd$¹1Ä.½F˜ÇÑ`JïéÒÏ1ƒäyÓÎþ3ÌôB‰€f*±|J¢?èšõ]î{—} ËÚ‰kH61 ²®ÂÃHTí'ƤOpŒ=rI(ïå\ò9WêG‰€^qÕhžÏp±?ùw§G±±¿J ´Eà.|7™aPF&¡smÙú–�®KãÚŽÇz%ÑOHl3=> BH0Ãʸ.T@R¡KÃIî÷zÎ?*·WZ!&× $ï ²0ùzNc ÌÄã˜aÅ./`Ì[êýÂTÄ›[pŸ×ûʵ-ï’ž 0fŠ»Jä니!f5QQ‚¸ÕA”£%mœ(:êºéb„i…“öL®ˆžýþsÍççÇn5|ýù“tÜœ¯Îùè¦�Óžöõéϫڕèà;cHw½áàzóÁ~.Ø8[¨W.ðØÃO, §“ûáù7}8÷kçlúã¸ÿ¿\ðÀmÀ]'ßõÕ»G€F}xø;7ß­žwﯿ>u~ ~tøçw{ðæ¯mÜÚø@ÕžHôȧyrEbm½ëÙYÇ®ñ~`æ;fÎy�¶$nF…oPM¿u`-Àjáz£?mø —s~¾ÁoV½bêò+í¡?žð=àW£7ýæ7ãÀ}ûóïÿ²6ðÛ•~óÄ﮼­ïúñW€s¶ºô}¿ßqêüÎO>y°ö–ëܱÖSÔ8´äô'îôÞ©óÝg§Ýîß2Ò¿”)þÕ–KÕ¬%®]È…bÒùÌ£7?vÄ ôÃ+³N\ãýÀÌ+ÖÙwí/!�ƒA±×(‚c¶,^þ¯W.{åzà§µ_ïúà¦Îÿͧ¿ùÄ.�rŠ®jd$Àsg<;úÜ—€cÒáöù“læçÌšóô¦5`Ú1Ó¾:í¯aÜ…n\°K3ïÊ%$q…—yW�ebŠI2ï'UL�(GEÒ‚Šd]rŠK5åê-].+ìEñqŒ±JE·×*"°bë•K½b“EæUPœe­B`£Ûaê׉�I�¶Ä… o4 a†•î¾Ï®ÕŠÕÍ£@”W6"ïùd qŒ¡ÞÏf3¿ŠCŠ¡Æa2˜µ8_ª'§²=0ä˜[¢rT¿Ðœ.QËTl=Hý?"×þ¹Q_Ž€4ðꘊ!¿Ô›‘ùÛ^a�Ùvˆ«Elz׆žùçû1jœ/]·ãcqtý`¾ŠQàÅò8æ÷ä{äüùÚm¬ùmþnÂóüöBXF"0Ïóq�ìy?�¦hñL1¶R90�“ç+qxÃ=®,ñ–8ÀÌ0€8Ƙ�±<ˆKÇð+Õ·“¹ áÂøfè°&Ì1kÈÑ`@‡Ç‡0ªø�· @#®Á•¡Ì¥öü3Ó„‰+®Ã}Ȫ("ùÒ51¶Æa-tyߦvY̱…–Á0TC½³º1‘û�cÃ-nç¸�JuaÀQL4a®U€A@­o‘ái<¾^¼ßªÊ¼5ê=°\ EŒ£$ÈØ˜t $¹X,6Ë)Ï8¤z…qÂãÀï‰Õþ=#°Gãb1Ç$�S�fªÿ€”äºò¬kÅ´�€X`Q>–q¾æˆ ­Yà‚±Iù(f½ËÓḺ‡‚ÈŒèH ²0^ÅE=»Š3.žRð—UÍÅ,(‚Ê# l±ÄŒ1 L±Kh~™*#J¡ªb›�t®êŠ«½QªgT°ZÅŸ�‰ ë§*t¾ì¨{€vFꀳbt€æ§p­€�šÿZî:e9ÒüÇùH~"g �¸EL±Aq9Þ[$�Y‰ÚPgY“+ÆVs–õ”Ÿep±‚–Ëé—/û³ãþòþ]SÚñŸæ©Y7|,0ÞÏE×Z¬Ø3ùªÄë6u ϲ\™ùÆýÚ¢v¦FŽ:?ž'ài w:(…!s)î7H!Ï ‘®È™cØ1 c…ï¥)�0×K»- PÁ.©¤»t€GKžg`»mä‘gP!†�ŒÁ¬‡²ïW�R :Ö�.¶Ƕ  ,‘©,Ï{¢'©�É ÆÚÈ9èUåšØ…Y32}kyž"À‡û¹&@ zÔ“Û˜Z\Ï”€-Öp=鏨‘šÇ€‡Ö%ƒ¤×*0cñyf[^aí\î:ƒrXB<Þ< g ´¼ËËsN×*5ù€Þ·1‚FÂú#ã«›€ãµ¥Ö--OËìM�Ò19õxÕ® ÙeaVÒcì"Ñ…té¢Cý )rÀª0Qt½û¥ÝÑu]ª�1jo—fJ-Þ ³‹F½çW™iEïS¬¥¼ü*úœ— ºu¨D±Õs/™°�Ís¼`!q1§S}ØuârªçòÃ’Þ“e"O7ïz Èݯy=‘ÏǼ'Œ!>_G&”3ÀñùÐŒ21P´ /˜å¢„sŠ\#2 áUf`I9†q¥V_ãÁf9 eÑð¤«ËÏF,sKé¸? éÏ*NŽ"9+š´ß{áÒ­áòXa<Œpm##Ž]¥BÃÖn25°)®9‹b82“R×c&–r̶¯’”¸Ö4žz0³&ª¦Jìq…�-.· üBàlêõoÅ"ó)ùçú/¬üÆVY–9f–aŒ¥=0ÆÉ3Âz%û\t¨¯¹Øw…ó×.ýèïE=ê±Ú·v_ζ’jÜ0§yú8ʱ°Á!4ùÒ¥ØIU‚Hd €l±l0knË×@ Üÿàý;ÿõ`ïÃ>÷\kåÞ¢Zebƫӎ¾pЧíp"°Ù¢·}hö‹ÀÌ­Öm®}/°öqk]·æÀZ§¬½l­€5ÞµÆÞ«_ à)<•|ÑB‰‚_gµpÐN21F_á�nøÕ ½q૯-zäŒÇðÿ-}àÊwýÏz‹€“šÇ§ƒg«Î\í=«| `ÅBF�OB. ¯üû•ýÙ½À1¿>ø¼]zçû×9b§½€#>{Ä+‡®~ÓL°¬IÉFÆ$¶ƒÚÄFµsNõ×®>êúߨ±ö®sü¿—ϾìzÏÛ_†ßÑxè˜-€ô‡3Þ[þMP|kÙ€c圗ϾèÇÇ­tØU«õÎüíýû~j:°Ïûž¹ûgYlqÎ}Ñ%ÃxP¸_ù©+wºö‹À1?Þ{²~øú ‡|s§eÀ‘?9bú¡·Ó!öJPX7àÙÜÿß÷ÿä¯ïöºìs÷·¾Ö;ßmöxÛk?œÐ9û,½ HîHîN¶ =˜”ï ¸»ïÓþÝýßöÞîóÛŽVzç»Êi3ÚÓŽ¾ø£/Úádàm'n¶Ëì—uwœùÖµÿ¬µÍZ'®9¬½æÚ?YkXý#kܼú%@òÕä©d‚¢«@#ºÈ&€V”ªDc±ŸdE*€èŽc ÄÈ –1Âù4cþ™Èåæ.Ìì Òh Ð~gltà 0Þb€ž‹®Ùz�”´«*ÍäˆößõÐnQäÖ©¶˜ö±l~^!Ò»”K©_lâûUŽA” X98תñ=fœŽÚ|âx6ígÅy3·áwk…fÞå�Šç§Àð^.z Û+ C*§Måp~Cî½á¿{`W¹°3ýÚÓ¥<×1ýû-Þmóx]HãßÇ<Z(òæXrA¡Ô @O/ÿqþ¦}ÂܤüT,%ÏH† b$&ü=¥ü;µÒ¶SøR¶¤äñ&±ñLûT=ù¹ðVtõhò­:&cÓ}·‘ÑåfK’c‡äÈLÕ; ‘$¯`a+€Ä€C˜Ípã…ºi ¼É¼ÆÏ§ˆ�»ÈUù¿Mb¼-@(¦6€…I&?Er‘’Ü+~Ð{ázœUqþ õ$—£CÑBÖ)\:$ß–¸z[$ðÔ,g2Ï›¾ å2 C”lˆò ×À\L�ñ"pêAQòIm}£‹Îh¼e‹ ¾ã‚b¨� d0À�¢àiëv%‹++kŠkÂŽ–šo3ri—T‰±Õ! I9ðÑï+K~—¸Ü°/T mz’ «:âÒXÒ¤ùê~¢z‘ /õÀ@aR•òM9YÍ),]9Ù¸¸DçØÆfÝŠ­Wî,M‹E¡š)cûK,ÆIÑ]Æ[F—™·¹Üd¡º“Ù8Ì<’ëEÅÈ`#»Ökf}ôœŽMÇŠ­f°èOˆyÉ羟T•â{PÉ!|$7ú]{wH¡X“}r9~7Â`V1iÈ%6Ïð^±S§z󹲮πÌcuº¬;Å.+*xÀL€?­èU.vÉ@+æ[²¦‹yûŸN.HQþêù¬)@YP˜-¢˜3QN<Îy^dƒ ö”Ðqò’~¤öä˜T./G›´k½IöQYdFÕŒ\(†XV‹ýâ<+°K±k#Þç3Ó½f™cI•�V]%Ô~>WEvƒæeh3“D)˜ÅÇ„0¿U> ¹Õ±ŒŒ+6ßßÊÅkÒ òÌ*F.ü½†NÊŒ¸\ž‡à*10Ðêâ²XïS½»âÛöEˆ�4QCˆ2 ÞFaâØ†ÆÀ¯ûÅp [kƋ̓äú´a¾³ÈÌ«¹ë9…&»f­Ê÷[q ¨8´ë_ÝÑ ž ¤ôœ5aC“È +ìWÄï©Ër¦+æYULl׎[7Ø�]oÔž†qÙ[ƒ3 éY¯âþãv0@ÕAz„þåPa8" ñ1jäÏrtëáˆcN÷ÓÉ´DßeM$V'ˆ:»ü%ù„y6¾ fm�ÒØµnÞ£ù#bP!ë+»Þ5þ¼þ(\²bè `îÛ˜˜#±†dÀ0BLå.µ¯aFÇ bîê“Ì côÒüY·.ᥪ]çä+ñú•œ!DŠæsšIõ¸.®Ak #Υ⠭ãQÜÜŸÞe¯]Ÿ8W-)éuM¿ù1Rü\è’6œØU¡¾ 3§Ã{#PŠÌ¬gX$>œ\b, "X„Z8h'ëž·F<óJêË1Áàɺ¶\ÿœËÂ’Ô`ÀË~õæ\<~F¼‡ÀF¨}^~%®·—\ÔŸ~¼ÀüžscÀ™ö2Ëù³ ÏÁ@ÞåÓåËåi9¿|Ákw` Xi¼| >bjê] Nêjð?˜V´lý[õò1Ì8m´þÌú´ñ@¬ó1ÁFˆ®{3Ʀ²&Îæ3¬×ûÌüº¬G~EÌ0¨ûô|ûÖ÷!ºÀá rœ-o•¥¶±T! _™³þÂAj!¸Y!B1º,xž^ï™cžYØñü¹×/8ù_íÞÞiÛÓßqïºo>¹é>oÞi9°ëE»>ûáK€5^ãÅ5–…z™ ìÕ¤¥7§üò”s~° 𾳦ÿ¢Õ»œñÙ/j?`áßFWùñEÿ~}7+o|ߪ§üí„þþ·ÍÛhé†ÿ€U°ê-oãkŽßpâpÖIá¶oõÎÿÔçÇÿzX?°Ó‘;íð�o©¯êf&ÛPzÂ]wþ§óƒî5Àâ{êÄÍ€ó~xÅywÝøŸëGN{²ó»6»¨Î­|í¨�«ÿ|õϬvÕ\Yê º6 ŸzØøýޝª¾:pí?o¹ö¡o÷.çVúÞ+Çþx÷W¶z}Ë‚¤³�*L±–:X·ã´¾xlüÕ“þœ5~ñI·ýz’~(?w؆ÀNóv.í°§‘<·#eK}´ŸýèšnØøúC¿;{ßÞù~s—/ܱK8|û¯¼ó#IŠ’ŸÐAŠ™ ÏŒ<}ì3«�Îæž¸à;ÿ¹~ÚöÂwÎXwðÉ¿ï=c§ý]Wßeñ‡?¬ùØZG¯±$*l8¶ORÅ(ÇÎоýY1ÔZ,±‹DV)…ÜY\ 9À¡Á÷ù=ʧE×uRˆfÔ•[‹ÔÀDiI¬Ñ¬H*ö{Róä÷d"<ç õ¢¿ê}>žCçV@±µñ½ÕmbÐàj—ÃåV¨~)µÏ§º{¯ð>ØÂ:õ!ù@——Ë'ãÔ÷åc"q;U×ýâå-–ÛÛ?Rþ„ä/õ`…zÔý}'çÉåâŽ!IC,ŸêErQõ“ßyÜеñ-ŸTÈ…g+tžòOµâ0kKĤO,Û¹=|_\K±e +ëeä¨ò·ý”oŸD&H&�´C 9ù'HÝã”5ä8˜„�ƒ¦UT$ÕàŠ*kZ¥Œ«YhVÃ,1_zô“Ÿ?:RßP£QR0P9uªW‹,¨+tß#.ÏÈd‰™T•‹XRt‘¢LÖŸl^GÒÁ…l¥ðûÉË4–«\Gf5øØs KIñÀ€õ„(È›ÑõM.nq|Ì+¸RˆT$ÿºV £E=Ï€NEv”aýl‰Â».ù¶Õ¿/1†E@=çbϺ0dEb…rj9…\…öKuDÆY@Ÿ|—-©A¸â÷êt]`;_döãUð~œ]9Vè:2gìsÜ{âú@dzäóã~­›ç:ª}ºþqßZw¹œPï…N‘éæ# 붉gb÷Ï€l๼pÍ€¬@ ¡Þ ÜB\iŠC=*¯’×�âë4>¸•-à HªúzE~•¢”¡ˇßËyî-Ë”o€ç”ê»]“FCó¾Ü h‡œShCR¬gfÞàŒ 3 *\?2°ˆüu”hÆÉÿk±)®\­Aš?ɰ'¶‹¹N€WU®ƒ|©òRêßô®!çâÈâpD­µ%¼_5õ[èú\ß^ã”®»rîÎqFÉ`©b Ârã\Fu#÷&­ÈU2äàu²KÏÕ)Ÿº÷h0…‡ƒ…²rŠA %q½$îadäÿw• �,N�¼È¾ &x¼²ËÝÕ—Õ… ÉP¡•Õmleú]f3ò Â×]™7R½�»ì•q¬ä€*f"¥Zðž,š,9Zù«äòØeè&`bW^‹T”®ÀD7@¡ÔG•U.DXÏØÐea|•=Ȱá‹ìCô|Üt³‘ª(ÚŽ]¿I^óV废ä~3Ïôq.‡ëü<1£‚G=kYÀ,¬løQ½“E|Mó¦*_À@ì6eM»n°‹mv &¥{C o(BL‹Œ]wÅà§IÏu>Mò ødQRgCuýTV§ùŸÇWV8flpûš^®$¿®¼GLþ` @†AM%žïLR7¬s"ŸÅdxÝ%WÙ°ÀDR-VÔgMZºQz™7è!ƒ¤fO²…QÖ„_WùËçXšÖ€B\êÅþ+Z7’ª>Â!Ç`Èê2âØ”Ã¸”ÓžMØóŠv 'žQº»-¸Žì’Wì9 õòT£žœ ï ÏŠtè:¥Ü:zž–XÓÂ4šÚ 5ä[|?«ç Nl�žk ChÐ{Fè¹.‹¤Çó‹b}ÅúVØc‘fJeMbdåõ9C©{Ÿ2P)r™:d‹éü©æ?Çh31ʸ}ÒîÅ„uEn]·¾æbêÚÑ@£±)ŽMÍlÍõTùÙQÔŒ±à40–TÉ0ªIÀ#16“Ev½ý‘XàËáï£+ß?ço˜—œO]7Ç$׬xùÒW¿œu7ÍŸqzrV$ý[ÀX/àé?•ÿTù1ÓLÅ:ûiÑsü»Ä&²Ì<:³Ë¦Oš«˜ÅkŸo0Æ./w÷½ëÄ©òñi¯Sl?ýÜëê¼”mÀXåÀC©IU,æÄé-|`LÙ’ŽdYX!KÍ”®¹¼:�\ñõýåO£&*8ëÉIþ+”6ùì̇V:8uÁ ¿\´0;™ýžMw�ŽFÓ÷âÒì×ÀA·~v•cÏþðÞþYëk•ù3Ÿv$pszÝéßû pú·N_÷܃eí³¾rÃßV¼^{ÍÙùÅÍ.Ž]v̶_ÚXïmë}`½Lž]XUìF¨ûT÷€å_vùæ'^üÚ+À3{¿t_ûã½Ë¹êóUߨ´1û³6ÑwQü8’YÑÆ;¡`ÄÙh²xí°WzõÀ9<÷ô8®~Æ9??õßï¯ò§§Ÿ6íJ`è«Ç¼°ïžÀžwïYþèaÀJŸYéÀm kg£( 3hZYŒÅ¥,è^úûK{½¼3°í6»ýêèæ.÷W¯]þç¥Û�ët×9yí­t{©êjÃß=rùíË¿ìòéOüék/�ÏìþÒ£íõÎÿ§Ï_°½lºÒìófýáÀ€6§ˆ ó²öwN=u8uµ ^ü퉽ó=ulbë/?ì´p§[¶ä û9È%ºn*Àug\?ÿ—WGRYí¬Gÿýþê•69|æ+}øÞ™'Ì[´60{úìÍgý@%±*Ž–Ä r.“ã"üž5ˆ96u¯ÑVx¯Â¿Óu9¥¾ 9€Ð"Å »`äûåĺ(ôŠù=‘ß-ÃÆ~·19¦ ·O©ÍF„]ÐÉf^ú1äÐGŠŽ aî„zK}]= ~·Ÿ¬^´Š 0®gÆ�˜¸Š Â(ãB® ÝÆuŸWÀôQþ.V8õÑïÜŽÔ½Ÿ“—c@qì#®·u¢‡"¨ã®9q{ëîw¯¸“5µGý:ùþàþ íd{z¥ ¿³|+±d F®þ¿{Æ!3 ûܸðr“vD¦¹ëÙ#¹qئú–kÑ6åãl„’Úì*ÕÚßÀ'ì*¡ažk%5g@A㊟£y"*ve~²ò¤ùKõ �� �IDATª•U§b"šïˆn[=q=W_~Ÿç/>0ˆ#_W_~¿Ãë³k'\VHÑÑ2²ò¦ØhÉ„ù%%9t‚Ll ¸þ2ûY+¹ž}j|µæ_b¹˜]N±Ëu ©º©?—W'yWÓ»êA º @¤~Ïja}HʤiÛbR¦çbņÙ°š‰ócÅ9»Ú*eÚí&À…} ï§Z¯àÌR('%Nn=\æÖS·²úyϽ­�ñd TDY'éÖ©WZTïJQ¾1z/~CÊŸŸŠ— »4WÀ;Å)ri ôsÚpC»ŽZÎ/Y:Âs©Z©,ãKäCã–Ÿ7±±’…!‡¬©F¤UÈÕs¿ZAR§ë Ð# )kÃCmØRØN®³Í¤]²ËÖyæwo¸Ã�jœ †”¯€»„bøzµ+“J0¸ÈZ¢¸‰ÐfvVÀÇ×7é/ÞÓ»fFTˆQº<šŒÃx¾ðŒ¤d¡(ZœË ‘+ÎJâ!%Ժ랗þ5Šž…°1-ãø©Ûý’ÙJUŸâw7>q~-wMû‚âûIÝ*êtùZ¡—ƒÑ*ö{.0±;®øêAÕÅÀJÆ1R Y(ŠÚª¸´†vG9ÔI^u´!LZ@vNbR†ùk\\@Š<8¶Ãuç î¼÷cj}J’ê‘�ïÔôoXWÌ÷TQ×c ¡åPNWV.ër’%Á€]�¨´A—6qõO*¨$- «+ÃQÁ©:6§|Lƺù½.Ï{ˆÜçPGQb Ž]Üzžq¾O ƒÉ'QJõIË‹µ´ßK—äU’çê®}0ùFƒ[6tjäÞëº÷`Þ+9ƒfÝ.¯nݱ-_(Œ'IÁu¶¸Øà¡Õs½°i!xÿhwÖªO+·.ÆÄß}ȧJÏ7åË´ ì®aòòèe—Ä%%g»g¨;à«åƳ]íæêíûÉŸíEÞ=�î—’´K—ÚÊž‹åÎ.#‰SHUVšèNÚ_]ê×’ÌŸ\¿“—^rómʹP¹“ǯUê•Pß1‡P!}{�‘ÄçpÉ•Zžñ Wêð»­ŸµÌO× xª£PÌÍoô|•îD ŽõÝB½Šäç \z&÷^‰bŽ2ÀWe=<¾Ä•Z˜o6_ßN1 É×dÂ>ïô_!ÿR&®‡©É%uVe€Ù­×N¾TϦëíy�Jΰˆî¿´ö«×f]`å f|Ëb½�©¬ØUböóÉ'ä«ÿHú�¸Â”cˆð.#óK§p]LÃóE�ØT‰.¾Bº„þîëž‹©ó �X¸Qî>bˆ÷_ÿtç×ÙqÐ>zc 6ÊœŽ2=®•Ó®4ÇùØï—WxíO¯ý¸ió›V¾y8瘾qe¸õ²?íóÔƒÿ‚ ÿÅ´cß6Õ¶�NžÒ¼áÛ€éG%O†˜dI-[�<{ÿ³—=w0°Ãï÷xí˜I€ÿªn·Æ¬c€üÎïêOË·X¾Å‡¿^|Ó¿½¸ôÔËßrÃUÀ 7Þò¥¶fM_ÿ ÕnvÜzûÑwnì¸ËŽÞnC`ë§·>íÝ»�¥SJïž~Š˜&%dáüèÎzüd`·/ï?m`ÕÞÏ—÷ ÀÒÍ'\wÕÉ_f´fœPþÌ̼ ö”"#ŠŸ€{Bÿž†ÅC£¿ñ¡··|òÖÏÿÀ-C¿{áßnÿÖ]}ï ¼¼ðõ¥ÝMw0û¿Ö>Øfû­*o} Øú3[ö×�Û¼°Íï>Xók¾¸ÆŸ Kel¹Æ!»M  þrêý<ðY`ï?ÿÞæ$€á;çÏÚq÷?ùÀ_:®$·'È.Âà,,ÝþÑÓÛØmïýŸ«4zç_Þúw§] ܲÞõW|÷) ¼nù¢ôF�K¨e ” ‡6°|›åï|ã(`3öýØQ¿¾üé ^ûJïü¯üÎùÖÿ˜ýÂìf…x‚ìÊf€g£h¯~áÕƒ_û ðëY7mzóCÀÙŸþánWn ÜzÖŸ>òÔø?K;ŽosÙF[ßýî‰ßL;zúÓ7=j-ó㡲á®å¾QPD…µßšSÿ!>íYà�¨Üûv²ºqÀå×»<yθ˜‰1´­v>‰#ªG‡žO{*l:.ßâöÈ©‡…‘QÁ¿Æùݶ»#òåk{?Í=g-©ò< ýô|™ú!lÐä줡íò÷ý`,½TýaÊQÐKa½ãóÅrÍ?ßKþÅã(rI&�ŒÒøpý5Jãg@¹‚Q.µÇWjʉõï¸ëQªÕ�åkëï·ÉÛáÓ(Õ çªÃ–ÓÉ­�1sý¯É=¿Ÿð\{r »‚òX-V7wÕ>ÈÜW 1Çœrì=ˆy…bÝ”ÓÑ<6�âšÌ¹žÈ1¶ò×<0³Âï£ÔÒ8;Ör€ZqŠßw ÁÚ.¿šQð °¦êi’qþa×”¶ÿ"@a€- ´Ñ P§|ê´ïPõw©ÎL8ŽÉëú‡¥iû+BœuQðÚçážç~fGY£æ÷ÏÏÍ_1ö›ÿÝÏ¿S÷âùƒS¼Ê¯˜tßÄpóåtÜóÑÑ2Íc‰ P§•¤ÖÃàËCiMúµ#õšGϧúé^ç!DÊžŸÜ ¯ó:_Ý÷]®F.©’‚FÉVÛäŸÕ ««ú9�HÊIé¾kq)’&_'-D$~.ù‡ûY£PF.츪}¦Xa•U…Ö¡®¡®• fèðB’ æM4¸1r  _ú6æ»B†M¬V#CÊ èa*k1 ì Jâj]·×ÄpL”dHØ•²c6v]=KTN¬'¨žÜ;T¬jÊà<sû¤ü¸7÷E‘Eù•èù®×ô0¸tÀ¤½5ï&M<uÍzÑ †ÙD0”Húø¹ Tftiƒ©yÔ¯e’W[É·D†À]Åãü 1É_€e)×’Ðz¦æ¬”qÌ;/ç·òàÕ]ÇðbFO‰bmvaI¬_=Ô.«êv%µ¤xßßÏÏ\?�Ù(Yö÷yƒÜ\,˜(_ýk×ÞOH™j›Ô®Èb“†È×äÇ _5¶_}?Eë×ÝïSý �£Tî€äÏù¸ö¹qÞíÕ D98�U}'ä æsr9V`‹ò ¯TÞ£y·§¦î©®¬›–‘+0›ÿ¾{åà ¯,æ¼ÞÉ/:± ëaWÖÇ8š5Éþ€{Ķ—˜0ªì:,õ)\—–Ç|mý=�Ô#ñx Á?àÇ»[IòóÓãߥ½ÇLcL[ÀÕ{lkÀSÿž| éºç%½T~vêî5¾î÷ª'l»}9rMõ•öT¼ü9Ö×Ûáä1…ÀÔ©×ûîÚ‹{y÷SÞ%¥{.9æÓË£¯^™u•O[éÖÿ#†X!àõ¯V“<_Xõ¼¹ïóéu½á=E.Fp™Ø‹!Ö 0ÓÏÇØb“W16Ø%Ž–Äz1ÀŠ˜bE1ÄlÚOþw0ðÚÃí—³­ -yŠ <[Q¸ƒq<Þ¦æùn“Ï Ô&�üííNÿûš@ý'#'ž|pë}:¥�›³õsW=Øÿ®½¯Ø~s`Ã9>¹Þ4๠Ÿýë ÙéÑ;Ÿx¸ã§Øõ€ÛnÿóæOÏà §ë–^xÏØ½ÀÜptý±Øê?¾é·ß{<pàÉ_¾Éš½ß?êªÏ]¸ÓSÀï<r«CUòà4ष ©ú5ÊWMô9u_â¾ôÜ(ÿ.–ááºb;d @B”Çã )Fíž ä°Tî+‹æl4\'A5Ãùp¾æ€U¥÷›t6ÖeãÒÈ#–d±wúh¾ŒêßVåЛR>¹~ºîc×½ö �G_[ÝàgOÒŸ¿ýÜÏvz8r»#?tè7©D®É<õ@2ŸGp–õ 6Õ·¬ÔÈ`•*EFP¤Y5G­€6ýÕ6ý•9dU:°4Q<ëÁÃÿ¾2Pÿòð¶'_ÜúÌŸ/üîvØà¨UÏöûáÞ—l¿°ÑÑ>»^ <÷«çÞùÂÀ#»?zÍçw¬y׫<ÜvòŸ7~úXátÝõuÆþlø© –¬?åÂL0‘}Ù{ÝKùRÈ)[JrœO¿“…?Úî@î/O²ë£q0QøPïÒ8©‰bƒ¡ÓÁÞ1ä€4²“€l‰ý³Q;«F~<çn½6âÐ÷³%$wðÜc^¹G~LÌWÏ3¹ûªf>b9&µ ÇØ$¯Jq>(ƒ3ÆÕŽU@E~„Wœœ"ª—º&©¹ùh4×/&¿¤Vœ¿È»¡æ§Â^qã†åÔè1Þ<ð'³—¾‡QbÀ Lq@á kŒ$30ùóÎÂ|ÊzÙò½\åùè`‘*žC.uéS"çÇòãñbÖ‹‚zäçWÛŽÈ»’º•‰Ñ[8ïäz)×^Î×¾§Ö‡Þ߯Yw}yë`#ôŸ§±ýÌ”ËðTÐ/mªW‘¢ŽËãõxAX7Õ8‹û¨|ÚT~¹ ŸËtÍõ ý1@õµõ“~‰_ ýbͼ•_‡a�3^o¢ÜBÿ%ü¹!s“(8€L)65 'û4;cy©uÀ$?È:¹ñág¶†™/#°Ìõá˜fáw¿ßœâ»5@˜®w'7X…!_½ÜkʹCäeçŸÑÄ+ÞÈÀ¸97¨‹a¹XO¯Ð]Þ×HrŠ/ŠR”o@CÎElø×}}nÊýEµ O1ƒ¨Ewìûñ>º (ªæŒ·@åjSJíò ŠÌQ#£W£º&£N¦ˆçBý{Ç<¡ßû¢TiÜG9±L¬y/Ôc€ž‰†"œìþ«›_±¤þ!Í2Ja”äéûm*à P¹$ž~¥kþës¦-gàQqë¯íË|mbméþ=?HåP9–©î…dåÎ1¥l,fîñ;,7žOGÉ a Àp¦hÌ+.½b”í*½[3ó23u‹¾²¶ÉÆ d”z¢OLL¼ˆÏ‡ÛËùtM»;(‘aImúg¬ ÓÒF®<–˨ `hªvi9YÃQVä6©üÀ°’÷â8eÐ6ôüÖ“.:˜P}3@roŒ—êæª£ Qæ˜@ÙÀómIä{!¶,þÎóûTX\N:Ÿ¾ÜsS6öJ]3n¹^-ùNmR az›Q×� UëFRÉÝã·CLW»2Ð~�]WëÁ¥\E1rƒq@¡Á»˜O¬’_Ë-<GóXçÍ*u” æСû,o5g4ïª}»Z¡ R é“ùsòÑ3z6ªæmÎ=Ð}�É1‚‡ÃXHÐÀqô^xŸ7Ѳáðy—ñ�ê¹y‹ 5�$ {ÎÐz.•òX.*%ùïʦnŽ1íßËÏ lø:d ê·ø¼ù²ªà¡}-]^Ré¼MǤ°Ë(VwîôY û<u?œûHvæÜƒXoЗ§Æu¡ÁRÔkòµ”›Ò5! ýœª¯Õt{žË Äxê¡ü‡è¹®-—£Œ …Q¬¯v¼’¾žú€–Î/w~.QyÃS–g÷Wž¯,r¦ç‡H®Ã|Ž•ž¬Qµ¨¿¼!@áy…Ûùò‹¯]‘uU €Ø$�Õÿ‰«Äÿ 0öyžSÎeba 1 8Řa k@3ÃòŒ²É]F�̺NÜ·ç{@>vXQ¬0ï‘cÓï*ÿWŸl÷e[)õrn!êu C7¥=0AŠÕ)@Ò¨Ø{âŸÿäGO?wè?‡~<±ú sÛ�Åðòc×Ü÷H`îQs/ûø;€ÏÎ8qÆï€Œ˜4j¢ Ìl|7K€Ç/zôOühNÛç»ç7ÜuÛœ‡÷é=�.;ëÜý†`Î/æ¬<ûsôcpYÿåç]=X´ùè?Ú¬÷ûKß3ø‘ÏÜ�ì¾íîívFÑ$%V{%ãàã©U€£Ÿ°ct€íÇ0µ2lU‡]þCÄ€#ÆÄ|šp–FQ�ú1Tx°ðÇçaÉ—ëÕq ™Tž,XJåvb€¡‚çµóƒ1U_¢Þè/EØjô£IïÞƒz cE$Š¡4zþÄ™'-=cà»Gÿpú¯öïÝŸ'Þܪ|a`×ìÚÙñcô~ÀmúÁì³0ÞG©]ñàjÌXû<ÿç)Y’S>A ¨)PØÎQ Ó}û<ß§ñöøãÉÏls臇.žH_øXûÇùö{ì»÷}30÷={Ýø‰˜ÑW^»|€2†°Lå=@êßÙø–_ôè÷_h^1öÁ“Gž¸mæ?&È.»ãÜÕæÜ<瘷܅ÈÀ!À 9óhË÷þ@ÎŒ=þÊ¢váï¨>�ó©–ÊûÅŒG¯È—;LÏÙñÌß+·‡¿ÇØ7Ø�0ŸK©üx?¥öv¨ýq#Ñ c˜�0Fåô»úçå5l~‡¼‘�Ì—ú³Ü‡èwÛCðiØ<ßq3ÕPÁ÷^TÏ1õNhg™äÌ߻ͷŸú1æcùc œ¡Mói™~oÓóö«Šå—é~•~ošü¹}Ki^åya <>†©Þ|ØôW‘bsBÉu Ã.ß!§øãöZ¹{)ÇçlÊ˽ޏ~„'Yma×¼ÙKˆiÒ¡zÑ÷Öo¾gfîR¾EŠ©b@ ÎAA:LŠÞ~Sί­ÚÕG힘BEÏåŒü;' êKoôŒsθ%Íö؆ÐFüîâ›6E…PÇäC†X@åGƯ3ÌpŠÜ"NUʧ‰¸qM(ÿx}±ãy”Æm ‡ˆ%ÔUXWè¿æÑýeªÝe0PV£û ù΂C;ƨ_âxöŠáõFȧ`™j×µ§Áð…ûŸÓ|Z7x½àöGC®O1_̧1w=Ÿö;c’CŠeTŸ6€ajßq]áu„ûy˜zÏ~ùñ>H¿¨‹ç ÿ=ô™|@å3�n×O6ì‰í5%$´Ìü¼Þ ¿'Cá÷l8|ïI?)H¤”AIÕ€¿> ²ý]A!‘òµäÇlXÆ lú~¬¢#˜“$|r ¨èt0°˜RÇÌŠ€âqô¾7ÑçªJáÀíbËtöÐÁ€™®÷0+T¤'âóßDPP$2n$ßç,)ô·vlÈù¨vç QÈ’ž ]²:ø&(N0#-¬#Ùh(?HŒb7vå p>ÌŠ'g~qã’�ãŽ5°™ÄPp@7eØbŒÔó]åNÏN¡dÃXÉý‰¼âʨQµá”›O¸ßx¼ós¦|û;1ul‰É€WYÑxæ÷¦òä”, ïR UŸQ+þ êël`,@0ÄCl»Œú…×µ²–‡÷ÝP^4lƒKÊ­z͘¯Qäqùa¼Ó8r†"0@Ä’PÿdXÙÕ+HÎà­Otߺê͆ Ô–ƒ™ŽfrìáÀi Jï7‹ä ò¤q:bÏMlPAó'”8C‡œ"v˜ä4” éï51«È€É n\À¬K2Ÿç.ņN2?ZEzq©R �X2à€L^§I/– ¿/ã“¿cÖ ±œz­a&ì9ž×‡@ë Õ«Æ!=àRùÄì߃žƒë•ÊsߤßC0péœ+Ô/~>ñ `U˜s (tÆoª®Ùi倫§ìÊ©|þ^J`CPOiŸÌKá«ÆrͬëÞí˜ÝIÚò!Ŧb¸£ ãu¹À@šÇ¯EZáù*ÇH´‰W–£FÈ` ˹ޔϨ’.WÆ­{~ؕחÙñÈ)?îòd!…ñ4@óÖhÖ¥kú^úÝÓ%¯ß³í˜Ã6”iÑsÑù©‘ý"¦SNžòðû-z¯ õõ-‘<x~ç/–hŵ‰#T–·3 FÙ ÈÁö ÷ãõk·0ÏРþ(ÑùNäáä TèÜë5äÐÍêwÑ @ìÄ×.ʺÀ*Ã+}rb¡¶»Úk8MœMà ÿâýŠ ö¯2ÌŠ]&r²@Ò'sY†û@–¿ïóɯ8ÍUŒ°^ù1ÅöB¡+D¸XapL±„b‹½ò¶×_ÍÞ‡x æƒï0†È¢0ÅqЀMä<EÞ0Rz>üîÏ'ËÅ¥áHyÚº§Ýrö;€ïŒžuØ SîÃÛk‹mÚ›kW;�$»àN\Œ ˆ°ŠÅQ<‚j¬,/Ùà’Û¯8¨-ùÌ…Ûö÷5_ýñw[;ÍØøãÎ@Q!ׯo=a[àܵ/ýÜïîýþ»Ÿúåù«[nñîþw™ÀÌ(ZHYa°T=Â*NŠ1áp¼QJ¸_R:ˆ‘¢„‘tКI?-ÏcjyVùgKå-èÚÄ šØ^ i ³„ðÙRDË3Χ ¼¤?*:°¦*Õ· dKé�ÒOí+ꢓ8®g™î·c>�€&ÐþÖëóÛ?ö¾ã€ÝæU¬÷Ì“¹¼ôÓçl2x0gû9¿åxª_Ì?é°LÉ ôû|ªÇR §óŠÌ`±¾Xä ʆC;’bàª_´E>Õ#Åi{¶T,@8íÊï]qöæÀw~tÖî78é9àû;d‹�µÖî<vH~—Ü…Í)?¨~ü–ä™R:T¯}À%÷_|ÍŸ�*é’/œÄõâ5ßûñ ­�­¶ñÇ7<žÆK™äa7hqüHú•â @>ÙX+÷‹³1¬ÈR'ÆÌ`%NUH9…„þnËὬ!Š)ÉŒëo9Æ—>õÑwòwÐ5)^ú“Ÿ~œL�ÙRª'ȃ„¢äòè¹d>É5ÍXIµ+nwâ­ñyÉ?o±>¡ç3éßjwÎÙJQ¹ãcÄô§{.WÏ1·yÇÍ Õ¯ãÊ£þ lÌŽ?¥8 rãñ*åY@3¾—Úù‘6š|îÈ÷gååkúÓ§ÂþÖåñ|?_êéåìǧWp³%]è‡6Õ»ì�^-?%©'1™³}‡ýö~îûÒ¿“�€vdjºù¢­ßWýT¦kwŸû•ëAýßáñ£rž0ùudÝ(0h0ëVyňOì^°È0 Mý°,ö[wIHÚ@2_Ö›~ÌSëÚH±7I?”ã:”¡2Ìói¦$f|ûï–¯—Á&–S•òiªuU¯¿.óãQæYPkB~ZneÝ^€ÌôCˆÔ Ê~÷½îçë«æƒ*åÛ¤úhæ9ˇ€—d~XO•<ݼ¨Öe}ßë¤5pÊ3a, ÄÒd†Q×zÝëȾÖz<H•üÃüS̼镨tú)jÛX’‡‡ƒ¸]Ȩó\‹¼áˆ7@ñçŽ~óü°{ßtÄ\;T¾5)VÀ¤îŸ×ßœ^ì�èÇ Rª¨w¿¨ø÷PÞÿ£íÝÃlKª:Á_@žƒˆU/hË·=Žã£íîo´ý†‡E1€àÐÀŒ­¶=H=nž|œ|ß›7ßy2ófÞz JÛ|3C·2ÊC(”fŠÆöEcK3ú)Š£Èô×M+PPxöéŠù#~+b­µcŸÌ‚žøãÞÜgÇŽX±bÅŠëiæ´tR‹å[¡)v+% Òù#9:ˆªF3ìN»’ûõ&]˜öÄä{—Y?)&˸e^ÚEà|ïÂR™WÀI$ŸX+3™k=Ö·†bm –gqŒJ¿—ñ¥u41ô!¥kßj¯Ž†|Á®¯¢è‘È¥z$©(„·P•›±B:Ü"ʸgò÷=~]7œ·ǶÜû¾êF†Gê[¸ %²v¿&CG‚㈎˜�rfjD­ÂÏ,’ÂXï?r®ÒòO_ÁµÂŠœÕËók¡ (f/b˜LDÞñ-xÇ5 ËOn9·‰¼ /õ·ØÎå¼oȾ•øðëð*†+‰£¦¸Ö³›˜¾Ÿ¡¾ˆ6eÐòó�Õ®v”‘”uÖá«è›4ÿÓŽgº½ ì9e–^ô¸e$©ÝmöÓ´?DA;5b;GþÍäù¶ãŸTñÙ6èIä÷÷}»ØÈâUâËã§”]~,|¿ÔŸpÿö®ävt=x[QÄõýÏ; è}E2‘hGÙze^ÃJâ8q]—sÍ g仉k_ǤVR=¦ö ªû`Ü·na%qäH<î§ Î-ÍßÂJ¿rü±çC½'¹Iø¡ÉkòEM.+õ&@1LWÎ{þ$o^1À•šüÞ:G"ãAúiŒÁ¥eï~6©TMñ†\å`àñ‚¶t½°Š½ä‘ù¤YŸa5Õ{•-Ýžì ÜCXÃyâƒé½‹p«Þì[9¿ØËtPé3ä75>£çEàŸ!t|9ùaKÿ޲/›ñVðìKqðPϘ¡ãÀ0µ+øíŠS²³žÈgÅAÁ1ãêyLI>ÿ£Þ'ÀWýü£'4ˆ=¬° ”‡•Òð¢ß?Œö¿$8§ĺ \)2LR"¾ËE‚wwØ ùÝ}°†±ªH1}§Ø´R3ˆ½3ÿ’ a·NI•¨ÊþæoV⛡s'oå=E ë{ þ•ø5”Måx=ž <÷/üî×Î�Ÿzö_}ü‹7¶[}ÿퟸå-À+ÿ¸øÃ¿Œv„…VHTþCᡯxèMÀ•?ؼíäxÛw¿÷;?V9‚?výÑÿnæñÀûþã¯ÌÝsôOûÏìÿ0ytsûäÛü¡>ùö›OÿêÏ¿¨{ Þ÷¿ü”£OzòŸû„z’*>°Ì¯Ìº7�� �IDATÿíA¾Wùbºà%{‰)ž±€Tg¨çºP1)]‘e]†½®R‰àÂ>zæ÷ÒšõüíjÇ~ÿž§½ç­ÿj˜ûÝ«ò¦›»AzìÕGÿû™Çÿê}ïúÐÝõ§úÃG½@õ#©›ú( O2°,c;�°>Ò¬‘¨ ÁY¢3$õ¤Døve\Z¸Áß· ‡üÛô{ê@8âÏâŸâ©Àso~á¯À§žüWûâ íñ¯~úöÉ-o^ù÷þáÁó9ó])ᡯxè)À槯þðÉ+·~òþg}ì›*xÞyô‡g¼ïM¿òOï=úé?­÷ª‚÷H÷¥¼/³?ÞJ-)Ô¯Æ[Ø2äü8õui1s9ÃW¸ÎÀ<ïîÏfÏ[ÿ0ïE”ÞèÀ“m§ïÚÃÞ·WÆkÛîu Z|Oõè*]æco¸”yxëP˜vàu™í‹Á·iõ# K14ù]?ã¥F‡Ëü¾ oÏ2?ÈãÜÎýêñQ‡¿ï~»÷n)Ul:ƒh°Sl¿›P°lø´Ðq¬)Ÿµ:Ùañ'½´ç¯v€ÐõG€â®ýŒ¿ôlôBÌ»úéz’bX"‹_o¨0Nã:nIIß¶…õ˜x[GQÀiE¼çOv¾S„Ö2Š#Iªgû>¥~ò©§5­,óYÓ}RèŽÍ-ˆe>úf_[N†´ ¿(u¤Oϧô{ÍçÆ( ?)û­ñJ$XQ` ^E!Z/MË€%Ï;(‘ùûªþ4ºñ GPA܃Z½A&ÑU1  ¿·‘£z´Cò4s —¥O}— å ‚ß.Ee* ŽŸí+~&X´üÝC'p”’Æ[ÞT"2]H-íø5]>­¯Çâ0=â  …¨:˜–Eá·ïÖ¥Í(š´Ç+ð´aèza9Í\<@‰Hó†ÐÙáÂ¸Ô °‘úÛ€‹+eM9ìlµÎ½NŽ7˜bø×ÕS>OI-%íEúÐáG þQßÏLëaƒ÷íJºáµ©®C÷]qÄqp ¼] ¢RümG¾Ÿ¡¢J(‚‚…‡°’ÎýÆ¡G+Z…ZÚFí¢áÑã²ãœžªRGØì@GæºñfŽâµDˆ‰ákVE”)<èväF"fÚˆûâ`D‘˜öå—ùD’3j:ôûĈcçÔ‡ºMI±èfƤG¡s?Ž.úŒö‰¯”ú÷rËÐv^©¯'‰˜eâCtÈÝVóªÏ³ö;Ãñêç4¢ðL Ö}*´kü£Âw•Á¡íø§ÀŸ¶/t¸qx<›öté ï íîÖgŠCÔætaÖýÀ9Ú¿®÷ßTû`-º‹…ØÑ)ÄT©ù‚D°I¤Öi­Yçð#íf~÷™LÍHKûE‚˜²Ž ü"‡¥óåÌz–v»öM)=Î_ÿL ¿¶ÿî¢ámï ©ˆay;·[uÐTýÖù7Zí¦²ŸëÉ]N¶´ñzñ¢ `>C¤–•ù8/Šük†z/ÇÚñƒÑÖ³U½2Nÿ gHÏo{¿/¿ ]ýºhâðê¿/eú8ëøo§ðíêïeýLŒ>a&nå÷�0 ÚµÄÎÁ«u”oeŽþ6CÓã$GôÏ`<ðªŸÀ ßøèW‡WTá¿hdÖy^èøîÿ¯"w—¨Ʀö_7ˆuÝý•ÊKðj´ _ïB1ˆÕ"´! |N¥ûް®»Çôaïäï·¶êKdX·ALÕÿÂî›l 7žw*x[3Ìz-¼¬÷߀ŸÅëãðýßø¼Ÿü©çŸþÏëøåmäþ·ÿìæ=ñ ¸þªk±úN঵Ç}ãMOpB…ä2Òs`áûÌ÷üõ;?ó÷€·þö[þ¾ àÚ#~îïïžøåù©á ~xÕ7¾úö—ÿJiçS§ùòO}ðÜϽük±ûû§üÛÇ=á+> ¼û_¾ãîÙñà#þ’£÷-ñð;O¡wžg*ï{J í2L]ÄÀÖëø½ý\²XÕþÞlñÇÛ^E!!Éô’ }™œ}�øíø­O|à•Àcÿ›Ç~ß ? „{ÂýÿCýÈ8xýO¯ýjÅ�äËÜ“~â?xüØõç«~ZÁ´AÅb H ÊmŽ')²©p^êÀOQäL÷\C:8-£x,ЇƒÐÎP¢�ÕóÒÁŽúý€ÁÇÇ×ã øþžëk~øô¿~à©Õu÷¶›_ùÄ%àúöµ¸úRà¦+{ËMoÈP–Tƒz^ÇÀgîÿÌÍŸùUà­oËsîû.àÚŸüÜÛßû+è,Ëë?u× ¾�¼ê¿õêËïD[a0M¸®{¶[Á®¯žE7ä<ˆÿTO ü[­uhû+ré5ÑEŸ eBaù¢®§KC<J{¢(^Î5¼¡§”žj ¾Ôþ†3¬ØïùÝpA¾ÔQpñï.ò¾ïVmPCìô2¶´AhÜâƒ1øyà˜ýé÷©´M€5>\ÖµŸçÃMöø1©…:‹KÅÒšCþ-ó«æuż¥©'¨å õù/ô;í÷â·\09T¿‹arÓ÷±z€-Såï )‚GÑ:‚žgŸ¸G~.ë£iáGϳæB#´ÍÓ²ÞH)ËJñ/¿ø»m·Ïù*êy<¿t9’L7€´GVÊpj=1¸nä™]‡^o[_¥X¹`#+¥]Á¯¤:ôôP7¹/»ùéqßÈë@ú™EZåâÀbái\;eG´‘e%’JŠçä©ÝËÕGÛb Ëó!ø8A‘0¥½i†:¡¦—&×ïŠä¨¯ËöîlùòktÉ3]E °ó€[·¨ò}Ï'»"‡ZÏqܪ�ŒL›ã ®Ã‚»…œ]‡MV¤Iû5Å`Ãß{ü½mxiÜ_½¬¸~{°†OO;C ’†%EŸÔ;ER_ˆa/úl¤3âV†¿kg³rsÝAÂÉ!‘rqXVo´²s¾“᤟¬LáÕ¤ÐRýøßëçä zT(eüˆ‰zªÂ3’Þƒ8Öþ'ãïqüTW’¬iOõf X'|íÞ¹Nsj£ ·®½¹óbçKß~.Cn~:Í@I…¬d¨Kì~ÐÂCw„ª(¢wÜw]®\u¾Óæ/Rìž7¡álF~âdž'¼•ˆpÇâˆÜe°ª|#⨢áðºªÎ`)Ðq«ƒ¯tËÚi%+Òí|”uëæ)Ë©\'Ml'gŸæ(X3(O£Ã.y»àǶ Lß7J²ÁðÎmÏc]ã¿Æ/k_h4`÷“rXmа½SGW]ý˸uD•sÐ Ëa5ÓÓ€ø8E‰üÐxök¨jSõ¥ÈïmeÛÑ) k†›5þµ«æ­Ðïåüå¨Ìgd«°@Ç’™¸•Y¤üæõÅöòzO‘I“ Â.¢ß+­x:±ôølцBTÚÏý–$¨UNÛÐw~ñëZþê2üTáÂyr¥7ôxP{œ²O7Hµ ­Þ‹Á9ݦë¥ódú}Ù× [n;^½¬aU Ù“Öxj†É.CÖŒ«W"¾Úó7MŽðá%ÿo8Tåó/}ðÉq�Üð~å'œAì¼”ƒSS†H¿{CTøô>¾ïb±)ýJñ‘aÏwõ«õ*ã4õ´AìUb„¤@à †£rgXWªÄ醴TÄv^Ìúow³çz]íxÃØ««µÚ‘`Sîûüë¾x9ʳÎ1 l`W  TÅC¤;ÆäŠÉ†!Ç<xI¢ž%Õÿ¸ë_ßý¨7oøÁ7¿ñýÿ[7šžpócÞßð²oyÑwþwÿxÊâ×|ø«ß<òƒü‹G¾øì×}ö©ŸûðñýÉ{ÿbxëÚý+ýpn¹ùGžvíÆ_~îk~æéWŸ Üôú›î{ì¿ÀáwþÉïŒ÷ÿ~âž¹ÿýuïénç=ù%¿ô]ÿ˜`þÝ?õíü1-¼"F'<•Èí «ã¡†@XJ °x˜¾3x“ß„õÜnwD–TÂRf„Û¦¾SŒæö—Zí$/9çt{a9ÁÁTcüδ#í®»vUÊC%j1Â)šÔŒ�R*§ÜnØÀ,Óx®_yàè‘ÀÛÞÿÞ»kI-¿2üùŸÙš¾öï=ã'¾öÿÂRò Œ‡ô”\JuñŠOá3,Ûy¯¿v((®ÓcK¿×Šm_”§a<DJÅ´k@ë%*îÄËØá<©ƒæ]ÿüᇀ7<ûÍïÿwãá ßþ˜ßí¿xÙî‹þ‡ïúJà)Ÿ~Ê>éÀ#?ðˆO>ò>à³sŸû_>·|ü·?~û_loýÑûÿ×~â|üÞü¼§½þÆ·?÷Ÿ~æïn~¸éq7Ý“мôô'ô6¥$E€Ì…óÌ•õhˆ‡‰ÎÂR<Ðíš~/b –öå�[hÁÞY“ àþ`ÎÔ“¹ßèCÔM1Š(‡ünÄS¥`a€b Bu]·x&xú¬góò;ê7ô%¾•zhStø· ÷áNÏ׈ß&}Wæ)nçñ&ºf»éw©ãvæ“#ÖKè §4¥¿Ö<× Eéwƒ 2ûºLšn‡Ä£åûm|Ÿ”ïêôgù êõ<}xºzÈ©÷t\¡îo,óá釹>ñ<FÛ $õÒ|nÔðw}„%X}§ÁÎÑp¡ý+7¯ËÖÉ\l§2¯‘¯,Y…z< [ù�«éÎdã¡‚SÃÃãxŠqlæ?¯2#£2îx·1 „¹ô}¦ç¹</¥ ¾Î{Û@;Ëzr—˜àAßYÙ¨ô˜ý¬s|JAœ9üÏräiŸêÓ 5FˆèëH²°¬ZÓ)¡Æé½à,n§ÔÍaƒŠ5IY³$ߥØàA° ô¥ Yq'=‡¥RXéq­³½1åœ3Ý|ÊÃ&ó'%oþ=ä< _¹hG­ÿ<Ÿð墀ír0²÷B‡u¸1E¶ÖéuÛXú÷ðåu&Ô¨ù Ö‘3ô’~ñƒöüɳ·Q£ÅCË_¢Æ•™Œ/Ù§¹­âHÉ>‚EÖëv6Äx¾é=Þ“³`IÙ•¾»Üq;„i_èÄàO9ÆÃô·êWàßâ¸/Sá /ê‡lð·Í ¬—ž—iP>`ò¼eÔÄÖ#'.qJ<`ÅpµA|lçÉC×Çïï*<r¼hÑŠcÈ@YWü=µ×-÷õ¨ÈKç“üEíRÔì¾'yóœa¹‚à€ 3ï¤yàîš\v)‹uÁÀß/á|qìqêÒ¥à׆êZûÓÜt,%¢j‹ø«G`<NœÂkÃðÙ†Ž('êý—è1ñy`™Ž95ã6Oš<ORÒ]i_;Pdê2Ý,『BiÞ7èÑT0sÆï¤}w4PöäðØc*džŽ‚wÁCá»ÖqÒÏ£(ì“CåN~¿Áõ´3ÒÅ,€ù<?—s„–u¬,í‹Ãˆä„*LËt0ÜQø¶p~&e­ì¨ú"ºõ¥ùoÞ¤r\5§è‘ÃS]1»Azµ•¥ßmG¿ÈزÊ>Û2T–õy™ëUÖ·-²O•»/s>‹ÁwD|É÷5CIYÖ!´¬» Ç‘ÚÉ .þ'¥Ü=½áæCÖŸô›ö‘uò{qÌ8@Ú§¤Ÿ\Æ�mwÄâ8ãá-·X¦g Žõ¸$Êtu¿J$³q¼o 6By‡ô´Žäø±Ãßu‡5ÓÎ$ï£ o6Éæ¬ZÖä²»%ZӛЅ¼OßuHœ!Á·#x[€]g™ÚÌz?Lõzfý{ƒ˜ž¿.ƒ^­ÐÐ!x•Hg:FòãH"eº*ºäŽà…úmeñ ¥Z ËS –Â_†jžJñ™ÖÌ~]Æ ÿyti?COʰ½åê!¿×rùrNe¸•z�à˜tëè"P¾$]˜qÔæÁÁÉoB¡ï¶;Éz6åXTÁÓe·ÿMÅÛ/xð‰qÜø-_ù–ðÁnC–*Uƒ—7\‰a hÕ{X±óÊÃM½xñ¨Gˆ‰ëm¦æ-4„ùH0ýì‹6\ù”ˆ÷¡DŽéú÷1Uâ ÑeèjYv«ºCLî{õ”ú,mƒ˜¤­‚‡¡GÏéôû5lc€tà8ЋM®§*7øO~à/þÅ_>xÅ#ì[7¿ øÌÛ|Éä?_pœ_FùæÁ3ÿç›>½eÿ»æž <}ðŒ~í€CŠ$½á/œþü?~Ëç½—Ýû÷ßõ–îöönå'þ§·lÞ²û<Yœ•ñY°KøeÆ!†¥üÜŽØHEȶ¶LÁ'}?Gw-·g#–4\#ö¯³k^ïï¬-ÓîRNñ“úÁ»×x“Ç÷¶1«úkcÖ{ã\Êׂ'—påG®¼ïh xÛyï¿ùØ·<|º¸òdzøâ¯~ø£/û¦Ý+ü¨Tè¡x»¯›™Ü¡r3á«(­Ê5)ó–øýß ]¤Îì]&>ÂC s¬wÈvuŠD;ÿbPÜ€OþOÞøÉ»€W|äýÌÕŸ>ó Þ:ùÜÃÇ×Ã-ß¼ýÌ×Üôàèƒû/ü_ÀÓ—žñ{Oÿ+$^!4ÁƒšWµ.¶Ýº*ti=®{u:ï.îyÛÀ!唸îuÂ;‚ЧŒdð¤ùbÝlØ#Òÿߎ°c ©§öÔf,QCáQ~oœçà:¬bÈóMÇò^+„ô´v°~²“SÓø¤ôÝ|eGÏ´7æ| ·D€‰ÁOJÁvCØz¯Ö¢Œ”"xöJŠ!ºÏ|Ð×óÅÿ€BwÂLJsªÂ˯ˆ+ãnÌ| }ï´"à–øïNkžÓóz~õÜžo«@“2� _“Ræ}´¿cæeDÅ÷°bÈKíÕ# …ÇŠa°(€í¾¢÷'©§÷ý—Ò˜÷r@iòú§<ÓòÈ>µmà;„5´ ÝõaM;H|~ÈïFlgèÌ-Mv )ãO4º‘Û~Ùge<:eSQ$¥Hb:ª ¤j’}¾‡3�טìsŽ©5ž5xÝ6‘VE¹Þ°ßùA'8n©+ ¿>)Ëzv2t6¥°$ÃÜâï;¿‡XgÿEAÆ-)¢68¾ÔÞ5*V»RW‰!¬à!oŽføzy¾’¢ÔÞ)¤“Z!V"™Ò<ÌuFî-s>Ê:ØA{H»s™.ÁúUCpVÄɾ7Ç߯AöQ1Llg9DŠæ“‡°û®Às- ¹ÝÔÎ:çkÇñA»ÿí´Ú“ñÕSéz8d”uº/x¹µ;2É®Û5ÞÉ>‘’ˆ­ËsLŠÁ%Ea›:æy¬Qý™µÁs[QT5�–‚SäFI˜ÞïP±Wöðw‹o)‡9 šÜ&%çAkè;D}Ï]R˜íÆãn¼l()¤”’r‡ˆÖy€x¡!<ŸG¯¹¤‡5ƒŽ68K†‡làr¾J©!›häQïÐ’Çå ¶â8w8[Kt`;Œ—s;ª‡°!J¤´1„)GšF–^K;î9Õ³Çg£bÓo—ˆïIvIpò3ý…åÔV¼MT2».G´1ûY/íåÖËyÓÄ{(7ÊпC|jÇÆÞ»KÇ:¶æ•†·0Çhòë¸6¼q[ßEYup­86ÆÝ°¬)Â×íDágì íý ,%8âÛYO·¸¶0 „eq¦8fܱã KÙ¡i }>KD_UVrÊH}×fŽ8«Dzéùôr'BÒsp½…õ w£É—³bth¾Jë‘ãQë®àMàMô°o'Äñ)G0ÄbÐEYïÞáyÈ»j—¨€>t©Ó$uaqœ›Xx,òú"¿ËóCÁ0ŸùáñP\1%E®/ÊùVÔ/ƱŒ©GwÉog,üÞéÈP±T²ÌQ{Ä]B3“ÍY Ò=دà¡Wœ<>e\ï'™/íkHÃbÏ|WjJ*&ÙAó«8 w}5ôCü ¿&Þ¢ŽZ6û^ÜFðïñ0\åïWØÒUÂ'¦Ÿâ¨·n´¾vâÂô<Ù³\cüÄ!)›Íèx¶kï¢Uû ÇÏȶ2~FHªq*úò‘½-zo9þØõŠy¶ ™ÄÁ£Œw†rå¤C¯Z àZPåo…o‡7¡uØÌN8Ÿ‡ñJU?å#šºôÀÞ±åvÔ‚4\²~Š<iñ£‹u <­$É2þ—à_Rj<aòÈn´zoi?ŸÏƒ=¯tâ9ãÃz3ŸHxk”CvÃJ‚#ñ…þþƒßÀ¿ø˜ßêH™XÇfÛ%å<C×ÔT‹S V]­®ö¾Ô4�ÓïKE"ÀÞÕú½” œŒá˾/†2˜çzÊD*Q§NÔ)ký눰Jyà ñKI±µâÌzTʉ ˜©-’¨Ö¬OE�eJ wCà7ÿé+>q ¾ûèÃox&ðÛGþ›OM™^éõ#Wq0øÇÿä'Ÿ÷�pëý·Î=ÿµÀ ·Ýxý†_DK9ª€ùß_øº­ï�î}`éS¼áþù¯{ÙÜßöMßöäo]ÔžáΓ´—¼5BEFTJñp¦€ÐRèçH—ŽÜøÒ~,)‡P sçŒÔï#]‚¹ÄQÜæsò즇b%3ä±Äôù»2è„!€Y ޲Èu�ÂZÚânŽ a{©1<Å:î úƒ+»ò¨£ï�Þþ·ßû_>6e¾|Yý·ßýÂo�^þ/»ÿ|=ðˆ7?ò»ù$…ñ&¢G|XŠÛÚ£ɳ;rC_â¼æõ²NèÒj‚ÞÏk\ðDIŒ°Ž3 ŽR5È&Ä+¬w5ÍGÜ1øÃÔþŸ~ÿŸ~ê‡Àa8š¼áYÀo/|øqŸòo_Fé?á‘k¸œüäw?ï�·þî‹^ñüg7,Üp|Ãoo•zËðÞ*<XUjNÁÂù²LôâŽVX…µ4îB‡l}G—Ž! r}Dkôw*«ç;ŒœJý™H5>‘#¥tä§Æƒ^›#�#*Æü~x‘?Ðrª8‰¤a„è0^ÎíÚƒ¬DR!©Dí!ŠPÖçï;™“ØTEˆlhIë[ðNúÃ)Ÿ¶'—ÅgA-î8Á5/(jƒ ùžïwØ_ý-©£±ìCÒ®¢£L?ÒÎÀÁçFµ7иþJ¡¹xê¹£ùÀ©šNbîPè9p¿mÑå8ϳ-Ö�Y ¯0í ú¿e@¤¢èÐ)Ô$’dǼª‘žöÙßeã"ó2pŠ8î\Wê׿ßO*ïC›¶·Ýeäß0EFìÂÐîÐqÄ©^‚'y�\§è[…aæuYð'Ì1ÃzR@¥#Š¡«D|'Â8ÑE<u*Ÿ†ïaéØ_níñžùg’�!tH »ªwg…aX§ÂÒ¤´CIŠ8K‘bMæ7¢h0%Ë;‡àþKºË²$ñ8yUŽ[gìm „aj¹ì³Tp ]É>,ûźÚFa=ãÁàËÊ®¼_§yܦã_ö ãOÆ5漊\mèÁ+‘¹KÎàaÔcµ>G%QE0ºB*"ËþœsTØö¸oe¬89¾PÁÊýk‡û/Ïk“áSÅ+³B¬e¦‘ÔWãרŒL sŸ±ü¼<\8–싚o6h°K:Ò‘]Mš7ñœÎEK)—†< †9È>˜zÛIç©ìÛÄ+µÈ0—*i/=OÒsæ÷¤gžã2}S6ÈϽ¤D£S0ÆQv5‘ÝìMú=¬å9XÂ)wqh ¼Äo c¬»0LíÄ‘js*2O)Á[ñ ¡ÿÖ<BÏC~^wß %kÓi£5hÖã2‡ÄÇÈ9„uéUÂs…ï%žéÐÐÛûâ(¿ùN®“àZ"Ä‘szä–En7•]åÐõ~Ä/ÎÒϺkZ ß!´\Æ•Wk¼{tËÜW¶s$V‚Û:ʵ ý"Ï]ˆJ¹˜±~¿ß…œ›7‡•“v[Ž4Mv�IŽ%RI¢MÄ"•e툨Šè®˜s_ÃÔ‰½|çÛŒq8>$݈ƒ€w(eÝ8Vî2òl‡Œ<+%ÄLd©uâUÚ/Ž Ònr)ë Äþót�9Ü ¶Íy-Ž–NÄ1ù=  ßÙPRîÊ„šç1]bM†jþwsjämÒaÝa©ÐÕ퉲a„t^‹Øª·³låæ)ÇŸðw‰8[#<å8¬¼Ú)º78?EŸ“ä–e®×òŒuœ¢8Þ–ZgÄoÑ Èyj@HN2²pË¿æ9/'hÌLÍW˜OÓÞ÷©To‘ce/Ýæ~¾h`SíËw:òj0©»Ë v,a‚5”T3 ïk(Ë%•¢ŒÛ;t[ÄÀ<ßì9¶¨VXŸ*øÕ¸E…îŠCå BpïÅqJ8º1HÌ“>N”»€6¼Ìð}i¹ ×RU"ëà©SVêöµã-WØo›.ÏzíD|bؽÊqÚýe††¡‰‹tœa½I+…âJnWÃá#É $Òî\¬ÈwB0ëK—4Þ ƒÇòý~/†«Òß>Ÿ'ΑÎókáÓRyúMýCtç]¨å~=ïˆ6ÃöÅPYž5},á*û—ñxßÖ°(ó}#à¿ýà›ã�xì/>æá˜vç€j$ØÔúªT g»h?ROú“v»¾¿ˆAìUÎ ÖŽŠa¬&¥ÙUR!¦’ `%"¬Ä^­Þ{Ù­®U}‡X*íT‰ÓÉï>÷gîÆïDbxió.äc‘–Â�� �IDATK­N rªÍ"ôt©ÙM{Í;&ÏnÞüáoýÁ«þèÀG~ï–}ð‘gýþÓÿøÀGüžôÉ5àヿ|ÖïÿçyKÿÀ3ûOû»7þðœ§?ë%_óxà9¿ùœï{æðõòõyöû›÷¿þUϹ¸arãWßp?´�¸nFÃú ¯ùÂ|á�ø;w<ï×oŸ–ò’åþÁ[üðg'½ïI'Oú>�kl·\4*‚eÏ„ê7iu¿ï«¨ ðG ù.½_d{GÕÉïîyO[7=ÛÐß5 Â#/[QöT X®¿Âw(°®ó»CzT‹‚ °6ï9®Zü—½w?ëþ¿ñÙßüÎ>øÐW|äÇþì×Ïýù^3Ù¾ýÑßðÎ'ÿà{V¿û—¾åàû&ß÷·¾{øº§~ÝO=û]„ûŒp —Mó\+r 8CJÔ&Ïëæ}™9p$zÁ§1@C$rPåc—m)¥ë»1ë GÀä—šomžüÁ¯ýákþèÀG^ó{¯üØWù¡ßÿæ?~ðÑgýÑ÷òvàã?þ—_óÀ€Çÿ§Çürÿ¿uÓSŸuã¯{γßù”ç_ÿïŸsÿ3nžó©¯ij¸ù®›¿÷9/nÀ o¼á½-}¬ño‰ª5ÿ¿Š`®‹>š®»Œ…µEꜩ÷ ^m*©Í}ϵ'E#ÚçaêÕ]·ž»ÇáKoØ{l üß+…þTóÉlH"³v3ð}ßüÚoQ¹ŒnÝ}m ’äñ(ÿdà‹_åýˆðéy»ïû5.1pßsD^¿¶í–úΰñ ôí¥ñÍr|£¬Þ¶7 óx¤Ÿ1ç«Ïïê7µ÷¿²ºî¨«¦ÄDãÔ=Ÿç;!¤y[äÓQž¿úº^¤€[æý*¡¼,™Qoìöø§€0ÌûµIà `ˆJ$b6´¢²N¯òYúÅZÙá ž î:,{þ'‘½íƒ“âßê›2î1j‘Í¢(¶Ü®ïEa×äyñ3,†Ô%ÓV‰-pêRÖ‰¸ ôsºIi'}×åµÞÙìoà8ÏØî¬kÃ}V"º¯æç”ÞfIEé~¼ÐöWîã²”W8¾u·"m{M…ÏØ•(Šñ±º/ÑÖKéw°Ž´.„´\P ó my*ëŒûŽˆ‡Y·¿v)Ã…ÞD9Í ñ{”¾=tûåNµùÝËÙ¥xÆݟË<\5@=Ç7š±í•ïDuÛ˜”íâùñºkµü¾Ëö“\ ©#¯øÒ¾IB~—~¯äö­aKøWy¿KxôÝÑåž,ÿ}QAرCJ_‚C Ñ#9Ð�Òp¹« ™Ês><¬_¾¿œ#ãL¡ÃÁ€íˆÁÛ`!ŽU9’s2"œ‚ëLg¡(Þ�•éÂ¥ðm{8_6ßKD•ŽŒRݯüøX¯‰WÌÙkDOô!# Fáª[×]¿%å®uj:xM蘱FÇ :ìĬˆsðBbÀÇ>&‰nb2¼HÄWæKa½N÷%É«‹D*‘ÉÕÅ >íÈàËɰ]OÞd‡E�˜$ÄÒ¢ƒ  Œ®±Öu=‡Ç>ñ`KIUlR%ڔŠ>ÞÝ%8„j$‘ka9Ã#.š65%Ìø|»E9¥Õ9B¹›¬ZžÄñ£'óÃ÷åùJ®o¾ç¯Åác‘=öüùbðÉòf’a>–ýcÄ‘ZwZÁ=C>2©¬Kp^´ƒdQü»;ÊbI&X=¯Úu$ðÅ‘ÐU¼böëöc¶¼3±(ì ñŽ[üu¤ÖSÃ~{@˜£CÏ5Ynåø!íõè¡!ÌüO._QtÁØËÖÙÃDÃ:¤p~Ã0áWõ7iõ³ `’¡ÐóÅÜr�?%] \u—„&¬3b›úÔÔ¯qlH§‰n—Ÿ>ÐãÉx\â¸C-é£Å ødnA¾“Û ÛçŒ*ýF1 ¹vlòº°”~‡Î!ož©îFjœ²î´Cs{–e^-Î(GpW†¤Ð»ýþÀ¶_¡ÿÊ:ýÍÇ5òß«þŒ#YÞ» ³ÓÃ3¿:'B *" >r›pÃÌŸ‹Ü/õŒÃ¨Z?v¾ë™Ç (WÄzÕs=}”ŒÓ¥ú´™ë¼Ö!o4=’ï›|Tl€›¾ù1·ë±)©/Õe˜ªÔóï»"Î.ùuÞÝgç•çÀSŸüÄïíN™øjXC˜N•´#Áê‘Y%e¢¾3L ]÷1…â •á •ï}»:R,=¿tÚa`äX¸U¥P|iPûÜ{|t|³îÔ1Ö’ìá*—TbD½ü¾u[YIÙØõwäg^ÉQ.¶c'r±± Î3Ö[¬À Âmž]éuò{ü}ÕýÞÌú®=QùR$ËK·#N´G|oöÊíu1š,Û­¥‡/Á*$K¨öZV‘]/}¤ƒD5rËãG0#p…µ¬j€~¢r—ˆ'¿õ<p¶›UûÂè7ó÷cÖƒú®©à]+K„X2긛ïèòãÕxè)¼tEºõUý~Å|RŒö©È;’ïy�[Tó=F1|.†5FYOeü} ôò¸í%åÌŒzÁ$ïŠGIJ(¶óøäë®ùwë­WYÏzÞú ~1”¨þ®°.©2³N÷8—îËzJõ6ÍxÚß÷ÜwR[¯£Ý>épÌzƱû^RGünµJ<vœmü刂EïUBkoLh×>çaV­']Ï«%ÛxGg½ÒxÃ"Ú¼°ZZüöœç‹á±«x”ž36ÒïŠ^w/ö}>ºàÈë–=åùŠ»<Ȭq_´õø©»èB-üô³Ò} ¯( PÊ‘ŽqöÝó¸³ù݉ƭyÙäx{º~<#¿šuë·F+#®‹aÁ{Y'ûô¸¥ˆIǘë©^¸TÙïR½úïçówöx¬ée Ä&™PC/Á'ô‡Y;A¸PÓÁå;ÙŽØï"Ê”¢X€#šn/[( 6X_Þ÷œ"RêQ!·èÕmy-ÅîŸk¦¿=Ö_ì ›Œÿ°ICaRT6q“û¼½C­QýL‡kÌûád_RqÂ�®sœ—*ôa d•ýR÷³G¸ɯ˾î Aë«iñzb%ÒYÁ£à/ËQŸO­}ÐÖÌWÞ“ž»®T;vÝuE¸äÈÈ ‡QÌv¶ãïŒÌPvœ|ÌkŽpŽÖq¦à{zܽVÈ7( ´hºÙŸyÃúW(ÂïÁ"¯ØØÝ†92zÒä,‡E§þ|—êɾ"rÁ.ÇWXu½Öq2Jp4jQQ’pÕ¤LZ¦T1‰ ߟӄnK{Óö˜#~¹ˆM¾ßdÝM¶ºé¾Ýt-Xøó:¯à%ý+øŸqíÙy9ÊüuS»û&)i>÷h@]tŽ=gà-N;ÙÆDø:óÿ¾íâ9vè¶Î;¯¬ã‚D0”qY~ÐÐá£çÚßãwÅqGðî2wdølÊê ¿nãµË£eh‹{ØE‹Éq0¡È™SoóÅšÙ/&˜¸~¬Ãl[òn¬AÌÒOäù2,ND¥Ô‰Öq¤ÛAmºãڤáà"®X~FL…‰M)óWLÁò~Óü?áº,óKy"÷{¾²¦¿{ïYq”Z Ã÷Æ‘1ÿNz «ÙÁà­rþ«ãyÒª_wÌ•»ˆÈG¢koâÚ-3Të5ø[÷zn¿ërðKûZ™Ålà[cDsÂ׎k¿m@Òÿ>äeÿmŠ!Å!¤qpHjÃâ`âñaçÎÊ{Õî„ÏÞ0¸ŽFµ3—ëO-™žæZ¯üºêÆ¿†Oßn–ŠRh˜tq’AÓ<­¶øµ”%Öë<I„´gû{É1a?iü{\¯ÃÖzõü «ÔåŠÒŠy÷ ‘ð»NÞ”ï»bMw ÿš†¿ÕÿÄý^°½ÆïwÝ<x~'ó»Éú›¬?¿¶zêüo¦¯Ç_Ÿ3„oqxIŽ ¼- [ðŸ¯à�ðÀ3 ±÷¾ê{Â+¦Fj—ña¥*¬´‡ißW [úþK0ˆð)GŒK†¤—´j'ÙÛZï§¥L|!ŸïËboÏ©S½ò\û¾«Ý[ÑmKÅÜ|d™k÷³Í‰BGXC„EŒÌ†U˜ó&ë¥~Ê\ÝŠ^õP›î½÷h1¢˜Ínƒ®m§ÑõâFΤàï¢ûÊÔ�äË.Û¹êÚ‘ßýw1ðü:H¦ïÅÅX‚‡xÄ Ã d=Å„UǨyjXP_Hé¾±‚hˆÇìo% îñ8 îa¡=¯üÁÏ 6´õs ‰«qˆGs~êŠù=« ܽÊñÔ™&9Ž_ÀuÈeÊ©ìÞUì†3;s°8f; ù�R€%EÚ.Áß&|±øMÏÄ#`:} ¦4‹‰>ú.¢¢9@SÁéfUÑsä5ì}� -¿¢rRó_Ák‚OÖßu¾]ìÜðvÙÞšÔLl$I*«ðÅÓE¦{Ó.:(»\okf<‚Ò7VZã–ö6Ýÿ=~—Êlé;<P kkœ#G,;vëh!ÿ~Äþ¤þØÔ+tzÕô¯Uq`ßáAê­8¸ËøÒïû¹\¿ö;©Üz®ã«Ý_ž?ÏO2ß—´‰úNƹÀzÇŽ<¦÷ ù}—À[ÇC…ÎØß.ç«>ÞÒï.ñÖ‚»£Xƒ£à{%ÿnûóã-Å«eŽø]]ݲàð1vøXå{¹ÊwÁíËÇçŽKʦû¿>îâ—¹‡�®s6yý¦ï÷3žë|¡Àµëž¯|å]ëJ¸Äözn]·å‹‹màR‹Î¬ÿë1ùqÁ›åCÇ4”\Jûqõ ͧ/¶öë+|oé["º®ç}oLø[ý´JÚßd´Ž- J®8æ¸Ê>h%±2^d¹Iï×Ú“¡ÍË!uE €8Ky©„³@(Ñ·�ZŠ>¿RJĬ’s²¶`¾‘ô&rX–Ë8¾H¾V°Iykc \j�½ÙcÓ²s?vÏÉ1æÈ)ð‰, ZQì‡ÙéQ¬ZS Š#šKÝún—GÛ.Úüx¨á‹uù4îåq¥óÎ,v‚n3suŽiÁÓ´ø—‡[àò<2 »éû˜ [ »¤—­Â!1µáb‰qb¿õsFŸmúO§Ô»aWsfÑun³ç‰£„Ÿ°h >ñMLŽ-»™¯°½8Pø/ø‘öÏ#3oMê'“ï;ù,,¸ùm€pŠr7Z“çuíìÆaZš?Çcâ·áNÓ“uPwtˆGLyºÈÈ ÷œ1’Âfñ,ÁfëŽ%ÅÑÆ>KÉŽ ¥xÇ-YψCµŽãnaŽ!ÇÑáA~gk „o’z6ã+¬?év,2ü· VŽëeGѦûÞú[ŽD-…¾à)ía1XCQ1ØoÚöý“šä²I—@ïôÅ$Ž ?9¥ cw[®f?ÊŽ,›ißIíÇ#Žl–)ÅA‰;Ú›pŸŸ)ϬµC‡—¥8°w”áO"ÅTêe@g˜ì§S½\¨8$wEŠ9z?ró½H<‹<)ç¥&r݇Í0@þ’Ç߉—hÆû®ð¨ÃT,ã’„`‹]P,ÞỜkΫ<KûK¹?Ò{§ƒ_Ã~Ó>µ¨èº‡¶a]ð=]窶Þ&½ÝÔ‘S˜ÀJ§ü~wÌ÷y^œ£FËJöð…žï’<ì¹u"ûgâk9"oŸí-J{a3SdÉÑ8áa½*{Ññc1¿/9S_Ö'á”õ‡�f×$¬Ùq…¤=â÷BWû.™ø"×íQç¼ì˜ï¥dzåûLÿê6·ôÝ7•c×™ÇnG áÈuÇhig ø‹†¯ð7»ÄÏ ×«àk÷‹C·3.‚nÒA×r‚DÂÏäȺÿQY߉†åÔN†{SàŽ ÔàüoV1V"À<ž¤ßeökŸÛ-X|K ›f¼GüLÚ9ÊíϘy‘ö»ÅòíŠë¦¾§ÑÑ €éí¸yÏtÀþWL-�a½>¯Ò_îžôÅÅØ�û†¯zOÇb>Òêá¾Àï/ æ¿“~¿ÜR…ÛÃ%ý=å£:eb2ˆ½‘`mƒW28½Ï/é4\Å&å>öÂŽï€é†®ša«Þމ 4 IDX¸Õ¶û™½lË DŠÒT8’±/Äݰ à8l¦TÜ IDÝ´GòÂð3Áz“MÀ dÇ9EH*å ?¯IÅ+Ö¼ÿà±|É@rDCúB6 Ľ8LýÚ §Øæ§*V{÷Ë+£hõž¹-…e¤¡@6zú~›±V?ÁÃz" ´ßïš¹wb]ã=žc'¸¯pÇ¡(8ûj¾sXÁújW° ÄX/)¢p÷™†;¬ƒâ^çcžêbØjòU¾iT èÇuüvß�S«Ê0CüÛˆŽ2_Å4Ð#ÜYHzkJ»­”‹éà±—qJÀTH‡NúΪµÍÜÚØŒ#á…Gqó”û¶‘b*¢CÚ³~Çiîro°üSQ¯­öÒw¢tï…Ä]W@X­Ï‡Æ“Q .¸úbxkìz, Q‘Oð`ÚRT.X;€žU¤ˆbëñ¼Ät鸽P"4íxìødÞ~i1Kä®ÃO“PNEYðS¯(¼ ý%º:vŠ™…ö{M¡Ãâ×_[Qcç·(l,î4¾°è*§u•¹øØGô Þ¬Šµê(ÀÚ4à6Ÿ;H’DQe÷?.=¯ò\?ð| ^3¬†Þýü¥qÅë%’Œß'ǃKÉs߯'Ň ]·ox8owòû»Úm ½?ožþ? ÇY|+\vŸoH'+Qø)×uåö°JÉý2’3Þ%tÙ^_Æ¡ñ$x î îÇåûøÃ¥vD9ÇÝsëÇó«Èݳí{¯ò‚¯2 nÙ'Ó7nñï%• ÷~‹^ŒA,,$H"÷ë@9!îÃ;ôì|çïóïÜßâ:2¿môºÑ|5¤ˆÚÍ8Kºè—u%ò<%¹$Í«Âo2`í³­î¯|FÞ•«�óùŸ…kìg>°fäÁã¼éèÖ²Ü õ;Z]•Ó]xùOÚZˆ³0Eú¡ÜµføÙ%¾¿NÅ£À¿_ú1ýúâù¾Ô“}åº܉¿ý°Ês†—÷ò÷æ½”ý®zßiœü½àñÛ¡˜<»¤èy—íZ…YVØæ=¹v~È¥Ϧ›-ÂwÍ÷y<T°Çdø¹$ÏìÁòkäŒj?ïAŸ‹vó{9ˆ×SâY¶ >©8<Î|¹1øÖçÝÏqX£a0Å wF<Ì*>Ù@E¸ŠbÞ×sô 1iöÙ(ä(ãQÿÞð÷ëÇ%ªè[*{éç*Ï9WŒÜy=§ª”ñ¸îå\dˆ�ëÐá×Oû<ܘïœcÉqÇþ!¿*‡´ª¡a?Ó³áÃÚ�c×꥜óEÍœGø&Ï_G;ÖÁê€ÏËÙ]ƽé-—\{âÐt]á%ñÙ†çØœ¬šã]3ŽG(†£¾z–þë8â�AÇ–Y:ÂÓq²ÐEûЦÌ?ùy¢Y”Hµ±oSqôÇL©1Vïg ÇYv,ÙåüËwkìwBº=$<Iq?KG•#ô™ ÇÉb}ÄÃBÆCteägz,wÕnœäó‡?\"#×a<ÆÐÈ«m}u<k»ãZ:’v‰§¦Ä¶°¿«ì'ËÁZñçk9Ê òaÁ%Ú;ÎòTv¼ÐpÅ}xZ]N/§¡M 8H¨’äV¹ƒòÔF¬˜Ó”6@‰â{’bKâo囡#Ê áCõ7CÇ«.ØœÌ⾚_k¸òã-‘Ä=:4H‘,=$%qˆŸí p rdè �ijÕéˆËyîGè�¤ß0›é`�Â2ñ¿ ]äö*t¢ÚÛƒp‰hMåß/¹ö²ƒ‰1ô—‰»®~£Ïçâ°fÅ@•é6Ã=Íðªú_âóŒëwÂö®ègõ½ô3Ãu6ñëŠïwù~­‡:ŸÏ“º¯³ä[®¼þÜWÐâKBGi²ãÊt]ÅŸêz±1P—gòÙ–á_Æ)¿ |nž¤Ÿ¶g"#ó¼8½ ðçß{¾ìÇXëpXªãe†·…>ªóüù«Þàqoºági»häWW*EtÔï*>ÅaWŠÅ/Éw^éŠ<Ó)Óbr7Ø»Z†¯’BñM°w‰Õ#´RyaN(ÏRÞî YÝ)»Ê› d¶—N‹0 ¬™jQ"ÇþúŸ}þ§£|׫ö&¹=#@{Å+Ò»xœ<6ƒ”z½8bñè–vÄwfU÷J„ÃØ[p•oÒ“ƒÊ&BK c¤â])¸ =ßâ ϼ]xñ$ÿÙ‰�„žò}ЈyÂ{â6¹¤ò.ÕG:HÑаh~Gþ^úß#V¯‚—0p§kAy\K»ëi€Ã"Š,1vE<hØ æ˜°¢¸}Zj$uˆˆëö™‡½ìÙ¾£Æ4Áú¤Èl%…ˤâkžm÷ùû±Kâ¹ Ž. î,Çu�—’‚×ÑÏ‘;ÄË:t„BÆW«Œ~ã:éƒðÇu�ó„礅×=âKàÝ‹úV§y¬†3�wq\ ÿ~6`ÙH°²nV >ï‚-ã2OáLá­þZ±]œ'cøjñš¶°O<VxÑ4ƒj'*´q§ké®r°2 Úrip*e½Š.K Ô².æùþĽ?†5ÄID•Ðï]/E¥5â<¦ùØ4ëm…ø9qwy!¿‡™_i§+ýJ)²®V <Jñ“ׯšgË'ù÷±àUú¥‚Õš[ïdÄ›à}ž �5/|Þåób\KïÃ®š·¬ G_’à¡QøCùÞÐKSúáøûlolûj½Oü.¯WÒGŸô1å&‹i·úvÞÍsßá]ø½(ìúù»ÔÞ~»IQd eȸå™íezå{ozÙ¸« 7¿Ï œO~}[¿Í·^3´œÝ*HŽÝz]Èß —ï-œeü{lÇî§²Îïb»w/wqüwºuR"7eü¤?Þ¼™ù¸“˜¿‹†;s$_æ÷‚oÎ{Cx$¾%=¯À®uù[­[ßžû]æu-Ï›Dh÷Q<®¥T !f]õò&­»Kè‡ô{\°Ÿ“(ú“¤¯>ÉòXÁ}gYw,à=ÿ®¿“}ÿ„ŠÅùÌö(o^é¸Ãýn{æX5á yå[ã,êŠbmhórm1@EôÇ¥9I‰„Ý#×å·ß—õ¸*0ˆ¡¿ ®é¨ðqáË«î÷º\ëçCöÝùÂâˆ'Náé׿Nãlû~‘/ŒcQ<ÆÖbØ–²Gº\­ÉrŽˆÇ­˜û=B·J¼ÚóL»˜u•BMÚ¯²ãPÃz.r«ŒÓìÃZÁ“/§Xí‘ûTXÀª~íñ®‹NhÕ”v\kðוš?7¦—l�©Êv¢8:Hx óTd\Oò³zŸ#çØORÀÍÛˆ”xÝÒWªa^RýÛ½®·FáíιêwÓN<Îã·rw%ÒÍ:@u(âUÿ�•Þµ_•›½Ã“½ó­uéf;÷’<Ò›`æIúm9†Øx›мƒ‰Ã‡·´¯Ô•-‡,•Üèf9g@Ü÷‘aªô»› a0\BûSÃó4ÂNÂk†GGºLçÕ†k½°×4ùÛ#ÿ*óÀqDQêsV2JðÒq$…䨣Ç“cEXˆW阹êÛŒ‚V pYÅšçgÝày¢ùaäþæ‰gî·a¾¼¯žë«h‡_Gš­B>þe>ÁÍîCˆÔ3åØeÎjŠ£§‘_T¹ÑÈy…=žŒú\Ãqu˜žd•´^Îø~â"§Dy¿ÇóÑ%bò¸ün°Rþö#îQÁÞof¹;Û9 L#9¾4�&a5®ÁÒ�Î0 §¨Fæñï*ü!óïÔÏ$¦+]–ÙÿzÑE¥¸}Ï7í· Ä“â+™Nz¹‹+ÿ.ißf½IG*éVŽs–ëGxÅ„ŽBŽtè_ö|Þæ»“=DäH™˜óåŒÛG&Ù¡‹DáŠDl¦gÂsD~R 2…~´£…Ï$ ÅÃsäà-tb×Õbx®ð÷ä¨"Ž4^ƒ@p<wŽd"|3—D6ÙyŸI:L2^Å*Ð'¼Î”hÇgÔ¿À ºêARÛOÞ*ÞføÝÄ9bJ¤ Ÿ)ó4=ÂÔ?¯ãD/7¯e>,^Kdo..U"ÛÒ¸W„Š<A‡Ø£„ÿšÿvÇ¿ñ†ÅޱóÊÃ2Tu Ôc﮽Çï›òþaÁÙ2ñ¼djÊÂÚ屮/‘bí;ú¾ëº3¬9öR>½µ£—êß»R'þõ·|þé¼C¬­pÒ²À¶è®í…!žƒ§ª£’ºB~=¹ÑjÇ™ÞXTÆZ¡’·vQ �0Š(o v³qxÁ¥(úžðýX±ŒÌj æ»bhÌ/âñ¢Ç–‡àtäNW 4ēܿ‘ÉŠâСö0Ï”JTLdƒa¯¨Ÿxèg<»œ¯xw6p‰FLW“Â*äDrIã‰4 …+ž¾mHQ-Б¦<O=§ˆkݲä 7íùªß2×}PE`ß|SníI‰> ¶?p ݯZgBŽŽ<=/8 =„V=tdÚã3a•ßáÞ÷/B·¾èñɰ-Ïn<­–ý8¦oô®¸õ–¯ m+œ³aPÆëÚë“}[ÖK¢Ö;]Ÿ­ �� �IDATÉsâ[é—Âz‡ ³×: _°¾jw�š{ÄÛ�éà_W„öª|º}0mò{ÔvXó)¦%ždŠØçøL¿=·׿D Í3…l1hfÅÙÔq¨ƒwUAåè·=/¥¢(öóÛÕžW,óß–‰Ô4¼ÄwŸÏcÿ¼õ?­ˆƒŠ|_iÏ*$ÛŠ•f*ÞÆ•ƒ{e¼j|-?o®÷¾k¬¿W%9âTðS›§¬ˆl�DK þù°v€xRnyL +‰ ÅZ¤cM¾{ÎÏ«5,€*@Rö¦ý¤¤ðµFóyß/‰±k_÷“Mkÿô|£ÉMÞ ¦è$*Cv8CE÷‚ܺ¡îlQøù'§jlj®¢<׎º³óX É:¼!> )òN’ŸÆiÜr× ï4«®WáWTF‹þÛü¼*6ò6\?íúö«¦ƒ¾Çt_nÓ<¦¢GžNª†åFÇŠÆõçF×Þ·¼!€9?TñݾbçK­ÇiüOÎF( Gž££øSE fhœáTÁ©’#ˆ7°•vjýh<x#Œ8ø 8=‡­â“o ΊÉáÜEÍ ß.»Ÿä„–œÚa:õû8˜‘$ÁÑviÜú²£LÁž[‘Tü5Ó‡ïÇÔSôV¥—Œ‡˜úé…ž¥÷h XM ¿n¼!·ãü]—CüLƒT^d֫οFþ¢¼Õ¢Ï­šÜ~QjÇ71(ùHZmÔŽ~ÊÞû΄ç­G/GK V-þm÷CɲJ<f:ˆC”L(ZAšêïq\5[ŽìFÞgsÿ³¤ÛNGä°‡\µ4Ýò—q¨hGVZ:‘¸¢eGEOåáe±}ÝŽ R2%;8¬ƒÐ%Ö›2~qô`½l Âé­bŠš*·6ï[øöãpŽ~>¬¡¬Œ¯mš ì3‡õH“Ù4qjñ@”È2¶Û4-yßè»6ý>Áýnâ2T ÜWsªb1ÜL¡eoZx>U†ã³ÒN^?~ÿP3¯ ûb ™¡!à*ẒùŒkÇþKdg¥‹·¡x¥Íç½c¨­YÆ3ñß·p<]ß`ã Õïlï­üå ‰hÑgÏã¥êx‰r.€xß ý.ÑzÈzKé=oh-¥ì+¾_×Î÷¥î¸¬oƒrŽž‚§®ï§ÓO…ßy¼^TÏv!=ˆ$p›yýÏ>ø—±žð´<Ç ö° Sç}ÿ%¼¿PûáZµ/ kûvÄRI)o©|Õf1 _oï¨×¾3¬«ø0 f {k~_1œ™È0ŸJÀ_¿ûóOè©�÷˜"1æã^ tÒï«Æ@Ö‹{ç JØWÃ.€&1W}¶Ü³–xÖ7Ù$yü'†ÐJ7à}Zþå²Èk²€¨ðš£!ïZ#Ò“ƒ¬\\;½(ž¡’Jp“=ÓNÆG¹ÎÑ,äá—Ò2û=‚(N; =wgJ%¬ZJÄK‹ÑRQžö”šçþz·ÇNhï*AöøÅ¡7ÌõÅã 7~~ù>Š'o)4ôdOo Ð_rIp/+ÂÒï¼Å2('¢8*½>ªˆ“M‚±-^ÑîÊ\¦—•8p-î[CYþþ8Ãïæ¿¾a„Õ¬�M‘Z4Ô†ÕŒ7FÖI}¶" 2YWiZ¹’†©÷¤Hmý«RU´yz÷p÷©øSñÕ6ô¤zsŠÎF�®•g¡kX.üHºTÛvÄcq?Õ T$d•[uã]f»ÂG¼‚o¹ÐA‚·…§+VAÙ*•#µ¢Ÿk=ÎK%BfüÀöë 3ù»öüÙ÷¤›>á³~qÈõÃÀÝ„sLüfÃMXIxäºéc™—¼¤#Ã5??ßÂ/3]Iÿ¬ð~7ὃëê„ý(e‚Áï˜í/¾‡Çü k©$¦Œy‰t#žç9O¢8ì‡+q )n­rô(ëÌôç;æ‰×¿_µ×»P—™ÿ^~ÏTN™>í]…=Îwã IâYœ×ëÓžÐÿñx-"WØOÂSË»Ð{#óJ…+ùi«P(ü-'ù³ 9Ž'+಼~¿æR&‹!­8¼8þ….²¥ÖožÇö¼Ùy­H»lXÕŠ;íÀáæE<¸ÎöÚ¦N:²û. j…Š|ðÅ­ìoš2ÁðŸÂ'3ŒcþÞ0Ïýñ¤˜fEa×¥(j9œÔë—}U"Éå½v„i¼!•yÉôR ŠfÜ̦·¾1ð5Ž>dŸòrטðõ ߸¬C»ÞÛU¸›.¾‘Ÿbÿgìbh#V½|ìöëVä)Lÿwðý5¾Ÿ#>¯ñΉDQó��¸ÃíW…ï, >¹o[ú•"çßI÷z|óWá‹E^׆‘Ó‹a®A§ûð»S˜ÄO‰ÿsŸäÔÇI#Žt8Œ tJž–z‚4Êð~ÑÂ|<B“ž[†±äÙ%×1‰pž§=*ÇJ ÌóüH9M+4µb±E§Q0%<gLJ‰œGs‰ö(/Åkp…)\ïHô+çÁês|‰ÒW—<•ggŽa cå¸h×aKNµû·ô" ¹ƒÖúrpDQ`Ù÷å<F~‡=?~ö“ß©˜þ?ã|Æ'uE›r(‘ùܳûX®oÞW"ÓV§ŽCŠO_'9c‹UœÎ8ƒÁ$š*VÙ±N'­D>¯¶êí˜gŸ!í7î_meKA+†´¼ßÙùô²U§¡óŒxÒ¤‰Þ‘ú±ce~®šýSÌ×M§[Á³ÂO¸ÄùšÉ çj$g˜gDÜA7}—Úúqt”ˆoîPЮŽ=¯5øŸXƒ¹D¶ªú­}<Ï ^2 ¦ƒ?ƒxû±ãœÉ†X kY‡YœÁCËÐaôwŠ.ø…¤Œ½Â™»Š–™9ê §Žõ0«l·un6÷n0Áž‹k¯[ÄTOéYî@Ÿ8ƒÛ áKo籇€Ãl@´Š“<-=/áÀ%žK†”5Ê»n%äΠ]¿+.blžwŸàª9oæ÷©H&‹|¾F>×¶à·ó?áw ‡õK?’²ñªë?óEWfüü˜ÒÎÐ%pImkØ]rçíKn*ãm™~:Ö¡d¤²z€6\W̸gx÷ð$ãA23X=@qÉey¶+ebÛG>„ž,=HO'Α`ž)gOÜ:g{'éî\þšñÂz2©?a»>CÖHúãï¢Ï¾ª 3û—îçŸ|ð'± <ái7._0B¬ë.®4†÷µž¿,C×"¾¤œ—rqê8|?mƒ˜Ž “Ôˆéùm­È±ZÄ–¤D,)}ÊÄ·gƒXúÞ?—òj´ _Luˆ[UäW*oÍa•;à ¼ñ4”ýÕsø¦‡žéÞY °ÂöxÐ[åFCš"<&)E¼ ì#@Æfa”d~+æ¶/ïIŒNKº¿u ò=‡>ï›öÚþ±*¨€0ª>^IÝ'õD\ô·M©%p—ÍLÞ‹AD}Òï lÙ'þ¼BP’­d…™àIGZ©$l|¿åFlÅ À¹}#ØçÄ@ö2ùŒ§¶'d.¹ßZŽu0åŸÎ=kÚ³ø¹–û£¢*o,‚¯2ÿ}3ÿ+y|ºô!6¦Gy?+È$[ö7†€R¯•–ÎŒzÙ³Ï{NìÙ¯r;+œÇýê†ßWŠÀ3�c\æül±þŠó¸?6íz\1xC¦×ׯà«ï6RB%¾âz™gý·Ž¥}oXlÑ¿ù½G8›N8}ò�lÆ®½žÁz;mʪ›S« ³Ý2kÇãƒ_ߤÏ}â?+šœ±Ã�ù£çW0íëÛAì|ÙùVôÜ?¡:á¸ý|g¾MÀÜq"£aûóft¥xÑÚF. ¿-ýž¸ËLÎÞîK]ô•ñÄv²/•HT;ßÒNqÐûÁ˜‚d¿sݬ¸v¯Òþôï*óéáœú{QŒùý&¹] ™.;ð(ó"x»j Dý2©ae•ç,gtlÏ34;…æ ùž“Oê뢔̿ÌxÇ<P"ïCÝœ¤>þ÷¼ïðžç½cõ&©Ë~· ”0»?H$´$›9€©r äF0g À¿ÿ‰G;ç1†F®®Ü.•à“ñæ»H½ÁÊà©'†&µo¤~ÊíW"i¸uÄ‘–ŸšâÓ½F9ežIUä¾ÊGb ¿J:¾â°tÕñ¿ùõjåÖ2Û ô°ïè=óq7K­ý¢ ŽŒ¿Ô^Kž5ІFy‚[ú³ž÷ãŒ7¿N[òíTF%bÄGêçyªíÇj½uì×ö¼pÿ¿]ÍlŠJêÇ5� ¼BÏ)òè — rhqóÉöl.1P¾hq!í{‡¦¬¨L‹¹ß«&Éa“ Röº|ƒó9LÇþ”ÈŸ<„g?{î»ö¨h\!\ÿ¥nN-øä>¿å0bÿEIºoî,SÅÑ£ðQ‰\ÙÏ×Ô¿ë2ÜËúÝâøK+¤§¦cÝæ}JžÍþP¾—þ·0­T2‡xKæÞ 3•\À1"—ù´Â»¯rd=ÏGCïXAƒ¢{ŸeZ©i@ÜjÉGŒÄ­E"›z}Ó.÷£tÇ&²B6&üOÂe~ÍùP²ÕÿtÔÓ‘¦öÙØ}TR•c¤vD(ê]ioÑ:Hý‰¼·ŽÎá²ßÆ=#?´ñÅy¤ÃÀ ášÐ°¬ ë]†�=ûe$t¤éÑ‘¦ —íüf<[9J XYQš¤¬cVþNÚç<WÍ|6-6»Ê Z/rOGäCȆª¿wåó$;~åS½Ë4µmÑdX??6 ¼m,;h¼Cø]vTËp9â.JJÄŒGº ÷—á„tp˜È¾–ñÚŠ]wY÷öŠ’‰÷ÜÙÑ"eø¸÷ÑÂ\X‰èõ’øû Ç=‰L žñ@ƒ‹à;ÓõQʂյ΀öºb-ÙW ½7ªÝŒÏ¿B‘S’ãʾI-)) ¥¿Â=ÉŽi­ýÂ:úyGgfšäñySª•·JÊÉ´¯•«,v$׌w"ëBd¦ž'å÷™”aC¯ïÆÚ2?3ünËðÕ™­âxÅ7öŽÍ wx錘*ÏóSÅG¹ñ벟‡ªC\^Â7ã–ç„ó²;fAÚëY¾^ÞOsèQ½u8ô´öyyè×OÁ'+Øù›a}Žû?û«šžøøÇ~ñ®úl–ºî»¨Áë¢w‘Iÿ`ÿ·|I¸i±W™”‰�xgXWªÂóS'É ¦¿+)}©ß!&±wªg)]©_Íg‰ C1Œ…vd�à¯>"1aü%5J:ÐÑC¿—³JÛHTo»@¼'¬Ä5 Ìå ÷ =•©(L‚A¼–ÞkϾ8,ÏZÒýÄkéwÕ¾0b¼’ƒTOâ=ü~à¤ÂÀ‰�ˆ£4Þ0H‚E<¥çÍ0 ÚÓÛñ¥—SþE0Kí–do©?>Rü”Ûžk_¥¸´›ÇÛ§gÎ!’g õ8Š¥ö8ô#ד9¡`Oéù49¬•�Äc«'~OSÿ!X¥Sq>Æ_ â)ã­ò8üa xå|-Ñ]ãO{¨#+¾’X6âwØ{Ía÷ã¬î7½§Éã= Rûñžä n§JŸ ßxXðž“à ~ЋEq»îèß¤È >ïIë5 ò-†BâiÜJø—adéD \ñžô攇¿Qx²ßk2Àr‚*úÀõÜE̓á#§.’Àå(ÜKî¶lÐjÌ{‰4‘ÈQF =.¡ã0@þ�Áƒ( î!œƒà~××7à"i„/Šæ0Sajo‰­ˆGU¿ÀÅïá¤Ì[†ÄòiißFÒœ²ÿAI}‡ _òÝ@¾Ëð\1ý–Șdêó÷S¶;C€ô›ùJ24ȸ$Bë^ÒÍmÅ@"í‹S™çÁïççÔã/··RWôe<çäj>—=ÛM†±Û¢þLj¹Qt¯3 øDÆÝë ì2ŽAÞoE]¿bç3—1çÓË¿1ð>ÎÓ½|ún¦<^VÌ<<|~ŽÖ4âïìˆ°Š­žçü}TøB]!ß“u£ö=ön"2îÛüzêØÇOó8íü4·7ù`æs±ÃàÀýõr‘ìÿ¢xo„?{5ÛÏš¤@“Hˆ°$û=ñÒ÷ó_ä®gZGÁGþÁ™¿ú)åÆŠ¤}qìSg¹aÜÞOeÿ£|@Oj€,_„§H„Èò÷TE›¤!ÎiÒJfOSòÏ0ÈÉ-÷éqoMZ©°+…b$?’yâÍ$ô/Å‘ßBa!É ©²»þÆì¯OÊÛý2ïã·[9¶µÛ [DŽ |"p<ï¼ÜªåU/Ïf¹³±ò„г__a@ÅUî7C‘—Yw²»_£:k.+2|ß¿Ý?õùÄÎSÞÇ2Ÿtï] Èt¾Š§é\äùq…c\âˆpZŠM§Ðù™pÞ®äöû9%=X¿Wæ£Ì¿9M È0 b°Åœ*Æ Á$ŽÐ‹k@f…Þû¹Œn—g‘›Õúi4=ž{xîºÝ)t{¾¸ŸMpBßò»îï´RGÆ‘§·Ì¹S¾olÿt‰ï¹Ž ê–m븕éÝËwâè—Ê¥¶ÙG"÷¸nO¹¿ ø~¬Aaàúá9GË•In“úGy¶ëVÚŸóz/‡…z¸ÆuyGQÌz…a“æÛ×h»Ãø¿§ün@ÃÕ):eܧtŒ¸] =-c9—hG‘SÁDq¸• {©¤ïЧú áMðϹþd\× n×å°C¸Ó8¸ïõœl?Ë¿³¨ÉCÅ€ºŽ”’q¬è®8”n±_9'|¡ñ[Þ.¾9gPrx1˜p|ižç°Uu¬m;`,:‡ ï %õó]ÞPk Dzw !ô¾OÇY//ØórC¼ÈøÝ™ù–RΗeþànÂsGž÷_·e¸2õ¤½B_7ßÓ#VFHwy rýUô�œÒqv#müÕ([âXØ2L Ò¸Ù¼ ¯-õiÂ_�¸ûáÀ Ä Åý —Ã.€kh‹ì à û4t®IX d’Q¥ìÛã˜"|U°Tpžð1B2¤ Tdu@IûÕ)éoàè‹¬?iÑ7ùkËÁB7d¾…~Ðpç¸LG‰Û9Z¯ü}±¾?µ Œ Na=tx½všƒ‘Û3ž®•¶�ÊÝÑÞ1êŸK¦/ë�9á<ÌåÈF™¹Âo¹ªòƒ§´/Žó^ÿd×O©'íìº*xòën†ýÉúÌl·[·b˜[%} >[|]?{øJ±•e}t9R[:½Føæò¼¦~†ùN·Œ/Â݂ϵkñ®öKίåwíéû»¸þ户åž9Å·ßxàüÂC³ÀOû2ľԈ®ó fæ÷‡aðº¨!í¿ê³5ˆÙ”‰mƒ` dµzrgØ}SR&¦òâê÷RŠá*ºÞ©R"¦È1Ÿ"ñ­º #È.`ÀûÏ?ñ¹ï}H{„œ’†ô|?ÍžÐË®!ì @ö}Q¿K’ˆËFA~On×zbÁ¾)uoKàKïgóï—» ÓnßmPE³ 1%àx¾8Dñ¾Ç{ÚÆñR÷oˆ^Ù¥s°QðÑ{ìe¼ÔD¿û„³@s`ð<À²Uü‿oÄuèƒ8¯ÉclÀMD¥lóÿ GËF‘pʘ>SÎnñš›UÁ¾Ú³íŒ‘T u†d¸æƒÈJU�?Åe(2Õ ©ÇñöÌ|À­ƒSEŸ©½ËÄ[Q*s<–"ú- ÑhëcŸ¬à¸ù¿ô»Åù)ߘïMªÊRÎóà £·¡£’‡~‹ô³ �a`oµˆcò{³ÂP†Nåw”õš`:„(¶mýb; \!$ëöS]—aè: \’|”è2 óA,•âŸù›ÌZñ,ÿžÔ®Ä¥ôn#žJ„¥+Þkn7@äõ!ã«òc¥ˆ•þRÿK9’å€í_f»¡±¥ñœÇ£i°—‘Ü·ÒQÆÃ<Ÿ'l¿‹KÁ~%€x :@ ï^qœ èᔿÛ5€²§ÖeùΕ"&ˆVÂ. Ú’ú‰niÙ‡z¤c}ˆwŠªx˜~ n¡‰Lº³ÿ“ wºbžíÊïTœúsãëëq‡l°*|•¢ð'­pþd¿0ë æÂ³¸Fúóy™Ï‰>fmÿñÌí?4Ô„Y¾¥ïdq”àPô-ðoi<^�»ïå÷‡œénã£Oºs)=Â�tpžórØ/¼r�â¸ó¶ ï¸ìøiš—Ûø{Q�FÓx½¢èÔñë;8ÜŰ|"|Òà¿ì¯û|n yâ,ór7\Ú—¡¼ìö¯"'êße=Þ®Æ70¢Â¯¤Z¹¢¤Jûß¾¿…)“Ó>9Ëç3ì32;í'·ÁšöÎTRš1ç!Ж]D<„¿ðé1ô>œð?Â2÷}Qdn³4¿#Ø;\¥=â=¯O/ÿ¾¶»Ìq$ùl–‘Œg”Wf[wøÀõ#í)ߘ»*³C²œLƒ¶Ä¹s?»½Àmä!%¿òYà9!æyÀv)B ýVå®S÷,ø¹s¶u ß"žVä½9øÙ_¾­H]Ž#Ëé|?oÖïˆóQð0Ïà<<p_]Žk ?9:,­€rKЏäYïÛ—¹½IØ…?ö×íù\wåûï ã À=n¥‘ßsßb{Öà:¤âoÄýqÀqÕÓ^¥öv¡Ïr—ݱŒ7{b'|]&þ¤^>?9UŠÐQKQ“郊Ù™§é¡qŠ¥‚7áëågçwùª¨Çf½>¼RmïÌ´ªù½”ž¡‹ržlH pÏ+|n\;¢ð”÷¶ý!ë~¾ožÛxnL=8ÅWQÐgG6¯¨*Ö èbˆb0;ÍóãS§ÊþáÏÝÉAÃÝÁ* Jÿq”ö›0,‘\”W¬á p¨±¡#F1ا߭tR¾ÓŽe¼ÊI‡ ×O‰ì‘þ”CI<¥ÁSâSZ†5ëH¡åÃl¸ìñ4ÓÑ’‘đ箰œúܯÒmËñ4Ð0N=ƒª Üa#â©Mêr‰§ÖÀ^Îâ â#3|=ö}GËÑ«å`'ç1Š×$¯Ëúu(øöŽçtœ¸#ã!Á»˜ðâ±vð-ÒlH‚ÅWX# ÞžÃó0ˆ„|=åÐ3 „Âqu”ìp/qO©÷Eô˜*7áY~Ä­ä@äó’à[qºxTÎq�Ä»ã¶y>JªöâÌq…e䤿"Ç›Ðij/pŸ‹§ÉàRYœAe·ÑKŽ6•dÂC˜KŽ)ññ"‘\3<ÌYhâÈ:xkG3¿Þ!v’Bœa&E²…AŠ˜Š§)Ò);MÂé`Û:~•ùôK„bÁ8J9‡¦�w�N®êä3„k[ÿ^è™ðßÄðX¹Õ²ÌK¤ßóúäHÑ#ë`ä¿ÏŽư¼c‰Ô>-ýéuOSDZprl¼›ôtG«Ü¿ég&‚Âé»Ì×vžŽ6>®;IÍ>iñÁm/ÔéÁÃ+óæáÏ+nÑ>çù5ü¤À)κãŸpް˜ðH—‹…ïÀç>ôà‡šžô]Öb(ç˜|=t¼?¯Ý„…/ÿβ‹Âñ|�xꓟø½õ;Än^rÎ]a]¿KdØÛ¤H1[ÿíü߯tDX—¡ ¦_^jÚÄÖ¾Sï?½õ¹ï}è™T�§ÃW= žY#̆e4(¼‹‘·^qÃÐéc 7ïÃlâ½HÜm\h=a¼©H;æ’J }±ó€þú§¶W åa&õ«%Þkûóp@½‹Å¡W ×oß l1 ‹Ä×Q¾3l�ÂmüýÞh  ‚MwWÒÝÛº^TJ/["xtØÀª«¾„lhtž³~^š, ¥ƒÄYR�…ÙxžÃrëY}oæÇªtÕíc@<ÛÖÃ- Úæ;uÀ½°1³ÈÏÔw€2 åyK†Å/š6`õT{`{¦ý¼qlÐ@—æó¬À˜éb `6Ís~˜gò»”rP¶Ï9áE¦‡±Ë_C;Ëúg½ú9vÁ)È#7”ýx[%^K ¸°”rÜèÝøfë_ã,šï_G<¾6¦öÂñWn Iëîפð¹¹9?T åg‹Çay¦"T,¸vdEÁf=Ћâÿšo@Ql—yõ†®¶#ŠÎziã±G{R½Ìæ[éâÓ¶+žÁÃ<ÎAC<§ç×Ò݇£Ólàî9x˱¢Çñ4çŒG{ÊÍò�qÆï€åj׬5æyÕûç—¥~Â×20ÄGn ¼¥ŸÆ=׿Gð2«’Ó6_¯…ß_lj‡³<ŸÙÁ Œ�¼ŽŠÏ׿y•2ÕVIl þ³Tä7­v}ýô~‘ý5Î<rVñaKð üË&"mèÍ~Ýöó÷v÷(ð¥u(†g‰à“vÆ4e~kÛiÏ#‹ŠUÑü¢È i}Üæv©¼_øvÉ_gù^ž_Ë/eÿÉJ¶àùˆÀ% ̾ãß[¹k0J¥©ôŸö§ùlúHp49’Y×Q®ë³¿1¿—­× œªÿïÁБÈü}6̥ȷ˜n™*ûOkžè“Z•¾! M«è1¥O8’ÂN Ï"g&9ø6¯•ÿâY$Wíëè¡ÛØÿ½A ›”¯Ùª“[ ‚³l0 ÍÒnqÔ²‘ùcÂ_à†9È/Sqëø¬7›ðÏ,ÉF Ï�� �IDAT<Ä3'yÐ:tÌVÎ ¶8±Ü¿ù®àÉÊ×Aä’&+°šäÈ’æ#ŽÂFfEÍÈ$ Կôß:ï8<I†¸Í¸j¿í’ñ8OƒŽ;ñäóÒ2 ø¦¥¨Ò‹3r«ÐaOá3Ÿ?òxæýÝ/ÂF"¯‚ñÄÏçÅÒÿØì³ñ„˜œg›†ÿy 3¿=>7�òÏžðeÁ·À'ôi×ø Ëš®¤ó¯¡câ;ž¥ói˜eÜ‘s˜rôfÓs<ã3Äñk¨ ³ä›“,Ÿok¨Š"Zž m¦K»Žã=™ŸH=>Â=àz?úðÅŸZÏóµ÷™¯µÏU|Ó-ÞKÉ I®¢ç¤*Ÿï}Û>`Ë6å/ -rî˜H$¿@ãÎñ4&‡ŽÛIɹCï“mÃã˜ó§÷ƒY~'r€Úgä—cnç¾r÷ÇÛaG Ž!Ñ:8œ¼„ØTéN0£1œö,ËíVžD®ïࣃ‡7dËy»È— ¬·ÏqØ”¿G-©k m§Â­_%!á¹f3‚ø¢ÔÜm#ß"ËqV^¶7èÇäÒO—ÃbŽ˜sûA]ÓuN*øéGøG‰àÓ¸|L`If2¾d\Öa 8~HÙ8Ì8 ]Ë>‘R/Îb¥ºã‰£U“"Š‹>…ã8*ç2Fj¥ýIð<ɸHóµèö¯SžçÄQÿˆ3>È©tW8¿L‘ÈïÚ&+Œ<‡ýç@"f¾4ÅÁ C?’Ï‘2^Á‡½cnÆ}?áxxÎ<î<gÚöÅAéŒç©Yµ>u½Rê?‡G㈠®fakV?»èÎIpôÔn?Á]îÖ] ¾ìz[äùqâ²J»ÙIÚ7Jwä~8Î>çHX3þÒÎ¤Š½[o]ãÖYßF˜yÃÜ ¿ƒ†¶»]»4�c‘ßÁ–°!y6\‚`‡wä’ç.³c)–>gø\ – ¿Ò’uóƒx`õ<‹|žðùî\?ÓY|σÿ66ÀWÿÆM_ ¯¸¸Á©b z¸†¯®v.ôþË0ùrÎb?þÙ¯|h#Þ…—�H1)oÂÅŠ¤BLb©¼Þ°õâV»ÚÆ;½ðN÷¬KÝç#ÅL„X¸˜v÷Ù§ÿÙ_{(1ʤ ÓŠÌd ÛæfUóVH™®`ëåú=*S9«©ÞLIíö]»]7rØQUž¦ßÅ÷{ ÓJ³_}ßs >/8z…vϽo×xxðx×J'íá lTn÷� ðÐçsJ°T­7ËßÛ¨Åàå6ƾܛá±w~LgJkt bþ¯<‹é9NuHG:p•ñx–¯q_Î ¤ÔoQ ŽéÏÐâõ þý¥Ã~\ ¯2×èÁ¾dRQ”dySé2Ä_ÇçK÷õ<^Á7ò¯ ¾±‘zÝ‘bFàhªÛñŽ2.EQú=\JíÄë­g‡×¬�IêŒKéšøø:^ß1({…¢ ŽõuÕ§"{,¾ë èJ}HýCR ³h+x ’¤±}ÛØ ƒ~—‘_Ë¥Èש¹,Þ¼ÃÀk© ¸žñh<pÚϹŸ†íšs¦ì³Œ‡9Ž·gÇË·EatH…ÑM‡5Þf^§Ð•åéå&¦Câo©U_}—x¢?›Þ~Žè¡£Øqý´½Ëo^É’'ö; ~Ÿ$R6<ÓÝîÇ4à¥Y <€/ ÷bìk» ¸·l6¦ }«T|ˆ¤(RdUI×0p)U‘¢Ä—Hªªî½ÜwcÀ¨. ª^ù°á¥{5[cº§ÓÓW$¥ïЕ^dDfDdä9ç£jrÁçœ|DF¾ãÙÜ‹t„ÓŸ¨ŸõKt…´@8h|€¨ý§y@éŸæ´±©”S£ÏžËÿ #ê/­gÜ/Óì\d5þú›ùO@)õ£Ißõµã„r½§ë+úÕ–[ `Üò¹˜—*ý»Ìy>¡yc”Æ·/¸¶Ž­Ò¸,8dØÚËÌ&¿¢•òGfýÏtÙý˜¢'­¼N²mQ¯§Åú’VÌ÷ìzIÎh­óŸÝûE�Ê5bvq˜ by<ÿиKý뾪±¤ÂìÈbŒ-ðxý¤u�V M­5¾ëù~‰,Äh_vÏÔëÀÐ_bMýäÝYc�«´;¤m±Œ1­SΩ¡¾V_+@mѹ~U÷Çmps9÷1M¨¸õßõ¾Ÿú5ÓsKϺþµ›�kç˜Ü^Üo˜’u VqŠóe ö@ċЬXÁû¹E­PD!+˜ð¤<¼š¶Ø¡ø[?nåÝ’ á‘“Jj¿ü=ÒÉçÁV} _˜T^²”óÞËôñûz¡`bƒ,¯¥v¡}ŒHǹ?KùÆö´ÁZîfŽ¼ÛŒûÅÓtfWÐën{Û}ϼ-JߢžïŠW1d‹0=®³�UŸÓr¿¶À‰^2õÃo`8¨Ô÷©“Ö›Y—èœuB€M¹úh~Pü Ti�ŠÅvùb[ëé„éþŒènMüZ=Z¢wDçÁŸªóh[œãc|OAËÒ)ëÃáÀ”Ëýþ)­ç£da¬=ÃH`HωŸ™ó³v‹ú_õ¯ÿ]!ïÊíüý6¿/-–ô÷p ÐÍ=² 9¨´/™}qECÔ;–º!\IFz*@r• ˜nÈE»H_¿Å¯¥rG�f ½{Eþ% 's¾bÅíäJÞœá®ÉÍ=n7Jõ´ÙB 4èüôT�ÖŽâE¢’’¯3¤ˆ•òÑjò¼Új�^[ÐÙ”‰n¶p!EKm9WÖ›ø|Wó3+€pûs}›õxé£kà„µ8ÐÚ»ªªíFí•òSã¦Pø2 ezÍñ^Å(¼’bˆ¡óªªÐOù¤ñtEùÎ�@ØK 04^âÆ ç¯)Íün~ fÌ3aÚu`QÉer¾õk—j–6È2p†,57ta\ï’ÏÍGºm1ZòU·O®å•Íöb»±qj?Ôê˜*ÇO'èð]N––mºÿÌTÇ× år%Çõ«?¹üó0þÝç¿2.9ô¹Œ¥ÿ~|ÿ.9OÜa64L屬I—‰ÑB,a?*Šô�¥w-ÂbøÚÄÿá`@Í+-»2@öå›]&‚žÙÅ"ßV  öWô¯ÿì»80·Ô!rd\vŒ’¥AºQ!S Ãré/cÜ@C‚ì@‚ïfP*8Ç’j}ø{ÞØ{T¾ÅÆaÔO؉ù4Ý�^ÊÅê>å§|¬ð]ôÕ„ËÊS¿ÓNùöö‰5®1½rG�61ñÇ]á,DÀk•S5Yà§â‡¨!ø¹«jÂÛF>Xv²³8Cñ"²¯¾k±[üÊö°ü ÛétäòÆ@8"=Þ§eº�»!ãÔ]AÝD䪿s°Às7=2éZ¯ìg¥¢®I« »Þ°kÚp ôv—hÍjrÙ¨yn©êO}ÊÙuÕng½uIº7Ëwèû–[»ün¯6?‡£(kVðSzÿ“ÄWá¤3pYº;T¿aý¥ÆW™ŸL?¤]jJV—êåoÇ¡2ÔÞÛ óeZâ*pˆ 6fc…–0æøšÞQ!(«6™o# Ævg@Ķƒè÷*$à„–…ô¼Mß·(õê>¢|·é;×¢­ŒGÍßÉ�þêúëѦq£n¼,B­”ýU—SŽ{=ëw¯ºe=ÇÎsLG4[¤tóŶƒ­_ÙþCç0©`RÜÝv0ÂQ³…1ЬTóÍ®Æúö'òøå©}ÇážF®^+NGI¡ÄìÃJÀ-ï àÄçxmØvó¸ž?w¢ýa‡FÚv€p`‹øl÷¥Å=•`÷¬²†vŸê $ûæ~h… ÌCÒ Ùî]åÕJ©¢NÀÚØO¸wóºá0*6`µÉóÙȤÐ.sPû| { u™’”-[ئßVïɪuþ?¤ùuvý¢7zÇœ·:ÅCÊËï|þ¶@±Ð<3ýyÜrØîl!H1§M|ëÜç©t tµØz½÷[¥Ì½-òëÚ7´½oüz áŽ[n1þì9PçÌöUøáŠø8cÆ3[ÌÐúuå¬_}?Ô¾Á™?´Ö{…_μ/gŠC:ç.’ózýâytDçÄ69/÷ϬÀ°DåÎ4Ty,<¤ø«0ë ‡&ïïÑÛTOÝn‹ó¬,o†ò¿ræ_»~<¢rÉå3øNS�Y.ÐhÅ+÷hÍ{–»´áŠä!F0®hý˜¡“Ê•+‡éß:í_Sàñ€=]^ øûŒê·ŽÈU¢U©í¹§î,>îÄ€nÙZ[ijêmzÙ #�ϨޫB1ÃçcT´?¤sÉRá ¤Ut]«¦¼\/Ž’ú6ÕåÅÛ¦x[•ôu>s¼-Š[ˆ,  Eí™ä }+‹å‹ß~]þúPÛÝ] Ìgì°{Ýù ¬(½ëæC ¹¤H½jêuåÓ_;W”÷ãË÷>û€û~©aah>:^À‰Àoš–NßZzÕrëtU™î|Ë_y‡°?\Ÿnv]º«ÒïÀ¯þ÷Ë&Àoýõß»è2qÚ;Æ~Ðó}Ú»ÁÞ–¾A€Üïü™Ä ,Äj®9h‹°¦g�ø6Ý–ï={ùIàK—û}×wˆ•€X¶“ôyá—�ÐüHbÿáßþÏt‡‹HY w_Mà#ŒÒ$]TO¿û�Žèÿ|p‹ÿ¯¤÷ƒ`4�p72£Žx1Œ]�ªxSxHù¬"‹Šey­sPáúH:¹þ+èg”Ç+ÓéåSÒ � D/§Û€]KqÑ€CâO?G ÖH ¡Žü=æÛ©p7Ðùæ‘*ïˆtrW´ËÃDÙ²EÛ&€yìÒ¶©¬Ýøï zV0V¬¼á.…ÛcÃ߉xæœËöÒ=íeE^ ð¸=vè½´Ë / <~Xz8Ž\>ä¾G‚ !Òí GtP”íÅv™ÚöKK‡}?)àJ-~iÒ¡RNy£š®ï}_qÄ–vc³IùÇq%+Íص“¯ Gü£4.ãó|ªÇˆÚ‡5òËvØ$>ìŠt‰/a7Òßl*:d}%–/)ç;Vâh_x-kV›¿ŽÌ³üîÑÓß+_ _ù9»_‰ÁÛ˜¿„î+(çh Ù~˜ÛØ֫I5îŠtt!V×½ÖÔ_®{\Ÿ=À=8Hþt‹âò¸Q~kn>ÜOÆEþçÑ h@؆®õlÓ‰7âü=n4ì,]ozÀï=|Éqg‹l‘àÀàŽëBôêñ´G|Ú ‹²=ã2qE¬?5~ôéú‘éµãÓÞ 9IôêÀåK÷.#‘/Ì»6 ³â‡·ó)…UËýÅ4`lÇ£œñ9ÝBPŽfL.5h÷2Œ‘×›1Z¬½¼C‹ëA|Fþ´…Àˆû”GTŽÞ7äÒÎgÜB[ÐëÛt%@%yh÷£ÐtÆü"úFa›Ú­æÔ„ƒÜw@äí÷}ü=R¹J¥ó~Ò öà‡¡¢ÂûÝ-âÓ$P¡ã(^ »Oné}Þoï Ï}‡iÞ°õÒõ—A¶ ‡#3Žk0ªß’~;s{Ù÷9]KõÝÝ„7ÏjèGC |®:"þy�§ÜËÉüù\VS`áõaGð+ç5Iû¶ÜÜAì?Þz{ˆ ™DAf<?R¿ mŒ×¬Æxá0 ,›Õ¨p¡xÌ–Ð)Œ ×K·S¹Íª¶hïU´Ž6«ˆ÷ùÏ«•ö3o]AÞ&½ß-ßC**ÈùYŽ#G+P{6rð‹yÝhU|ûÝZ<›ý*O—ßÊ|Xñ%Åt@`‹ò�‘ÞfÊäÕÀæ TM ‡q}kVÑáBÄgû—ͯÆ[§„$<‹ù5+ñ<Ž¢gŽf]( 9@X8Jét¸Â6¶HAißÔß»?ÐÖ«ª°Tw-Ò…‘ºâìñßShE~8í‚Ô.~Ðôô[ —í%ëÙ%^Õüàul¤êÃùgû(ý\Ž3m¶¢ŸÓwR8h²Jñ³Y"ú¤˜X´[8I@Ï[¬`V‚îð:c°=Ì)”r^³ÿÏ¢âA³ê+ЇCÄùw ±Éúq‹×ÒµÂCσrÿÆ=x Àf°`…8$å5ò%ûG—2 óuÕÄb˜l†$ž¼±œ¬ÞÏ5½LOu�¤«õìþbDŠ-ÉAÊr4¹4Vó¹ªäkÓç|[RlQû¶Ä§Ìö³ àè’|ÒÀÆ ¥ÏÜ3W4 g÷¹5 iÆÉG¾94ï×;�FËPý��ÍCUŸCÊoµ(ÇÒmé¦h{XÉÇöÇC“_ÙO}˸Zþð„È—ËY…`©½V+€¬­?[ȳçK‡å+¥õ¿\þó0~냿wF€XíÎ-µ»½¦®jaZ@솎·-€v™øÏ¾Û¥;Ä~ àO(†Æ8x®ós¼Þ`)V¬d9ïVã½' lIVÉ¿y·!Ë·ðDzœ¿üoÿõÿðÝß!nX¶fAl`$4dæÅ±"†GItÌq6)]‹- a;fã¹E ê�€KXÆ€ò‹aLƒe±ÙAX Çñ{³LúšÇxŽ-ÄKLw€ðu [A7@ù˜4Ã)ÍJT„#‡Ž˜n\…� c“è-§ÃGTÖ‹üd§1’€+òiÇóŽœz°&·øÎœnX@œ]Nh£?N}+à‰|ØÄ>Ь`k@x‰ÑÓR:P g´Á^ˆ€P¢o]Ð+ Í òÍšBQ�¿OsM¯Ô[°š¨ö`*5µ9þ(Ö3<£v£{Çšå¸1Çhk–‰>véö ®à±Y"Sç€6¡zÕÒöÃqÌ7]Îû,–›øvl-1šMlÍrtŽÁEw¼± ;îÆ ¨ °m<¦Ó ̹�áˆ\ÐåöÌÇXÕ.Öµ¡IÏ©–aƒÖŽ©•–©œãJ=xcf‹¼ñXŽ|Ä1ëüár,ŸFDoëÐ1jE &lcÀ37ëUý´¬¢àmÀ‡�aûÈ‚6_[œï<ñuܬEAv`/ÖlC æcxIýŠ]"2€ÃåïQˆó‰Ü û–3c$') ¦óŠ…Ö{ÈãQÖ3·ÓûˆóÆš)_—ó} ü•ù•‚ y�“ü•ýD¶‹šG Ö·˜~™r/ ù6"úµ`êØ”‡”—\o1ŸáCó»<®xœq<miÇß²lË~Ëùó|ÊÏó°Ã îÆ 0Ûd fœ¿µÈ2¡O˜æ¥ XëïÏÒ¿Q€YÎKQ@IóBš¿%¿‘çEžG£8 ÖÜCEü4ë/Ç<Ó%Ør~‹ré]3}·&÷ âß(Ä-ÂÔ>h,Ö³I.K–˽"ìakT}бfÖE¶ŒzD[+0ô5+ŽâK̯¥}ÏVQÿü% 'ˆ‚ý TÔs’èÛ³H¿ZÇíÂí£Ë¡õLïF›ygVÙ¢ý†£;ÜÌÇ}dÚßÎ {ùMhߩĢb8¡z(àMõ»-²,ŽñwÔþ6×u‹ö¥ÙwÇé9î7–õzŽ+ã¥bAã ¶kt½òþ¿;L¨ß)q±0¶Ôþ¹Ìw‡ÊVÀiWÔ׸­;(ÎÈqâšl›yÌ9K9¿kH3ÆŸGÞ¿�q8 L£B¦mÏçÐûK-çh à#¬!®wÛS àù7óá~òÈÀ@UŒß*²2l©tÇT«å$°ŽTA:–,߯P>G”U8âuœ×›£â™óÉÜѪ,˜ôö£5 5©€ ù¸‚ûÄÇEÏ‚j;Ú´Es›€Bm|dÚƒÃJeôfEͬHÃûĨ‘|îR;°E”t™h-äºQï£ä’>*Ê.8ó-·ŸœXòÈ<çQ˜OͼÏÜ7éå¹úŠžO‘ÚC<¿ õ—Hÿ3´Ø°nøû ¹Ÿ1?eŒ´ð�ÇÜHb‡t?•ûè-Äq¿à>ųöìV@‘Þ{Ï ÅVñ³õ²B¯‹lA ¦wà[”ÏŽz³,ŒfŠúÆç+U Üp¹;È®¯RúVåÇýpÚY0§Ïý{‹¨Ù‘ò¥¢~5A½t-¾FíÌç%øœ8B©�rDòÆEqN]ü?jî'KýèC"ÊoVÈ2ˆýžë—,Ê(ÞaxŒ5Dû¾¨9¸«ÈŠ;Û‚¿¤°gT¿4¯5<?·ZáÖÔ™çæ÷‘xÏ󘿋ä‚ò4<Kåqºx`[Ìœ¬èÅŠÕò|‹æ#½ž‹“Ï›‰¢2,R¼SäqQÓ •ø¬ñžù¯7] ŽpÞ3•LÏ'’.¹þÌ4ÑÜã*<.ò“íÁa…,‹¤E“¯ˆ›Óô>ÆÏóSlñçtrZ|å^¥òrˆÀ­|¶ë=ïç ¤R¾ì[\­TÞ—û ޝ¿ß§ïÏ)Ÿ•d¡¥é“pÚ&€+j„Ç”ÿŒÊßòc%=ÃÄÓíÈëÂs?Þ¯þÓËÿ'L€ßþÇÿÿ6b5 jËAd Êu¥è�iùÖBóûÚ•¢}vµ\=J—‰ãðKè»Äjcú}tøNñ=[ˆÕ‚²Þ-Êy¯@“~·7ÆbþûË¿üÛ¿øîïL¹9fK(q«Šo”«bɾŒ4CŽÃ6v /EŒùày7ܰ ý(ŠØWåæüŒF*Ñ»Lô¾„ö@,7€žP¶�Œi�O(¿š» eøì—&¿ü}äÖÃH1À2J®e"?VÂDå{ÔŒÉei47ã´pJ²ä†è¥ݳ [NÙXÎ1MƒËT¯c”NÞ¤kéÒïÐ’®óÁX NGB\Ätï#ê]F¡ó&m4ò´,-³–éÀu, ñÛö°q#?"@‹]Šî¤zGzâ†l,øÖ�0/øëؤzmÿs{�ù¸úŒèµšìljîM*÷€þcoûla7&ú¢@÷s ÁÛvXö¦ˆ·Lùòû6I@­¶]BÐíok¸?§ßRO;Òù!Õ‡ë7N�F®Wü®++�—½†È›F€,€ ñ}LÏ`äçu”5›99¤øO X! E¼f…øK°px†5,w¥q ÁD³N�k6[\=»EýEË‚õ2 *Ríæ÷J@/ÊK‚k¹ýÞÌ|a¾‚n1h>D@Ž©¹.ÚDGÔÄ=Ï'Ù¢&–û(ÑÁùÇz¤¹f;¿gº€È÷ð9vi̱iñ˜á Hl¦öáúÚ ~¼Q¹“Ä·1•¿mâ#Ó£ø^k? <‹÷:¬Q¼ý/Ö3ÖrÞƒäÌ/åY?Á?`HÎÃn%�1«�°Itg=d÷±Þ÷ ßw)¾vJþÄ~úŒú¥œ'ø™ûI|o½ªë™Š½ÏM½?[væÖ—ãAÎz†ÜUÏžf¼¤›Ÿåxåù{q0.RëÀ€bÌÇZôéuÁ ³ÅÏ#‘’6š·°û[²èl±F%ìõãuN:åúŸ ÁT&#ŸHÁÇæ�îåÇa¥‹3æŸä+ó1Ž»Óz<)€R{çiŒÏ§6 ö·‘nœ/ï_Ÿ‹ý´Ü'Ó¾†Ûiéäš²áy+Þ1$�ÂRš,£hß8Où{ûä-ÅŽD‡í-íKŸx¦}:훟Ãß·çç–èÉ»Oiqµ"ZÎZÈÉýï|ÊOBn±ubyF<Lü9®¸,g—Ë)÷‡n‡ÇæÍ<âxIï›M:×äq§øCßÛðX;cm6cÿ ûÔqæXn6㾓ò³í9/ø¶ `�©gæD³B#,YV6qý‘‹F¢ÙÒ.EÁQ½¯>¢óÊBÈã€ç áZ ·'[Ä®C-X/»øWÁ¹ ôñÇ;yNás‹\G׈n9ÿJà(H0ß廋ܟ³…ƒšÐ¬©|…ê¡Åk‚oÆBa»°H·¾M“ŸºüúXÁ¨uÕ–øfÇ•Ë ‘®¹Mr¤jz�4ËÍ–ÚW?'E<:'±bFx‰Ü?¶Ì¾Q—ŸŸ¸?+ŠXÑOÌŸ›ô,èStñûýhéË.úÉò7Yì‰ü¬óæG@xÞ<Šû_vH�U¶ g…€\ƒ³Ÿ‚ö† L¦› 0Q.uQöhRh;é» B16;Âm¶"½ÉEæ}ìÍBØ•ëdë´TXŽý9<Or'ZgHÜ¿àÓÏùXK1A)‡]­ݬÅç(gj–)Z·šû”o±þù· ~r»?Œt„ÇLeK<ÉÇe§ñ>»®¤ö8Kß[²„‘"„Q «CVâ<žs½‰?Ç,WJãõ*•ËíÄçá1ªYŽç‡ÔïXz|“-¶Ú¤¸Ä®JÅ÷ð<¶o³HUÕßdü#ñÌóÆ>õsí ñ~’ßh•¡­´}DÏXÞIß¹–VŽ%$ Ͳ~žG�¿Y‰ûw¼xûkv+û+ 0PÎüùsHý}‘Îß%:ž§Ù鱜gkÄIñ˜äXጤÁl|ŒSÌO[3Yorå×,§÷9}bÉŠØ|þg…òM¥èV¿¨F*üÉ’b½Y±ìy²Ü¡Y!ùÊQ±^ñ9î1åC�O䫪‡íg ±Øñù¹öˆÒ‚j8JéèÊžt7«ëZµY)ÚEÿÛšûTïçéÒÊ~ Îë#I­—P¼ŒùQùm¢‡ËÏícöÕºY´é)(Â0"þg»{×ÂüÕÎå¿¶ßþ?ÿþßõ�bSY€9@ÕPW†0ñ†pµ0ˆn¦—ãI—‰ÿÌÜ!–ÃK®w(Þ·ë¶$CçÝbï’Ø7øŠ�²÷(þW)NÌç½ÂUâPº#K~„_ÿòúW/Éeâãlÿ¢�� �IDATt€‰€ÂMÀ¥A¾X¨ÒBI¦�ìuTLQraGJïÚÆg åî}žwD:äÝù‡èÔ�í>ÝrCä¹l)Ã&Õw—êÉ®ù:aæ{ ±1ð&Ë™8ïw¨¾â9¼ÐÛzþ>§à‡aè¹5Ô ‹Ý˜ê½F h˜Ž¥¥WYÿæM‘O¥åTCá¸y¢ÆƒËX¶s³Lš¶ÇáirÈ-¿Må1€Ïq©çéAÊ]oQ£€+ùîñÚóQó@ LÃÓµ!× T/þ¶`Ò< #JLÇ`ß]Êï›J‡Çi¡Ù&z¸Þûˆ×5ª×¾¨OK.õ<ñK<°="è`W¹¢äïr]ÄYZ,vAR–f™Ä'„§®%š´{Š]�wéùçKé˜wÉBãiðŒ bÀ.Ä =¢Ý­E÷ƒ]D�[¾ŸPýש'~% ñ™"cºûnB®Ò o”înªW,ç…ègL箈Ÿ•“5lrP–)&Ÿ$ÞK6|kY´ð{×»ï󟿸=bºTn/z—øÿB”ËaŸòY£üw¿^$Á#÷Ci™4±à.iò½0Dr²�~"é"›¦Í*À³Nc„4ÉYÏ'ÍCLˆÎ}¢Ç±¤á1FTïVÔ{Bt¡F@ó€lž& ) ¿Où?'¾)¿;ÄÿÌWnçÔÿž&(�Ç£í?©ž —k<n!Êç¸*øÜ#»Iu`M¶?»ú »¦¿lR½vÍül¨6ã5_·»ë0–iÞ º1¬³e&¥ŸØrï™·Üþ Dó?÷K¿�ðœæ÷»ô>Íw!ÎGz=‘ê!z|èöà ¯}ß ¾OT|ŽÇ‚‘h¯(ØÛ-,¼ÇôÝsÝ4¡ù<»@¥ï|ðd…—|[œP ¡y4>s»kê?gº…E¯«\_iYNw†5l ú!¢`å˜÷AqÝ ÇЮ‰Þ†è Ç”¾ýÓÏí꺨*ÆuG“’n7X×~qÑRù¥@ùV­§iÿ÷ÉOÍ>ùYn©yA Ä8^|ÿXz Ï«Ôr¨µÒE!íöši6}-Ý Eœ_¬Gœ}x;åy.ëö@óÄr_lÎ!60`˜Ú_Ð×R:èÉšë@òä›Ô3ËÙßæÇÓ1PÇÕ½dÉ¥ß#ÍïûŠdé|R±‰ë:Qô›€f9 .Âs<¦;.GØ$ËFVÔx¤ÊÓ-”í‡J—p»‚ê¬h =0ðäݰèßκföÇ»gK_! æö(Íï 1<LÏQ€dXf ÝóXq„dx}Ò‚¾e¨e¥X¤÷•ÿ4å»KçùøžÏiOM>±U®ˆÎR`»¢÷3ô>[ äÔº^Ü.U;è{[Ä׊'|^{ŽMêO»æ$SÍ“ ò8S¬`È–GÙ¾0®ë»iŸ¶FùìS¹ ŒîP;Æþú8)¬mR>-Ñã)`”O»Fñh×Xì¬)Ë0ê‡BAÒÎdZ1‡-_FxL€Å&•Çó*Ï_iœ=$9·Ï®‰—ùÏåsˆüÈw’F×z3ÿIRìðê ”ó#ç±Eñ£Â6¿Lå(ÿ–qÙ^"[Di~îVÞg>€Úô¬×ÛMElU­À‚”žóÛ¢çdWÀg©üš-+¨Ê= ´TÞÈð³´T”¢})÷ÙBœµËȇÔOv)>÷·ÇªÎç9J¹ðݘ[¦|ËßdáÅœ`¾¶¢|Ég~ïí(®¨ß/§þ÷üd=[dºóúÀã2Z¶=VëƒT`ˆåF…'䤅ØÒÕå40§[i9\ÑþzÛÔ.1Þ}%o`9Ã2 Ž›T&…0!ØpX10®;ÇiÿÊñÖÔü´,ʉí«å²Ebú|7ì¦x^¡üK ¯Úùnþ Œ`œî1ñŸè¦y˜<`†ÎgWá±®_RèÎ3´–×tº0Îô±¡F“ÙëvZ3ò ‡êY¶‡\åsð+ÈÐ3×ÿ* -½‘R,ÈŠƒ¦]S}‚¿oòv6zÜÔzÎñ—½±|ò¼í~ýBÖw!R~ÇôÍDzõèòÂ6ð;ÿɯÿb.€4-åÄÿ¾\*NU®cQf¿Ûð�ø?û’]&þ£ð'ˆ@’ƺ,À²XŸ%œïÒ5¢µ ‹á«€Á÷þ�h2p6•«Çù[»þÝ)âÁ\jøñãæ¡ô„§æ€Ï—6´ -Ì¡MßUü@ ncEüy |èÍ]Pú{�^Ðþn®î‘@à@ Êa‹´Ðêîz?FTb¨ð! �‚„çýHL,¾Iþ¦âÓHÁhÉ5ã-Ó{/mÔ4 8= ÒÙËSle jàž¢E”³ßþ¨‰9Jv>0èš°ÅÁ&•s ° +Ø$Au<hÝ%ºXP7РˆùŸï^ý8HšJ­¨ï8Y¦ðqo—4­µ‹ŠØTü¿ ¶ˆá8)¿Çfå_îrA-ÚñÂøØÝðÉ7U»e AÆ“–xVP‘žÆU:ÎLe±ž, àÑ92-,°—7ž»Èš¹Þ%ß$ÿÆD·àaLýBäu‰Íû‰L‚"¶@Êý%¾ß§r×ÀÀDž6Õ³m?M󕪻з²1P1Ní›çÉMó,Ë{ÔÞÅS#èaà‡žLÏ>¢Ë¼(Èæv‘ª5rQ 0&ó÷9` à>ŒEÖØŒ ëúÎ~烓!�+[„E¾PÎ97žoZ•ÕøbàAš¿´óÀ§ôüÐð“é|€}�Ïż j_)Hš$>3Ò|óXå:ýÊŽ/)@ñ»ä¬7Ö¹LzLýÝ�2xPŒs¬ÀìAñâý$õ{;o¬Ò÷±JwBýsIðY×c‚ò(UZtÊzÄv‰ùs_ZJõ•WÙgËØìÚ‰Ãã4oÅ÷ºý^€s_ñ`"ÆS¼ 9.íüj* yˆé/]vÊ»Æøý>õç%ä -šG¦ýZјÛÔ>ºßMŠùuB|ÓW- •eÄܽ»·¤�•ÛA®g™O Ðåv!öŸmª¯Þ§= z?Mý}Bôs¼}Š¿>¥ö™00¦}ÚDºPT-Êû4-ØQw%:‘ögå¾l‡èÑû´§&}¾¡LçŸ[Iï‡vàM âXë zwGÊtÈš™Rá«MûÞÜÆ[ˆëÒâºä×ï^°4]5ª°fé›ôüØÄ·wžéõ¥%z2 Ï#´ÿlî¢ ;êû=¥–Ï#ú¾L©IS>À^ÄtÍn½æžruŽp€ÕXN®ŸHf€˜-ǶL¼}Ðãnz^£|¥�'Ý4H@®¦v‰V ³Î; mâ:5 OÒÌÊ öŽê-ÊYvM>Ü^lézâ*€� àÇüZR@`E¸4VÇIQ‚ç›GTÞ¶,S†]½.XŸ£å*|½­ŒY0ˆø- :3paΓ©ý6õºöuþ¤Ò K·:W$…ÃÖ¬‡(¸£­ˆUÈÈ uõŠíhÜÜ5ý­¨]Ý1ÒÈõMó›U/ï%zZÊgàÊ<£x~RõºÔ&K[o}.ÍA÷¯ÌIÎg/ˆŠ»<îS{>M<gÁ³ÜŸÎP¯ÀóÁ#yx•m9¢ú·Baôå'ëÕšö´M+Æ…kë@µzAñæµà»!Aq¸²ž‹R¥y=x»B­` ïŠÌãgËÄ�â¿rñ®ç+COê¿‹yZ–ÖÖÞ b(c‹±ÍT_Ÿž²}'ÔnÑÂ÷©’¤ù5ͧ™/±e¾DËÃøÌ.:g(ߪËN¡èÄóü6„\*Íù´f-¤™Ï2ß4Í‹þeï"ãtœÏ>ÑÙ˜1ëßåŸË5kDÿ¾Ø®Hñù“¨, ¯Œege>„9 Åaæã¶jÇRÚâˉ6ðÄ_…b^Ð|xåŽ|Qª¸‹¬Ø=cbi»/Y:?ó<ù‰€¨sºìQjÓ=_æï¹¿©u@m„×âù†ÓèyÎQ»T߇•|¸¼¬¦¿?6±&Åbù}Ípˆs¹kògƒ†»©ôÇÕúpyº}-påŸÚsü‡i²{Î%K[6Õs ˜qÿŠû¾�g³ KÓgé°ëõ¾›¿QGÆ ew ¾´�ðê£Ë? àwþä×ÿêלk j�RÍE"¦Ò:\'ò÷?­¤Ÿ`ä’Ÿ÷·$ ¶K€XÍUb-x–^ï$׈_§;Äjñ%@5ÓéÞÈBÌÂÂ7Äàô½ù‘ªÏ»Ñeâ_üwÿjç»ÀQ³¾Å¡ÒL<1Õ¥BЕC<8S¼æý1°`+n@— ×Dÿ¤é¿Ô¬ªƒì ¬¥¤Ã“Cú®6œŒÛ³&¬8ÐŽä"¼ˆå4wc>M¤ø® ËKéîÐ7=ÓFî ^ØšOÒ†t h˜o¬Ÿ¾ù–6öÒ@8¡mæYTD ²YŠšá$n<š%¶œˆœðña)ÒNø9(FºÜ¤A¯6Fá$r„ã…“`4å¦Ú¹-\„å‹x§MOÀ•7æÍRó nÌÅFƒ¼‹ã¤ùDnÜS»ŽÂiVohAwØ+ZZ¤_FSöænð$ Ìâ-dÍRjɧ©Ý<K)²Ôz&ö<1ŸÕkË餯~ªƒ9pB¼ôÆ|ÓuµÙÒg“ø©Q¼ 'aÒm$¾'‰¥ 6ZÈìQù±þa»@³&æ}'zˆÞýÈÇf̤IUŽî×1^³ÄùŠvá Ú'œ00Š|ãñáêÍìBó4>6ÝvŠš¸òྠ„/Óx¦ïQ£©YŠ’œ_áDXRŒ)Ò‚'¾œŸ–LŒ5=˜Äzªq<zO(…V¬çD—Û/Ð<Ý,él8‰ó_Ôþ')Ç=IW³ÔlP{íÅú4xDåmÓ{=N>I¼}âÏZž/wrÍóñX•Ÿ{ú6ÕsDtG;« ŠË4/Ðl`_†=y Q³Ô|BØ'i>\“ýú9ûžê¾Œ‚1ÿävÞ¯ä+ú×/Ó }÷WvEIÀ°/É‚Oª> œÄù£Yb`- ÂIL×, ËCùþ•7¢þÕÒ<4¢òóv: fu°®Ð²%P Ê’x¼=!þ¼Z8¡þøAš÷4P߇“ø>÷/ò|i>d ÐÜ/ã¸üDXrNÜhÜ}–¿¢Þ»rœ5«4Ÿ¦vý"­ë4Ï2¿šl}8ÿ`ÑVÕ ¼¿¡ñVÜÉÆã<åœçh‘µ÷/áIœo(¿–Ö]p~Í' Dx‚–Ö‡ÍgÛÐs¥v>’×qGï/ÃI\‡›;4ßÈþ*€”pÓ7K@š§‘é 'Í=lÍá�(ßm¢o À$<Ià ÏÒÕÔ æA¦;ÏâNŽ÷ƒã~IŒHAì+>�)dÑþ•÷%©=îxür{7K쀯¼;?¿§|[ý=|YÍ=ŽÂ‹¸mî¦y{ƒÞÓþ>í+âxܧÕ!Ó¯¾‹útÛå¥SKCç¢ÀçøLûh,H½‹Ìp¨6ó3 ã´qÝ=!�úNRlÈí¶² ÔQ±&Þuù€ý² (?y'ÉRRŒaú™î{F�ø”õ9Ÿ ¥&Äo¹âž‹…5ÑÌ×¥/?]þpàý¿gn¬Ç Ýòܺ)ò¿ž¬"“ä*Àû@©0aÖd=ø´Ô…–,À³å<5ïsÿ‘ +´ÿƒ·Ÿ”ùd~Z﫟¨òÚ Oè}.Ïž¹çšÇòŸ*Å·;)½íï,ðþÄäšé›P½¹xõ§s(>$Îÿ)BÜEœ4_c~2žœö)Ý]âk…¬§äâ7òçs‚‚î¦þy/ѵ«Ò±ÂR<–E£]8 qÔ¦|äÙäCG¡ ©,àÑuW´T¦8 zÄÜØÃÈ j¿ÜN1Ý]Qêâ<$ךּGóB‹'ÔžQ{n#ö·-z z8\¥våÞÆ@ŒU¨àßsßÛ¢¿siå|,¦%ê¯Ðóü]Ÿùp7Ññ„BXà­Õó�_‘Z*¬îP~[”_æb´$Œ!÷N  •mÌÏ-�¦ÞÆZŸ½v={@ëË> ð¯¨>ùûyV¸[(òp~Ÿ$�9G$wÔëG–÷=HŠ~qÜ'ÍSè.@=¿äz>0뇬X:F<í`ŸâY âf(ß'�íû&È7;YËkº«°Y¦¬8Á>ÖÌùûc½žHú³‚�jë ·&ôe Fõÿænl±ð"ÍÝøß“ëd8Hå*¹ * _Hc†Ü*ŽB{ �Ε—lá0ÒŸvm'Ðòœ+=^‚œ'c¼{…¢2à)PXÅC®+¨ýBà«@®t>ÖÏf•æ‹«Ôïkrô:ŸÝ£|žçO˜s\<¯>Hé9ÿh•êMõýžYWžýg—è×ùs»eùý&Ñù{@|Êår;q}v3¿š¡úaøœøõ!t°7ÍàìáPoæ—(OÑû«Õ‹ƒpøÝøÿ¯ˆ9að5ísGþ@–�̆dƒâå;ÄþPÜ!Ö}G˜ÿþôüÃ^׈Þ{vyø \$ÆðUëÅ÷`ƒø^ºRl~äÅû‹ÿèoþÉw�ÆxB§8p¿¤8K´ÐB³$4f·5Gy£˜Oý`¤£TN ˆß{€:`‚â/AmyÂãåëèˆôq=é÷”&²E1Àw�|Išæ`•އDˆN+ØbA ÓŸ[l(ÍRÖ`?MwÃÐË_Ä!¶/óäïLÿ”Ž¿gþÄë»—H`Ã@ <¾ÀFE³ˆù¹¡ÚƒC>l¤ç¸q=TÜþ’æ,@<ÁX6Њöa—€ ˆHJ}@Íã(@æ|˜Þ“Ô{ŠÎ%l¨ƒÅRªÏ'$šÿ¢kµÀšzTº{ПSú¾h lë—ÇI«ú rÿdÞ:¸¬_N ¬u›ë7¦q÷„øõIâ—ä÷ÓV<ïŠïlª¾}YêbâëXõ3÷„ÅD½sx èÉ–±œ5a‰û¿OL îº^œï—©>Z0 -$d°V3e¾æû‘²\™Ðm É…¥[4éNÓ{žŸ˜SGDolßÓdÉrDñAïWˆÏšÿÙ%å„Ú©t­*Û‘ŸiþŒžßOßõ<²(Ɖæ×Côe~Jºâ¶¾§Ô‹ˆý÷ñ®¼E᪫5ôÊüOÍp‘Ö›Sš—qˆm�?£ƒzr>tä»˜êø ]ž¼‰<¾O±Jü;4†|€µ£äßiÒ…b:£@òù ÂÀɘâé—oßõ>åÿ³TÏ”/[}NTûpØ£vâïJÐcÛ_Ž÷Xüq}¹þªÿN¨_ó8~µÀýšù¦çq¼Jæu{ƒ4Õž¨uƒ×%<QýèDŒË(ÀÜKýžçAî7r\Úõ<çWæ#)=!‹M.—Òz¿g¥„|`ç|ãsÍ‚ís¿•åž Á¦þ¾Aéd.¹~ï€æ›%šŸ2=+‰ŸžêÏÄä‡Êþa‰ø}"l츽¢�£¼¶�> ˜§x 4ÐåøÞ…œ7A鞀o7ûΟ)ÖŠ-K”.ÃÝYÑC ÙFš[”ËÙHë9ó@l‰öHä³”òÝS–yÌ÷(÷/)÷Rÿâ~Îó˧J “׳<F”nÀ%“ùÖÞ/jÛ†Ú/VÔ× Ç¯Œ_ÒÏû·Ü?øYŸt¿b µSì%†ýGö‹”KÈ›ÅÌ%`‘-P¡òÏûŽª‡ÜG3½<FÊ}gR"=q]¸VØÓçœÒ`Ïû_h ð9á)XÀÊóiÍñ¼Ïõàõ5~¹_j ,è]¥úî%À*Î!'ŽiW…{i>®52l2@"éàöc¾ó:=¡v#îCcù,˜çù“º[7´´¹‹\B(Œ‚XZGq$xÍhÙ&•"„©g"\} EQa¦¹(X Ÿ¦ï*ߊ"Eóšï­˜qý•â¢}¿™ë¾ `üNª?ݤpÀ®IÁ“5·Y!‡øØ E4ÅWBAFñ')d²…Í'ò;V�QA)®¥ú<Á6ÐÜi>‘.z…bVÎ]èósKåŒ(_ñ,êÁL&’EÙ½¤8  Y¥ô‡€R� ÄH¢KZÑ�mxê+n>„eiöè’ù%AS:½Ú7K±>ÜœC¡h˜)‡p!ÿæCJ?C WÔ_N’eÄ{‰.Ù>R‘BQ/Qe1RÏ(åû+êŸó³.§ä+å‡ý¾àg­h•R³‚c¢\¨%Åc½¢’¢p8I "ÜbJ±4…«¤€š°Ÿt|î—á$Î+ª¿kÊ7HEnTäìüÆ@ÙŒ¯°CýZYr±¢¦¹"ÐwD’Â"®È"j†,Ö®š{rOó0)Ü~AÑyÇÎß1?¦#œ¤ùê *EŤ¤ËêžK¤ fæKØ––Ìcâ‡\×®Àr¤užù ˆuùÎûæ&®»w¨‡¦})ŒgùhžO¤eö•V˜K$äº CRäiò9…ëË Äò¼ð¡¹"ƒ]ž°-YøTï ˆŸWZaŸSyW–úåq¿dN%‰ ­K z8D…v៯ð�µ?éÏS~Ù‚xWÄ{AëÞ]ǧ�¼HŠP#*ïžê7Éò\Òù™G!Ó%zŸ&‹>ÉÏ pÆpWÐ+˹ÛhO//Ìz^\­aêù‚ùeûsüV•÷‚Öí»¦_Y…�iá/ãÙðBü¿+ÓYKGÁgÁŸ_ý÷¿&À?øõßø‡�bŽ‹ÁHeÝ5â÷ T]# µ S!bò±¾;¾þ�Ñì—�¾¥wì21?[׉uK1ϵ¡w'X ïÉø x…obºæ]ôX´ @ ¹œ?ÿí¿ù?¾cáZÌñ&â Œ& Zha>-4žõ -‡ˆ—Û."^®úe ƒ¬±«úZOš›q!¥ƒÁÇæûªzÎD1Yž4FPŒ ¿Y$ãSDÍÒÅxM_ \Ò„‰z‹ø‚½YåíÐô'6b£ã/Ð@¡EÍw~š CºöqBñÙò,K#‘¾%ºF”˜’šÅ„¹·”ÏÇ©áæ¥YŒÏ™Ÿ1_ÅÇB¬YDœŒ‘.ýäxÍb8Šüm6’�„ï,ƒÈoBí{ÏöGÁ/ÉŸqØ‹áѲ„-\šEÚð:ô þ¥x_Ô/—`kIS¼–*áË(@kÌwå*-YDþÜÓñšÅháö[/üŒèšˆþ¿ àgFó¾$)þaÔ|¬MÓÃ3z¿®¢çù!~?5ßÇôþýf]YšXÁT-$º¹–vL€â÷ƒS<:mÛ8þ Zõí#§"ö.Å—–r‰Dß"]÷yjÅ1!׋ÍJ$xÞ²–´)Ó¸p”æcÅïŽöc€HnÈ›4»–&÷jù¥|h¦ô/ªkw%ß?V5g�ê4äkÛ€Ãý%<‹ñè9g®®þ˜âM8ßff¹ iÇýÍöû1•›âS?]¤üׇèX¤r&úu¢I”}Z¬l#S> ìè=­s§â@ �‹iÝcþ¬(+¶°œhËÌ4>&4ÿ/6 ãÐ7dK+PGªÓ¸–:‚/0Ð6¦z0ËãYS[¾¼›p3SE¼Æg$Šñ èù€ù±)è¡ùïÃ�ËAHˆii^©r€¥]€Þ£üD?uùo¾@Ï_ÚÞOõ`@ˆ5-OM½˜1Ns-(õ<&=óä$õ§=ÿñwÚ?äñú$®‡z^ §Éå蘄tqV[íÂÂíS¶ó>@í7"Õb”•˜D ,œòºÇûCr¾¼¯1ýE* x÷I1ŽpMØ,Šý(Í>ѱFõÒ‚Î=½ï2ã`Âû]ÑÞû@ñi‡ö![Hû»póoV?Mÿ {$8ÙH׉ëúåv…Ø—žèù…-… Ðl•@¿mj§ Y¯´_Ï.£@‘ç š5›EÞçnÑþ2�©ß�<Î0®y?õ‡¥Wž&Â)Yº.ÚóOØKt¢Üñ¾`:Âõ˜•¸ï¥úа†üDÎdÁîc2ÝÆo@øTשÆoÃ'³ïJíY Ƕ|'ç.ñç"�ÃõÜFbš÷õèsl·CÓþ_Ò¿|jã|ÃçÞǪó˜ʛ�á4|JçU¦‹ø²Â#‡]�_’¢C¶xÍëQÜG1 ¯ÿç pÀv=‹¦øž[†]a·´?¶@²ÎÇÜ Œ½#Æ¿cy²â ¼ ]PmB+zjúuª ØO E“ü¬øý*å#Õr¾yÿ»GŠU ôYE싇ø”ÒÄï«Ôþ­h©hÙR¼RnùYÑ éN±"àݘÁ*)reÄQàëYr- z´bç*)xRþY±¶¥ö” œÓ|ÇðŸÏý‹©¼V½‡©—lONÇñ[z‰gþ»˜,–¸¿ÈÖ®ð©zÏ!÷ï ó>Æ?$`~Æô—;I±«ìgÞsÉ+;^uþ'&Þ=¢ã åä§ÏõàuÿÚæaÕXºžŠP¬¢,®1JùÎ(EÒ!³V,eº’‹Cä;®|þ}šžÙSSTðˆóÿ´.0½‡U…ë4ŸŽÅ÷CSî’à;Ó� ÅšHïñ/ó{i¥-C‰ÞSRx\Lç°ò"çý;¤P˜8>MŠ"²>Ù©0·³oy;C–Þ XØ%匑”Úy¶z^§P›Ç¸ßð<»T™ßs¦x²¨�� �IDATÑýÛa&õ£=“žÇÁ•úþ9>RÊõÒïOw ÅäÜOõúKZM³·7ów/YTEK3k¸ -üÍ "]ŠÇø|~ü˜Î•¹ÿmŠt§•ùö‡/œzïRù›ÈŠFLÏ•ÉçT´›:Ó9%P*ùÈ|úSy$· zfLÚ«¢^ÌÇO‰._±ÜòÃLZWô:c÷¹Æ¯þëËý0þÁ“ˆõH0ß§œ¦u­X‹¯îë×è´…Ø?" ±aï‹�Ô·ø:YŠñ÷>W‹@¤¬ÅW|f׈ö1˜÷9tb „E‰¹üæGø%ðçü×ÿÅÿ·�`„QóSú6öò 4×ÕóZÀSŠÔ—EÚHˆŽ(jvPÞp2®nl>VùÊëO²vŸª|¸Ü¬ÁÎÏ6âôÀ]0±Îz8Sh/WeºYãþgEº#•o¦—é?RôK h[›‘¨.€éÞZE‹¨ü=YüðŒâe÷ȼ×)ˆqc&ØXîFÑÒ€\àL~|àËý¥¥ò#=ëf«Q£Žo«tçY‘Ÿ ÕÆË3Êg]µ—ä#Óxý’€ATú%zûáXü•ñ¹5àÆÍ·¡ j8LŸ¥q?j´/ýOM¼˜ßBäCø9ñÉëÇNhÌx v|µæÏÜÖë•,Ÿ@³¿[A^(ç ¾ûkLOÏÌW �åÐYC§<j¾mî¬a=Nw’}J¹—õçz"oø-%$Žù)>˜öÔÕxLo8yt(0¦ÂÁH—ê§5©Ãý\¾_®o“b<h–œ¸5‹QpNÓ|5.(°|—õͱs¿š ÎSÙ¯ç`ýêYêÁ•Úæa¯Y¯éau»&sè $h¢ <ß•$ã/ÏR¾jþlH {†ÎÀóFÒãçç3ã¢!¿çq·�ÍÓû"„­˜®Ùq¿scËT-pÈ7Á?V€ÙH@&$à“€Kó/×ÚTöÌ—"î²ÉI[jÏèýºIç¯ÃÈâýÅû´ŸÂ¿«‹-/ÏÄ<$’b¿IëÔJ³¸O8ûáHÿ ^ã>基ÄÖ=@mßò>ð,ѳnæö•�¥ä=vÕ=£í¦ƒßÎ ”ß™9ø.ý¼Ÿ·û—* _p¡Ösí¹Äã^£ÔŸ×+éŸÝUŸIïþI¹mçq¶ >4㸟º=Þ'zÏÀ #ÌŸÌÐÅ Vù¼±‘Ö1£à¸¤8¹=z®í7¡Ö{)‹ù\´“^gt¹ \}‰|[Ì/×SÓ£G×¢Ùœšø²t Ùö×=«OÀžùmßëyˆ�Zü,5µs®mÇ®X¹–Ëy¿mÇç·î–ck>ý8CÁï¿vNÒ^4%fKa(`K*òµ”Oœ—u¿°ãΗüuˆúU8Ôù4«hЂo o‹¼U° IqbµˆÚ–y¨}›çâ?»š¢; ªŠƒù¼o©5ÖfŽÉØŽB/ÑyˆÖ[÷r=‚ž¯®ˆI j¥Ý+ø›ê[ÆnM<“¯váݱOöËëã×U5_‘Šß·ÅûÏzÊ5|îù~Ä ©ýHÁÈQxÑó1Õ²›¬(N› 㪞ùÒ¦ôRQN|e‘Åßå#)8dÅ©D‰RÌ©·–¶œSý5Z´±¢~</Í4©vIwª5µý² ©gTö}k°"0·‹?EMmäµÙIj€IªÖŸÙuÞj&|ñÛ‹úäÔã½¹c®â¨)JÏÐû«ßLºcw+t‰ù‹'W+ùvŸVJI ‹µþlù ŸE;ŽÌ÷nú’‹DŠ?CùÝIù z\†/zó1«±¬OùÄß_ýgÿV˜�¿÷æ7ÿ› 6íóuô.§*×Z¶9w–©|J@ìO¥ÿÝ\w„Ú"LÇûºêJÈ€Xv•Øç‘](¾ç¹DTw†ÙàÞ!ßÿ‹ú×ÿü»¿Cy€> |0Ìaà¬Éä,„�€MØ-k#“gE¬a,OZšxG•‰¿&h¶ù ]pFåö‘o î©ÐѤ'~?ðCð=lÍ(<kžÇz…ûTÃçD¡w$QẕԴ >·5îä3ñ)|J[Šuü@,:pÈÖeáŒxùc Üïp+ÛGÓ˜�9Q®ª½7,¨"N„¨18nÖCÔs»ÚFâïñíQ̇¾O(~|'nmÁ†&dÕŒ¬“Wwñ=¼¤<æ ¿Jñ9ÂVŒßì ø7ù2àq.ˆÂKÚæÍcBtªþ+ìƒR»ÇôͺªWX°1BZ&Ôóç/ÏÂΰÞì(@LÈ 4›:xs[1ŸóÁë¦Ý¨ÞÅûnJZš~Ñ-Ø~"ê<Níéc½Ù§|¡øëÍOUù#ªgì¥óÓÿ X}÷éù9•s¿LªÝSÆ€m?¯¾[9mx 4û@ó‡ðÁ¯2ïç�~û@=]jï?ÏF÷Ud-ØDïÂZ|Çó…¬wø}ûC'Í.ßHµ s»É2­ƒ7ËgžŽè`32 …\Æâ@4_Ÿú5·'õÛA€Ž¨õ0Qcš@ó@\Šª¸+¸Êö>ðÇvãðiØÂacç%O1¦­�èãøM p¬ÑKý¬¹¯zÙo…—´ªÎ‡Ïh†ø¨àôñW~ŸøV«'šØ&iþ£u5<‹Ïñ;¯cbÝSe†£ø¾YIë4šmñ‘W¾á/í;ÃY,?¯sù{ªÓùÀ$ÅÌó¦Ü?”üÏõDùlË’à6×1ºÎ›P<3“Ç–ËÀj u-Ò-ìªck®Ð>ø®ö1ýg�HÐÖðºØò>”Òõ Þy}ªö lÑû’øšËõ÷í%à¡ßÛžwFíócÃÿ±YosïèRÇ�ˆ?øqŽ×)˜ê�Jø\Ó‘ Hœ{TpΗ'‚ocšÒçôó®õÚîÝaŸÃg´ä|è|> k�Ú†÷NÍá‹«•ÍŸ£â Ëï>×µš*‘Kÿ:Cü Ñ¢“ú)åÀí?O9çg曼$zç«çPŸ?Po6íÊþ¶�Óûy“bžÚÐÚy* Î}úXe¾ä{ØŠ|àr©_·ÍŽS>+°¾ùõ |Š=JóÅ6€QšiöhÝñ—/)ß÷)ßRSÝržÎ³øØœ§õ8Ï 8ú¹Ö¢ì eD=ƒeÞy}ç´Biö²òŒè]'zË™¸KtÊßÄüBçáLGÛ›‹æçÞ|Åô[KDîïm‘¾E}¾;3�ëBJû™zŸãk… Þ‡žQ¼èÜ4Cõ¾J -¥S NÈûØT/éŒíºÐ+7ºR\vNa½ýÍ <nRÿú´Pœ‰A[~²b°ÁçÌ8oÄÿÅ~® kâ;Ý… fi–‚éïU5§¸ž MëÉDÅ+ûe,/µ'Ñ»Òüh>¨Ê!Y‘Dïo¹>3T®opU=§_Q93TÏ+’ƒÎPî%G¤+H»_®?ÙrLTƒC¦BåÎð™TÔCžw|¾×û§­ç ½ýŒž´EYia6 ÐåÇt^%`†©È¦îwÚ_Ù~n„{'o:Vhÿ™«‚ù€’µx*Cíü_¢û™j¿ê¯W¹Ÿ»ëNyG—~î¯oQUN™_ÁŸŠ‚¼nçZ=˜¡y¹ì…#�øÕ|ù(L€ß»û›¿0.¿W×…`6\`c@MÑ? <·\" ÆÁ»»ëàú:e5Ë0ß_ßðõ.^òYXޱX'ðå–Ë@Yˆ½Kc”Ï¿ø‡õãï¢V‘9&‘À"i†eAE|AGíQ³ãñÆ›âÿ,!㾆Ùm´NÏ|pxYä¢Ã<-_¼±F8Vé~NÀÄ‚p1%Ëã@‚‚ô~lË3tÛ¥/•OÏy:ˆñVˆ¯µî ‚r¼(X%þÿ85;�~ž4eÔBÌ‚Œð2M£æ9„6WŽÂ}�£¢Ÿ%A¥�¨šÓ1ñ瑾f¾ù¸y„\ÿ Z ™€SxÉu@ °ÂÏ¿´“Ȥ¥Y³€QÜèGASø9Ñ‘êùÑÌóDë%:ò`~‘\ªG ˆ^Æú6óñà^2]$H2åeßKT›€f!†áÌváZ!¨b€p%–^jpÍJjOâšÈ_°ýYìÿÍ<½çq‘€¯(øLïMaAgjî]+Ý@r8+Ƌ֕Ý8Õ?ŽWàŽƒ¶Ì’|rßÓë_¥ ¤ŽΚ(¶YÐ høy ƒA3&àz<¥`vœ5d©¿­>ª…¸™'˵—d²B€ÜKÒûÃXNøXàÍ@ãzea¼Œùˈhg”s¿]?Â/pÜüÀ„€ÚP¤zü"õæ?÷x¥ÓsŠw*wL‚â ŽR|†üïÓóó°ã½÷M~áïHôÅzsÿ½/ëßÌãyøI¬Ÿ²hã9ÑyŸÊcLõâz²óÊ­€5Ñué}â#§O@–~Šoée¾$šd¿âz†_€Å.9ßÈ×ûaMñå3ª?Ï{Ïè€8Vt2€6¡ïãÔ/GO رÏsGZ�ÔÌc]õ3ÀÌ‹éý:õoæC^äwG©3°þ)½› :+hÀÙ:\ ”¾aÀ)¦›4s>5Γ ]?fçÐq~Ÿ4;¨ [@³çû0LØ¢‹ÿÀ€;m*dË4>ËÀ¯5€†Öe˜'‹²£ŸglêGú§~Îë£Y'`潺€´rð 4¯èõ m\ÿíülüáÌðGÞ4¦‹ºtð:ŸÛCC<¿ªþ:":[Ú¿Äuy9î/è9bB¶U€ÓOé"Q¨€BZïç›u¹¿âöË�GzŸÑ°%šÌ“]MrºGàmËt¬ˆž…û¹>¬I.�p%Ìû·àŽ÷<_ð~ÞôÛ‹Ë(8¡uŸÌZ»N5Ðûl~ÿ’ú?6ûút®HšØz|84  ãüùüÔ ˆ^Þÿs?°ç‡Zç&KOØBÞçgË??óíÌì?ùûQÈ–aÆÍ' 4³ùŸ"/¸Ê M\ qýÈüÌ‚l)\``̴בPlœÈz—Æ,X:2#kD®€ÛÀž"2ª<®w³Œ1€÷iyFå²¢&S}½v,„câTüâøç¥81@ùõ™âü91Ý#êA ø% ˆæ—¦=3`Öªï<:çIÐó’ðH6ûûœ/ÏÞ(  kÅoǦÿÎ'!]­Ê7=Óx<fà—ráõ量ƒÞ?,Ó9þØBï¢`-ç@õ8}×ÐúV:UÎ`y2ÌâƒUÄ;#Kâ÷ñ™«ü˜Ë‹ó÷JGX¥y3•÷™²Å(ÙÒ ”ïåÛ¦ùè£41ÀÆžT¤¥ö哬™Oz`Éa…i àíˆÖ«¬Z)ÏA ¥åt¸,x?«Z.·$GQ<;ÿ'z`u•Êçý¦•e~ëgV×ã‡ÓqíÒºa�¹ÜO"=´ïÇJ¯*?kazU±È]NÀŽþÎéÄz(Çqh£Ep³×´o€Ž×,×dˆçÓp–Î{Í>€«B$]X Jà¡yŸÒÈ‚ëGá'ñYí‹h] y^_—ÀRóÑÏ¢|7Ü>kvè}º,ÏlgšÎt5ÆYê`”éÍB´ýGQô߬DáúÝQR¸ÏùHúóxÞ ü?3t¸–¼Í‚–'8õPýŽóA?()46 Pç#ÕšžUz?Ãü§ç ¢sÆ_´ä!pBH…ª�Ñ+Šß,'€PŸßPÊY ðÂõ;$:¹ßªùBô§¨Ð¸L@ÎUràÆ�#€yN gä´JåªqÎ𑤯Yˆå…³Ÿãq½xü}Fßgd|ÌÄz¤+€h¾ g8$~^q;šüZIŸ8ÇqþWL¡ž\ËÉÇöK½®Îèù‡iîï¢þ6|$û?ÿêƒËÿ5L€ßûÏó?¨Ü!ÖiI5E¸–EW вßÙ…bâ[~o1E‡“�àwþLb»ä2±Ï2L`ö®°|‡X÷]^ý–aÞ롞¥Xo=Þ%€ì›ýÛÿÛíù柸¤8·0}xE¿·ÜÂ,=]˜X³^ÒfÖÏ2\ßý|o¡’C5ÌÒß õÌù^T¿ëÀ|º¬>[z§£³L}½üd{Þ6ßd»ÍÒóæèí9•2gÒŸSº9Øàåïµßmz~Õ‘ÞÖî¢È¯ œžéÓÏ%í÷Û•|m=üx”Ïl5¯^œÿr;È÷¹ç&ýœ›½wøœË­rabM;®,]ºÿ\ôw×ãm©°ùÚRΕ>„2Íq¯ßÆ÷ù¿Ú8´Áí¿ QÎõ3ׇßÛ|š9ÝÏc“Þ›e%Ó|÷ÞËø¯o\wò£øÎõ<ïÏp@ðÆÓmóþ•‰ß7¯x|,øÎS»Á䇎|!Ò3n˜£|Î)Þœé?çµ~ÓÁï~Nå÷•Teªíºƒ¥>ÏBµ~àÏÃéJÏ®³µPrUïSʘ˜*¿‹Þ™pØ8𮵼ôÅxé[—¹\O~ºó´¾êPç¿7?ÕéÊë>×îã–?µü¼øe; µ}i'õ¾ì¢'v÷—ËkŽãþòxŸ’ùý}„ËêyE½•Òøœâ|÷ùaÏY—ÖßAñ.E{é|gÓ÷Z°ýÛ£×öàÜŸ.Ìs~¿>š6ý­"žäûÛðûy­{ã®,§{=«­à—×왟—†žá#X†×Õú\®ij ßNGwN—ùjçÛ¾ ã3n&¾ôÓóŠjSëW]é^Ó pS¼÷é(é•ñ=ŽÄx·=þþ¯›Ò×Ðýÿ&ÅíÄeº_9t{õ¨{‡·!ç‰ëí_ry—:¼™µ+ŸZ¨IÄ4¿†ðeõtÃøQ¦Ïýå¶[ŸL7^¦ ¯ö²Ï)¿_Òó-õìÑÕu¾²ù¾IϯM¼›Å{�èonê¬C?—=õ»¥øÂAò§{Ôíó†ò»aò{ƒa¡>öI|‡Íßu:lÉüöº=M—w]~ÔgöÚüÑ· ])®·žO?lþ»>_üünÐôÜ^oßNÓÒ�ø‹ßý›¹ïþ¯za,»j.aÞO›o_pË™H³À˜º“Œ-Ä~ @ ýÒüÀ;Óáë*`…Žü¼r;Þ3ðÅ–b@XŒù#Äñå0ê€åx| ™UÇ ¬© >‡ÆÓñy öZ@gÔ}@‡:ÆÏÃ6x}õ”‚ï�lØ]ËÛ+ó+ä\ëpa0- )œ,8Ö™ò€3D� ù�•Þ Â-=çI@u[<{ù”œÏÁtÛø·{sñƒ$s=J L–™®aåu÷Ç ¸^‚‚¡W–šUûÛ®/î:wŸÞË”Åv³ý¤>±ã°^ytP2×Ì%` (`&[Ý=ž`â»­hÛq+Ìq\ÏõŒk–e Ö€°Û•ßZ>¶žÝ@®—Ç9ý _Î/�0Kí&ó«üÜ~Dí;Çß©Ýç Ðæ‰Ù½y®‹Kz]ò8˜í<S|††r<Ÿ«÷ÃjP~Ÿ~6´óšØ4¥³ŽºzÑ…ù2ݼóJÏœÛÏ®WºLyQä;D±„ãÉy+®ºi~Éíc÷}Š0ž`Ï£“׿>~þ2HºfSÿ©íÇúŸßÓ…‹Ê/‡šâMÞú#iZÅ»~Eaûõül—A#žÏ%Î':”bŠYõ+CWÉ‚ðY5ÿß*¾£³_Tò¯Å¬µW׹ˮ#Þ¸¸ù߆úÊ|,?% }Y-§ÞR, ¿mò•éÊs­ž‘/Í÷!ýÚ|2fOrÃN¶ýâÅaã£O<ØGÏe%§áã]óùõÛ.@·€]Ša_©ç[½ó³ì·ö\_Ô#hEŽ›œ¾™M¿Là‹‡í8•ý9ÿ–3È+õÛ}>öÅÒR0ËÐqKa¨¤·Ï9\¤õ2».^o=JüMôO73ÕÆIYnÁx­ÞõqxË}®aCGŒ_O˧ZüרŸ+¦)·V@ÿ~…û¤ëµyCÎËöù ^À+·œ^ŸnÊô ñ°PX·Šg?7‹RûøpYä'ã¿1¿CûI9ÿÔÖ—aՒ޾’9¼fé³åߘ:~ûݨJxm:ÿûÁ빎g둟»Ûeh¼zúnE�K¯œ:Êý¾0K¯2pÚ~0ðÙ^Zy¯‚µÈròï d©rœ»ÁTþ(³é\z# f0/|›~¿¦ÿ¾V@×;é½u¥˜óï²+ï Ó ýFüÖ�6·Œ±…˜w§˜ ]¶=�ä÷ö@9HÃR<íûë·ÅÝ/zžûøQ?HMW®ôAϯ`x�’gù¡JJ`F úÅ ¾(mÖä7\³ú¼ “îV�?,\Pü²&R�牊¬ÅˆWë‹^ ;+êsŠ~€¹¦‰wÝïç^³ü’ÀäÛäo¸õþ87àkÓÚIÁœ’ùwx ç©\ pX�LÏbÈaºZß;ДõöÓåq’ËÕóŠÚçÌ|7W‰w>HðWð! 8Ëàó±äÖ€Ã> ­O`èæ#,¹\‹ZþîX˜©gVP5ý̃w†ñן_fÓºe-QmìéÆK9Îç*Ïv>µ¹.}z À§¬œ¿¬…ذ0¨ÈY÷k¦¯Ÿžë*|ÔHø—¤Ú8¢Yœ÷l‘\ÖÓツ‰üÕóßl…Øó€ò¾ùJÓÅõ)çía–šßy¿|Q¤{UMUßw\ ÜGÜ2€Áu÷é _`:(¶,÷z œc´å३¿mxºÎ üý2P -/jíØõÜåI€é¯YZI‹® PùtK D]ßlѦ×ÁÙžü¬¥I? å}çÇzÑéºÞwYò0ÐqëZ¾YrÈbGm¡dß×B—Õ˜šC5¾M?Þ­ebmEîö´`Оe†üîÑííÏ ÄÆÐÑÌ*K1ž^7Ã%jó�[¦Äïý–�’î:pu«šŽ¿w­Wuñ¶^ßsn5 yxõ¹Yàú¡èÕë1ÔchèÆnN•WNo-ç^_“>ÒºèÐó´.OÎÖ²k hþ½Ùk‰åçËaY΀×뀞o«_—¶Scpeùnçiqé×#Ž·7Tï7ÄÏ y[àÃZô½°ë„›¦ü¡ë¯W¬7é·/]í½ÏÇ7;‚!Ïo0\ÕDƳ€g_½êôö•gë[« ÿúêS{î3Ýðw 5@«Æ—Ýñ0ÅÁºT–T¨[~ ¶:ª¾tNúÎ|,p6 �ÖB¬âÝaú7»PÌ¿¤‹Åw+ùñûo’kį €ö•¤KY„ à‹27üÀ»lþ˜î,óÃu +û"ƒ4.;‚=ðt¬û†ý¬ ù¥ô³ë弋ÄiRù.ô{h(ÅsWCº|I¿ÖÔ¶ê2L#î²ÐÒ–Uº>œÎZ`Ô‚µðÈïõlÖeÍlo¾ú¹¼ØÂE{Vã}Zf~ ^×ç‹Fî¡6Y¥˜ªXó!®šø=©ûéz[ ºî0rqÇÏìúŽ k &ž_ÉgnW¾K‹0 ßÅ…�¢Ho-mj-PZœp½ã¯Âò¹­r™«Ì#Ù2¤kÜÏõ�]ù7(Ö"Õ³¼õæOxˆô éZžq¿hæzç k9hßËüæL~õq3kæE[^·ëÖú›aãî¼ú\ÆüšôÍêÃÅ8¥ëáî÷}A[Öå·}žO±uýYwi;E[kiààb�@3dݳë¼"ýñšv;]ÀYÏe¢¤ßZౘñ,µEÛ\•.™_ŸÞ¼´L¶ŸÐåÕì>soü6;pD=–W‚uåÞÔç­šEœu­WZŠ S<ÐåÈóXm_ª-9vßþûÂZWõ¥«Bûkû[ÿv½`K1Ÿ¿Ÿß*êY(µña]äy.áÌO^ðÎÑ>o‰¿ò­ ]ß–�^WU—üñØ/ðé³�Í´�_í_÷\S* zýtZ{OŒw»ò½°UômYÜå2ÑSœÈ ·è÷Ò¬3·ÜtÞ/ -ˆ.+ëQ`¦·,*ÅÆ³Eý¦ ¯+@дaz lzŸDÝA»`Ì<Ãò/éÂô€Dvi(-º,C�¾Û"¾ÍŸû§ç¢P§á ô¸±@?ßH.Yî+K1K1K¿j­e›çÚ²k/¯ ŒÜÆô®ëßkªÝ#òFÏs_¨YÌöõDzÞ8ñ˜ ©n¹ôý�ƒý|¹žŠØp`êméµÀ£ÖEâ'éêÃåÔèÂuâ;wl¹ÏÂ’ê@ ¤9–Vn<\ÿ.²AhÝn`º}*ß_sSy. ¿%Àë[0àõµù-Óó]a¿„ÀløªjA&ò±À[Š5ò2Io �{—ÞçtJSnh(-¾_þe¨1ÝšÎòn.ÿ¹^ÿ¾òë¶AoÇŸ[OéBĆšÅ—԰ιùv«ñlÖÒ–¿1¯iþéôR`Ü-¸9W}Y¥·TÌVýý£ëÀ\xŸ»íb5ÞûòïI¾S]ÌÚïÒ®‹Ê:µõÛô¯ýÞ}‡ØôA÷×iëÚóœyÏw<¥ ,wز�œøön°T‹ÆïOvœyß-(öç‘~Á¹vm˜Ûó•¨ÿ¹±“–?¯Tª²ý%€5GùØô%™šWÎoÙbÖR«¿‡ùº¹bõ‚7¯y¿ž«Kˆ¢_�ã…ÐäÕÚ¯gé‚6¾­í#ª·«u†>Ëй*Às=gªžká.ŠJ—·u—xÝå206Ûù}ú§±Xb1Þ]/-À–õ‘–ðC]Ë\%°gç³Y‡þš¥è°úÌv 6$}5 $ø�æ�� �IDATÑîp®Ò]˜yqèn²®ÀÖ7Î2�;t~òó±wiiº®+öÏcÓ úñ¼sŸÞT\K»Š}~ûZ…>>e|} bl¦ùVœz>–¡Ûõ ïê|úsdÍét€8ZòŽ"¶@«…aý>—–uàqhÐñ-P6íÝaþ½9%`Ü£ÛB‰]'¥¾f™v)æÚ9¬ ˜ò¯l‰á÷³[ã¯ZŸ -„S9dAvÓ™!†YÊ\LWÞ Õ¯uý–g”.º,W °k–¤�ÏŠ$à:[Ënçéúuü°ô%€5Œî2øåLïXNË›+\Wÿè*W›n—”ü~UZTéqt«ržÐñnTÞ¿Q9{á¦É_µdðRùãdžK5ÿX*< 1/xFC-íŠÚ «ŸvÛøZ‰5Wt% â9ÑD5V_¿¯•—/¿Ã]õ §CÁi][–ùùóÑ›^à©ï½Öé–ï U˜öî··½ãÿÀüº.׆ւÌ~‡‰×g9ÖùÝÔjé;-Øl`úk€™ˆEˆ1È_}‡ØÑxúƒžï:¼—~…ŘºC¬v÷*參ÄoØe"Å»ÄìÀƒA ·zÎèÎ%ÔC5K»/[î uþt®Wlð4oý|} µþ 5ï¥ëú4®¬ ¸&¡ûîœ_ý;ÓÏ_}�ž5ßË|»--æý’˯Ìû!šAY l5K³‹¼š¥C­|/”�W·&þôš÷èIq=‰VW·Ü&`œÞqc·Àùm]"öqÚÞ‰'5Ó‡ºìÓ€N¦›ß×�w<T€¯ä2ºv[Ûýñbç{'Ÿ½³'¿÷ø4gÒÍ% K%|–ïÚC%?oœÏ:Î{,‡ÎÍs ¬À2ñ«ŸºÜòNµ. µl=[‹ ývÍ‹çÆµ¢¬…m—¡ý(ûãEOÖ•Þpü.ŸWcؘþb5úíüXÏ·~÷f­ú¹¥é{¿>µ´´Ü”ém~À03[^K€lšý©×[´EL}ýè³X÷Öw[NOïkº,Ýýñ^®·À³óÌ0…[Nmœ]t¦®ïú³b–|îsÍVÛ·Z׌o«^6œ?}€½ îHÖ|ñôƒ‡ÊK 'Ú†·¯´\,î°,þ«ísJK±¾uKiáÅõºþÙ|¬‘uqgéµcP+]XÖ�>f s‹ËÒòÁIÓBÆ~|]=_×ù9¬Ô𥨭é»Ë-]ìYÀwX(ïð¹4Ϻ>ò/]n¥};F¾çÊÑ»SÈ[äüŸË;††¬WVÐ\Þ‰”ëoý}ýy RÖ±”igpßÅãëª@ßO7ü®/û^¯ ýw’1—Sů¥/ß×óóÚÕ³`²tu¹Î´ýfÈY].3@rYMïß ¶nDŠÞ$—‰ön1˜÷ÀíÒEbãµ·oYy«÷@ßê\Ó­3µrmÿóËë€2PV«YTZ†á–bÝ+UÝBk:À¦À±ôÜèpnô�GuK¸¡wkõ…¡NŽû,¿¦ }ù S¸é Ö²²ÌÏ_µ ,Ä:¾Ãä×PMe1ö=ZœqpëS·û–þÿ`ú6ýÇw†ý°óް®;¿jïcøJæ¾ÁWô[·$‹¬Ów†¥ïdfC P)ãÕB]qÀ„ÝárDçoéœ~xvkJN{gXÉ»qïuuéåvüø g}tûwXÕ¬eMõ·¿ÄÝ·+7ÎV3TÖÂ;øÀÀ¹‰ïß-TÞbùáoì/L>³¸èÝ Ùt^˜íÀl˜^ð£›ÒUèu-Æ:œÎBÌb‡äçÝuä½ï££|_¿ãN¢õùNö›š€¾xÏ–<= ïõ ô}ê ¥ ¿ë~l]ë•ÀTÍuKŒ¥ªsœ›qÝiÎ)~J‹²| ŒytÍ9ñnC[œy.­Ÿ´T“@Ø\QÞ\¥že}k|•õ¸pž¥b€ü½!ÀcaÈ®ÏïØõÈîûa¹î{ŠÒòxšPÒQ³0EÏ{Ÿþ:5>�6[iÿëÛk ìºù•õ©G Äh×¶Óìä<W®ûÓ{%Nùf xí‚°~‡ VzW¡½ãF[ºI€¬ôyó>ß…Ê®¬­\9/Ç µÖ•ïÏj >²C-ìm(׃â•Tø®Bs˜î–¿ò˜\Û¿»%vÜ!Ö²EX.gÀ¨·c_ý½ý‰7^­‹O›¯î/þÝy�zöÉvð]h³¦ÿ×]®±À+-!ë L>ÐXæïíÿ®s—˜ŽQ–¦sÑV ´gÕûiÇÉeï_puÝ+ úÃìàshwÐ.ß,eÞ~·Å{ Ç’‘,äø—]§ ðKº,ÐZ¯%àÁå]we—‹š~¿ó,^¬¥X ÓT–ª3Óµ«Í±Âí®Çð;¼.ÅꊱnÁ3t¼×î 2#•åö5uKD 4{�l-Ì—ûéÍŽø]Ï7*ß3Pv“âÕ[¼cý ÞøõÆëÍ)æí. ³lù¦ûûÁùèk­ÇK (ë ¸¹Ñë Ñ·™³_‡Zн©¼¯Ñ÷o*X‹®7=ü»>]ÃVÔ óé-ûÑлԦSèË¿¤§¦"wÝ»ÐøWIl)å¸B¼VèsUxÝ|У�®)€>4 &]–áë"žg‰åýÊ ï‹éó¯È‡-ÁšwÓ]bïUïSåóatéP?8Ùƒµ< Ü3A¸3Ì÷y~™×Ó¡.iú}_®µayYù6”wAXÀ‹ùï·×-Ìö ld°®š< w+÷5~=J~烤ÖDµ®“J—Gš/uËO£úZ°Õº/*šËw}6LëzÊ+¹L_Ó-Ê™5‚Î,ø¬AQÓPW¾/¿×ï ª¿Í¡¤J÷·>A–µ�zàÏ£U® ׈*„ €ÙÇï€w¸k$¿¼: i…ó[ÖN�Jñ;GXárϡdzü>TcÕãKpc]+êïèºíä'-Ú¼Y.÷¼˜·4µËÇš+Õ\?}§˜ ž"€uEÇ�l@ÆÖe'[š5}Xjý—éÿ>CÍÂo¨ @†ÓW@½ïÓïr¾Ň2ß¾úX~ÔîÀÊ¡Kq€#[Ÿ!ÁË÷ˆÎãÁwíÑåYÎ×,Ñ$æ ô}Å%OÞsi§Ô­úQ³¸¨ 5`ÚÕßÿ­eØ÷ÓËõl: ˜¡Že*ùÙsŒãñ·Ìþ׳ìêóð é¼4üÍéËs”'Èïr¬h]Z�Kæ+ôÝãÝRön¯ U s¡¨=iHË-8´üÔ¿õüËúxߥÅ\÷¾åß „”™n+¥Eg­ô¡ÞàókgCÍ…iÎíúw2 hàA»€ÓõóôèÝsh0ýš\(&˺C¬KàÛ׿%pu‰R£¿OáD~ï8_k‰V ø«ågçýÒòm:…‹×ðزß2¬ÏŽeÚ0½Å®G®¡–bü[›ÁÊ÷¶Ý¦«Wvµéµ›8º=üärôûº«Ð!û$ (e ,Ö¨´»)ó·®ù.1 ¨?J>A¤2î9uÍÈåEú§s…Y %LÕ½ôQù}ÍY¤-ÿæ€X]¡°\oÝ,-‹†…>€«@Ýè‰ßÿ~˜‚Jérѧ{ø]pÖrlZ ÔÕèé³ÔËtßêyßÙž\º¡ùýa®¯ °uäo]%º@ß´áת_Þ1¿l)ö,Àôu5?¨üÀ»Ñâ H€×W2iÈ€Yv™(\'iy'4?ŠÏôû ýv¹päÐ 8L§afB®áÙ†PþùîatÔ|ö÷ã×~~Rs¿[ÀÞ-ŠâÒ¡Kà˜¿û–9Ì ÊOº´!ÝŸ. QwÙ˜Ë÷ô5K™nÀÀÖϺî’ýeˆKŠ:_-8Wü¢’O—ËÅá¡O³º»„ c7[µ¬èÌÕõ[†ù߇ŠÝËxV ©Ek³ó›´¼Z^ ø’ßãú¼ÚOÝ÷@ô¹žìš_< (¯&ÚAC®2P¤k\ºDÔ®ö<z ëÓ ¯å£éÖéæœ|ºÓQ£w®ò¾N7÷_ËŸÌQmi6gÞkżñ^sÝÖÇ?Û?݃i »ÚL?îjÿ€i]´i ¡‹4N§›Ï+oJþwÏ_Ó»8:S s©XÃÙu…Ú<2‹ªM«ú…µØ.C—eGW}ºÚ2ßš¥•œçÊúœwÎ볨ﯺ÷]V¡¢î¡ [ Ê–n5 þn…ÏX.yHèöp0<¿¡wá }*6~¨ïÛk‘ú ¦[ˆÕ騻<¬ÕOZ4]š|ì³gU³ãø}ç¿>×uÖâJÒÍß/‹r4ðåYÖ ˆÖü¼,æCßRÓ³,³�¥ e¨¹Ú«‹c.ݧ|Þv§‘ ¥åIßÊeï¶ó¨ó¨ðV—oé2±tµ:½su@ žå”lqïœêÁ{î¾¥1€³€È­ ¼Óóƒ]Ä· Ñ@{bi ŒùÀF÷ŒÜ¨ùûºËJ<ÛÞ]|ˆåû–Z}VÃ-Á8tßM6ì†$| ªlYäÇï 5—w}®°ê"Êü­ëβ<_îãïsnVVä›×v݃tåg/M§â@#¼W€Ìãg¦Ãªe}ºCÍEŸµäœþÎJ™ÿëÁ€Jw¸®ÅÓkÓó†Ëðxã(øõ±ÁŠê¨}AÇÏ€¾£«,¢ç}èSõjQ‹Añß8;–ièìÀ†”5‹¼>K½jw‡©ïö½�žlü˜ïµ`-»lþ5׈}®¯u‡Yû–îûúN±oEœ,ýÐ<û–fߘ_yW˜µÓ®ߣ_\ ±Zp-Ä„%Ù…Æjê]Â×(ë ,Ć…ë^Æ] Àc¸À0ͳšë—[UP·oñº€½<¸År|M+j€¦ýKa‹*ÿZ:Ke®­u‘h]ó”|évÑRa>eø}�ŸuTZª1•ÓXÞu목 ¨«ñ£ÿÎ;ki]NM7»,Aõп~úá7uç7cÆ!õË®%¥Àµ @ôÚÅ-é¹éð<‰*ÔÞ£æZ«~w”¥ÔwÝ×Ïa/]iyUZði‹±é5Ú¼ùl®ç»Ç/û<D³v®òýuÁ…�¥‹Æ˜Ž]4Ö�Åiù¢Ø5œtùféäŠ*œû|ýr0Xã_úmŽcx[—‰5 Ó>›ÓéBý.®n˰ïË2®n16[‰ïõ,¿†ð©tíW†îýOpKEš!ë˜ßÿY‘€ûo èóçëBÙ–“ÓÍVö)y=¶¼C€ôÙêú[Îßž ŸC¶\±çnK’Ú×þýE·«Äi÷ñV©¤dØ*ÿ}>#.� ¡vd lŠsMÍ"'[4 Y¥`^æ[ÞÑcëÕ=ÿçþ]ª0 ä×û™?žn9ýì6ô¹r¨eÀ+'¿ ¸YW‡î~¡vçXy7ÚÐ[ìúÎÉ5Û)}—Ø­)OÚu—eÝ;ñav6òÙÿ’ku=@¯›+1t)Ôn¨©[¬\¦_ý¾Ì¿pzãâ5Í 7½H‹“¾PóŒ¢9¥ï`*ëç»6Ì.k‚äK7¿.×~èv-šCÍ3K½Þô—@ç°q3ÔÅ¡åÏ´|ëRïfU <Ýx©9¨+ùÕ ¾ËÂнeÆËeOü\N×zßgÀ¦ à•ùxë[†Y 1cææ,¾7fÜ€ìÒä“-Ƽþ*ëÓ½ž•�J´t»Lõ‘õ¿Qͧ2àxPw¹Ça:Ì×ÄÿëZh–À˜_ßé¿é|ñÝ`7 ÀGo Œ Óe%ðÖm _¨,PÕí±Ȫ×Û(o ¸µù^ Øí�°¬EV§…ʻŹ4ì�ÀjÁÆšß¿ÞcÓW_'‹0Þ¡÷À{ïc‹¬_"»JÌ@ÖW&þWEzàK¼Ww‰¹®ðâ»Ãè÷~/îëš@ëRZ£ìû ðé.ç²'}j[ÓC\Fz_ûë5 ©º†U-xêÒ‹5Žë®šú4|l<?è¤ç±ÛµáyO¹ç©^5p—àÚZª 9ðÚr¼ï,éì¸ü®|k®?ËxúûÛß%Ó|׆zÖùøïkbå· F€Ù5xýPÂxÖ²F~î�Êú?2X‹DÉïÚ8²Ï¾€À“sn~Ö]œÖ­ÙÝïµµô~¹s½‡>‹®Ÿ|ö�@~ß5¯yýX»Z¬ _³{¾ô�Yná’s `›\H6¥+Ì邞íRf’iBž½ú®êšŠ·ƒí2ð4ýüëßva€Œi)ªÃ5 ÉßGxë2‡a–_³&ýEO|Ÿ;³4.ò:k¤²Ÿ÷Y‚sþÖ’Fz�°`v½éo•óŠE°]w»WÄÒÒ…÷•}ãéºãÌ@ÖúõBΥ慺˜~¨sÔY�hLù Œu�dö|S*¸Y@¨+”�uÙ×oQ©Ó—P·Í¯WZþ}®ÐºÄWZ³~W[šq<Kß—¥¶<¯tŸ?4°|K<wï34J±Ý-Šõ¶Ðq õ»Äjw¯i*ëâAßÒ­Ʀ£×ã×,O<àÇÆüö(-źÚ[ºúCG<�^“ËÄ!Ðy_ùú»µÔ¹ì¤[ÞeÆ|pÝr÷Ãà"ˆ¯÷Ÿa–ßLçk˜È§¨t¨ßÅåˆë ðë.¯wùÆM“>[FÖ ìÒÂȶ§ýÞWïüõÚy®ݾ6Ý=úäïd�,>߬œ'ozbN<”…Ø+ó«ûë­4N½õ¶¯¿–Àžo€E¶CWx]ùê.î2_uÎÝw‰Ýœš‚îqR@茟Ãteö}?_|`lxð]XÖ¾_x«‡¡w¤uÏ;oŠ÷>l=ÊxÝtÖøR±èêÓL–^xûÓ®tÎûÚ÷ëi*øwˆ%&-ÁtøÚ¦¬—´ðÒ@aï) G®éêð—C,Äà%éI霻Ƽ»§Ѽå]�\'j�¨[OÇKÞV`•—£>'J׽ܾ¼”Ýj6ÖB·�y¨K´î ®l,ðTsÕ5ë8o›øÝùnXþyA·¥Çæ«é+`“à]|/°èüK¾jWh¥�«ßBÏ5Èéz¡¬—¾“­êšö2ýE¯ˆœ]™õÝYÕUÚêçYAa·¦~÷{éPì*‘ïZ uÁe—àdzÌ.ô<×^¯œø% dï¶ÒwZIûƒ.-]|ª}¯ 8ºø“{û\¬{|+ËӀѬà‡ägÝÞsͪfA8Wy.ó=ï™ßKàÌËÇÖËÞ±˜Æ¿è¯5€W=7ºŸ$‹oq·˜ CíÆ<¾t 'd*û vøïrùÛ]²Ÿßð;Å|—ÐÓq¬?äþÓΙñ¥÷]Ôè}BÝ’íU5ä¼h-â%ýÞ~ÂÒÓ?¿^¸óuii~Ñ«PãYÆ[W³i?TZ ±ä¹UÝWúÏÓµöÜ€ÊóõB ôÖ~zõŒ¹'‡p¡-Å8LíþÒœw¼àµ'N|7Yn× õ½Ëò‚ƒíŸ\km¡iû¥ö¬Ð%~òÖ£¾;¡Øâ­x®5³zgÝ}ˆ:äQµàˆx«ÓßgƒuIOÃå}–"}bÇ·úÔO“ž/¼« t?æú¹¼c)רÚ5™WŽJÇ€W¸ðã–ø/€±>E.¹¿Ë–Š—†Îá®õºð²e|àù9ÔÓCm¾¯¹ÄôùÌ~7ñý�Jv¼L+–Ÿv|ÕË/]^'HK¿îv¹ì<Gäv-ÆÛ&ÝËÐG‡÷œÛy¸…©ìÇlQÅ€× Ñ2>^·c—‰¯2¦,Äl=tõßsþ}wïYz‡Ü±äµC¿KÌn gh(d½~ (Ù o@X }߇†¡. mÐ.ßþ®Ð v90^¿íw÷s7½õzumy½öê"­eÌó�תæBñÿçîíu$Iš$AËb*#"±ÔÌ}O°ÄMtý}ì6uO²ìî½F±×Ó@5ñq »O²Ì‹ÌÈLfòˆ SQU‹¬aN‰ôtwûs3swÑîï£8?µYž{™_]»�b>¦–—JüKüžÙïÃ`–)fóãR‰ŒÊ~Ïö¯@Ø �{øÛ%ß ™ýï#7+A¡>Ø^óOc\1ÙÐÚç\’¾2¬úd¯˜4{vh_DZڣ¤Sò¯Ìüƒ¥µ&0)ÌáÃb] #y¤×©cW·ærT1©¶é?S){«z‡•þQþöúÌ¡‡-[ï(A茻‘=T¬^zm1_ŒY¢$švcå Ò³ƒ£fˆ)G12çVKîI{à1™_ lJÎuöŠ1ˆ OÕŽÑ”Ã×3zìÖÎ7P£ìU¹<@ìH±ó-°žøcDÇöÖQþ"òá@2óìïi§ÕžÜ½€±5ïÙùoi@îI±V–µãì·.½¹¯¤çñ³kO*ˆ/D°åå¿ìKrZ;Éù-—Ô¥Ñ9ÙmLç>ìšåö$ì:é"> €(@ÖænŸ×èX¾üõ@ÇdV­rœËùš9íB5Þ;+¥ãür ûì}êx{þü„íËæös™{ ›æñ(ˆ9à>ïOý÷zoûsUª½ju>­ü x΄a÷A=W=Ž ##ÊöS|_Τ/èÁñ7ßï'�„ ¬ H¾ôGÎìêJåÙû©æ¾Ð02ÚžDºª}ly2·|÷ùwÉb¹E·îQWùí¯Z}e^îC�Æü}ë´ïdjñrVQÓ¸C;�~ÄÓaûÑãÜ¿z@ÞŒØjµÀŒ•v1AtKªT“™ÂóÙ[yßnzÊ7^Ž€ÌŒ [Œ™.?ŠÞ^;øôE>÷Âo¦%m;=’ûš=Opº¤(}«�·nûxöËÅ0ÓR¦x|2ÄÆuk1Ë{ºnŸÝv•ta&]ÆçX>³Ï¤ŸÞYo{ž’„C EÕþ1ægZ.ãó’L\€D.™¸lÜ+•xPóÞ~³Äö­€.dîa:<f–ŽªzußœÕüµO5ɯóÖn;õyoÞ×¾µ€,"8©Š©…¦Îß¶ªXd(Á8ÏWÒŒÊ.€˜†~5Œ¯Ë>2ºþ¼m‡;žÇ‹ö÷pä»;þ‡Mw2Åæy+¦0Ánù^`VZq¬ô’r-»| ( ƒ”)¦�°DRW’ú+ûrt ¡c嘜™zÏW¤¢CŠ9„²üð¬$$3iûb¼‚²O‰Aϰ°Ž,æ¨QI”�RåèÄQ@’_9î%„jÉÅU^æ˜Ãvg÷µ w ¥±2‡ê³ü…•™Ý’q °sqž2-¼T1%xú¹@Wϰ¿ì´“t‡?,)ǧ1Æ‹�\?œLšt ׆ýLÏÈõL°Xƒ °Å¥ð¬ž1àð¸*/¦ˆ@ÒQ8Ð#CÆK¾˜Ç¹R¥Jö<<°¾b Åtm¹£dYŸáfÏ·€ãdâýÁö÷ÿÍþw*ŽÜ,0Ÿ1ïŽie˜fch8Ûemù„5ÏùíHÒˬŠÌÔùÅ·gïø(ο·Ý¦ÞƒTIkF—g’Þö s¬y‡õñÚ/Ïî=‚½—(Æ)=©A,/c¸ÏZ`@2pƒÎ—S?á&°g u²cxæž_å›i”¼fgUõ@Ðþ¯K*ÕB³ûF¾og9Û�ÆøHZõ ÷¤Èð»á(ÒáŠcÄùÿ‰žyéZæã+×À…Œ50XK!—ÎÒYý8Õž¶<º?®t­ƒ˜ çÍ÷¼¾Ô`eÕÀ¼k7wÀu%ûn.Ïì{%ã±ã^iËGßñjᓼèº9ƯÇoåø¨tðù{1Ä|;ä{(K¥c}¹£?‹ÍÆÇ¥ýy0Àù0Ç+‹Œ´ŠÑ ÓÉ÷+‡ð^¯cxå×òº®ñØfÀ!?cT „&p¶ò·ýåÏß÷¢Ÿ›;l¿lC�±�ê>èZ×{@ò‘HÚü2€Œµ‡ŠùÔ•ÞëK‚VÀR•ï£ØW�ØczuUŽ+ëþ¥ì¼÷‘/üx÷¥[þº~[1á–UÌ´n¾>½þõª÷¦Ã¯é¦é#P„1¾†TD©C“ޏhŒ±$ÿ(SÀØÇÿå­€;÷{dˆýuÝþz=þ×ø ~_ ±Kl2À¬±Ø_“6¥½dâÀs€™“LœûßÇXÒ‡“öñ/ަ¤¿ÍØbÄüJ(þxØs™5˜aÓ0Ö�æ»—ŽÞŸG{/bˆºÏõ¥LñÃÕ~H.†ÞúÀÊ?4§¡#Xx›÷å¶+ò½c*~ ÛóÆÐ’ŠÊ!6H9”D"[q>-[ÎVpûßc=ªrßÎùJ óx‘íâÏW"k¥¹/uŸ‹x9 ïwWª«JK¡îgƒŠ]]廤©*e®a/ݦ†ù‚Ì)Ç -ëï= ÷$û«ßbñãkß÷ëP$Ÿ¬Üì)Á˜£VÑÛ¾=Ðw^úÑ:Ü=0È™_*ÖÚñ´\zÇ¥)±žª½•€ë>TŽŒK|¹ÕÎÎ×+–´ƒÝÇ ÓYÄýFIІ4(€Xßìƒ÷óžfÄ·ú«–ND)×=æVÆ€öçáóm—[YõÞÒeä-ã�OýH€qL7_Øß“:ãK= uûjƼª2N|Í&#Ç3“Ϥ½ó…«ÿ±÷õ~…ûšñRmóöÌ[hÙ«èo÷¥¶ÒééBÔÆ¤Ú|yiÊß9±Fìý³«DÝ� àä€Ö²ìyÇeÝ?üùõ8{ý’(ÄØv÷·§PœÚx}ÔwQn«ÿÝçðgíaí1<á50Èì Ϙ�MÏñÖuÏMàÞJab¹;Ra�”•èb$Y)x. �� �IDATMwß4þøp çM?Z6_Aºðp ±šß©«]lº•ÜLׯ ªžÇ—û—Çh´õ íXï1²sþ<¥MÄÓ­c2Äu?‡ Q ¯ÅûUžn”ªô�4g�Vç½Íl¶¿1 Î¦û.Ò{¿¦ð.®(s‰O޶Ì_¯bxy z¶‹í'j¼2 ¹–ܵަfˆuí1Œ@”Tì#Èѱ¶8°² 8á>PU¬¯•¯ýß‹÷Ì¿ »õWÆç¬–n¬,ŸcÌ8:?O -Œñ54à…±Àv™b.Rz~rÜi]` ëykŸý¿þ÷ù·ÿþñ1Æ@¦Ø´ €ýyÀ¦U’ƒ([@J%›1Â&¬3 cƒ lî€î?ü~ú§‡ÿL’;”¬­DÂ;^ß·r³kÑ-qŸ„\]žÊ5À·Žþ�±ìŠÊþãk9ˆ=sb1Ä&SC­H¶åd̾]f«%æÃöm}Žw”ÍJéü×ýëHéô÷1 êöëK9²üÎÅþg±GYÿ¼=~Nî¬ö]y¬*¦˜©äóÏsï;ò´CÞÚþø)İããõåv~±6�O«Ü|\®òãuvÜ* Š•—;fc=U{a_œ?^ä|Äʽ€;_æè¯æ¹^¾Pš÷‹ÕÒ¦‡1îÔ‡ �«�|g=àè>aÀÌîáÉËGþ¥.M?gÝŸöò]×sýY”°z>t¾1xÎ�6ÆhY¿ãs/:F;@þè_JÇag|jÆØ´c÷:ïQÓ]”Þ±c=¹ãHèöµ¿ê~Ñ{ò}–£ûû�§• \:gÿ=cø!Î1Å<“([ÚØûêkx_íÕcJb)Y¹QÚð(éûš?×–tâì‡@ŒôzŸŸuŸ(æ kÏìúç4ßÏ*Á"4aã5½NYt,þ¬ñеûÊ­ÊûÚ(oÆT²õéö÷Õ3¯l=x?_û“!6™`΄VΛ¹NÎÛ³t¾ž¯×~{pû¬˜#>Jª-àí ö}I|ûÕýÍ_ŒÖzž³VYo›=.JÉÝ—N•n4.•8§nþŒy9Þ‹ÕÃÚÇÇ<Ÿ3—bz¬ÿÝ«mæÛ^­Y|¾4-ÑŒöpæ>"Sǃš?üxšõa�ÚÓµ>æÛ>#iŠ ˆßí§;ùæöÖÌŸ2Ä”4áhÔïÊv£a~ö ¶›ßîï(鈱Åz€ÿϯÚîS7ÿÃcü¯þ×/ÿö?[×oI&ÀVë÷ʺ×+éDR/WŸþ§ÿø_¿ü7+™ø+\öWHè· •ˆö;l=`†@Æ ûÞ@˜“LôMð·Sìû ±Ã¦tb#f˜·ø!ÏÍW¯F*±ŽÞÄŽï½Â}ˆSå¬V0¢tb¼º -Æœgî-ËW‚- ì’ï’¦íH|­Ø(AÒY«Ü)/23ÿÀœœCH3ÞPJÍ·ë’rX¥F†Û=’»ÀW-¡ÙK© óül L¯®\Ý‘©´gšrù»ïÊECæWeŒ“ŽÊëÇà ì{�‹I¼Ùñ²€¾‚Ž1”l;`ºØ_ìøñÀÔ)g�v³’‰ÞÔŠ± Xùc{ké5Ï\ó@¤•¢õÌ1oð”å;÷ñ~­Øbžéw�òD助‹Rn¶Ül¾Iûó_°pzˆíLÅÜ8ÀpnψÛÐS¥á€¸.M[qÍ^§fzüwµ€¢s½íÇzYżS¿Ÿ›ó¦Š%†Lµš)†å¨ÚowŒ¡cc¡ñvTíꥧÏaÁŽ!Æ¥é|y×g¤’ÚóåfíÍ?wÕçïþ:y/z/†å(Þð{góí’»+/V­ìŸý­ZÐÅ÷ñ¹çïù^ê~õLÓñŠ$™tdõÝâ4ÎÅû:Ÿ°ý™”&î}Oèºu4ö³bh`9{Ö穽Šëï+ÿkµòK—…’eX³ ÍãO#wR LÙU*ññ:ChÆZœ·Ù{àl{ž’™ŸuÄ#ÓeÖ0sü׌(¦ábí íÚk?åÐ_å¸Y©›^Ì¢º=FšÎ½@\Ö/¿ç�/+?Ÿos ?k„)À‡ÏÇ(ÄñÚçV:‘åûµ„VÇ{ˆÒƒŠ ÇÇæ¹½: ŒÅ¢ê´GÎËb1ízKïcûæ1Äb‰ü^W2±b^al¯Ÿ“ªº>g iÛáL³rTKmƵºKrT~틲ŠIv/0§˜Â] Ad„¥×)ÉÂ.PFòwûæú_ÄÖ•cnMús?­Ï—Û /¸Žÿ Ò‚¿` ¥¿§û(‰øG'”L\¿OéÇ¿]bƒ]a3vØ k”­ó¢¿íI÷|6U}† n}1Ì—™–4Ꭷsø]¹¶”„_Ñh·Ì΂‘“ { Çðž¥gcgpÇ/ÆðñŽ5ëê¬B)°ù"áÙøáÌ9ï8gRo~{º9°lëÔÂ3þ—ÊÚ5*ÖË}"…ý|�;Ñ_ïu„«–9‡ÿò™Bæÿ K6¥âžá<ì÷èæ€ —#2&m»½\Ï[î]De1›¸4ŽÓï L•�½ÜÏÐy¡jkù¸öÀÖ:_Çhë}x<i~ÜG@É×ÿbVÒïìkË`,²—áÛù¥\q ýVåËæÇÛ>J†By_®ãååcõ[Ûã-k—5ž´X¯µßª–=Àë– tbq!Í l»Æ™auνTë³}ËÚyeZ¨ 03óºÖ§#Ù´¶óy¬òõÒ„X> 4”¿¯#ýr}%é{ï|þ>&ïG™½šr!ÐbkÎîw9Ê‚Ï.Œ¹ºÖB@¾@X÷»cY6>¬„úd®X€ì ¬ØJlüÄ…dG辿X·Iµ°c¦7Ç‹eбëÐØqÌ•ã®Ë˜¤ŒA™­WÈ ÂôÐ, qh:"•)7¯v4æãCA= ©U¯üì˜ßRAàô¾'ëtüZFÔ´gØÇò§LA ¢§O¸Ý¢±ñ¾Æùd„Ír¶æûéØ_@ƒŽ™6n5÷6™&Ù»eÜpÈ0½_tvµÝ±ßMg/&Ù½1ÀÞ ¿(Qø9Óý óÛ­Gôt�,>ž&CnÙ¥¿Fà Í_ÐÏÓXÀÑÜ2iER¾ „=�pýÁ€S®ùFÉq;¯�L,æ˜6¼?—í«ÛßZ”U=h2Ãî•JTíãÇ‘ŠýõµYójÐAF–J·2Œ%¶ËÀÚ5|qC í«¼N—½|î´ ©^ š†’„ôwÜ'À”3”UR‡ÿÛÑ9ŽR‘h>†Ød€]¶`ì×+�ö×2æ––&ðd%€*Æþ~ûý»�Àœ]°Õ´ÿrÛºØb¢œ¶Þ™±~¬4Q±²ŠQäW î§ê"g™Æ6E¾¹¾r»YGÿ@Séö‚kÃåz1{Á^Ì>6žWIìdåeW LÆ›*&dŒ—ýÕ?üŠî«uJ±)‡>2Oz¦¤•øHë÷ëås܈{9tDï—Ç¡Š…Ó˜ ÚÓãôñâ~�ÙG.¦04Å|Š@™nND2­ÇÀò�Æ÷/a>¸l‘ñå÷ÏA’,21ª¦ÊªñU9”•õ˜+¾Çœ¡þœ-{ óÜ<¿Ë˜©Ž_€&ÍØ™íÆ$¨ü-c =ÖÏYû±Æ2ÄN ðÌëíc3­r¢#oÁMœN°Æ9f=8.K_¿ËŽo}À@¤>½UîgØb}Ô<ôœ¤™ÿÑÁ]9àU=üœ5žÙ¼aÛ¿ò²q:<&!^ÍÓØ›�üêÝ÷ͧÓAi™Øâym«v9o¥·o8ì÷Zª2�`÷w‡7‚L«Úãï@Þ»ý–3ÿôói•J¼3Ý ‹ç«ú/FÐ¥^}g„­ï” p™s»Œ3>.âLÌ™d9påï’¯�M¦UÕ?"Ö•öçvØþÅ;îáÖTâ�ºVnᆀʼnõ3I/yæð¶V¶ÿæÖ,¬œû“6ºßÃ8._e?é¾ÏZ[ •0p¢4ÞÙG JmÊÀç» 8Ž€”vÚÁ§§JÀã xî–ãqä@ò®iÎý@ag!šm?{~”ÔéÛqÀAÞ/Õ÷ÒãøºÄ[1ÄÞ ½–�,¶Ÿ/2õ80UƦ×zøß+)@Å|\ãi¯¿Íòô%ùÈx„ý]`,_¯ÅùÎçûï%६*OµTFÅ6C ”¤Uy¿¶ËŸnL²÷°ï¥+×q%ɹ‹�¤çÏXaÈè2Ç õKñ»2¢\z£`žUŒ.’Öw˾©Ä_ÍÖJ$®ó´dâ÷q¾ÆX ­i຤»bŠ™˜^ßnÒŠ— ý€ô×/ð L°SÌÄCIÇÌP €uW3±+íü»í³¡„M€©S}þ¾³¾)û°:  {ï_±q|¹j‡1“ΊÌ»Rgùâ‚ÌÛ>çá¥ÙìÊøLòEÕoµ?Šúõ€&ÆäQL‹¼Uº/dÞ¡»êñ¹uØ/ÎCIFÝë˜=‰­–”ƒ¹Æ"Äø[é´Î‡¢b¨ Œ�a“Æ®(ÇL1¨xr¿òòYËÅžñÄZ‚I„al8Ë´`+Edœ¨­*¿ÝÏbœU@9k?Ö>Õñ™BÆHU= # ÞçxÏëR™zVŠÀ2bý|¼¶l>Ïb#¹r^ÇÏ­œ(#­—µ2Vûùù fHñVéCõõ¼ïËÝ5yJÓÑí‚ c”tÞ(ðl&=øä¶uûðó8 ¥§Ïá½$sxÏþ¥kãRˆÓ´<•ÄãY.¸é2ßgyý‚„õÞÔY�¡×»îaöªçÖ™˜ß¿½ë½ÀÛÇóãìcˆ‘ßcú¸°LÕŸ,j¾¯$æ×Â/›~VKãøBF×™ö' �ùt³*2­<ó§g<—ôðûi¾À{¾¼>½jÆU•Q*´\LÀã®ïØr,Ýþcó{v߈wü¾r#@ü: ÖK<Щ23 â½ò�gù~x»ŸŸÀؓݟ ±ëöñCµåˆí]½G÷XåppôØ8îø|•”øòVÒh¬E`ëµuýýÒ‰š©Ø»žÛãF:`­üy{<‚CcÕeÆú“jVöÞ„Ì©¯W`Ì–xæDʇ±Ã¦D"•Jdõy ¥3©D~üõÆlóí°ËhÔ±ãxûî¾õ$'6™b÷2,k†Q—9ú שô°]*f]Ÿãã c}½‹7u-ÈÛå=Ô³w# Õô°ž} «ªWÕ®$ÓZ•)f™±ŠaÖb–!mZSéîuB2ñ/qú:þ[øíw±Ý5Sle€0Ì÷û èö ˜ó‘)ÖqÈgdÆDèØŽq „{ñùåïÆ,Ë-~õƒT?%ûÖüåQ~ôúiÞQmnÕÊìé Aǧ?/2ÜØ‹î2ÿá™ÅñWi&‰w(÷¥Ç›cm‡_Ñ=óa+áyû£ƒc.UåîIÿí:v1õx·Ðá›;hkØYÅ;‰ã£u|åÏ/÷L hšHœ]¥Ýn¿h¦¥r0å+8OÐbŒ0{ÞÉœ÷4ü]²ûÖ¸ƒuÅâòL°ÓµcìŸÞ‰Î̺�7OÅõ¾µx9,°ò,ÎÇö¶ùVéWÌ==þ}ŒD,\æ“,3[^Ætô�ÙIö 쇞9s1|3é-g‚v‚ßïç«Ýsæ³ H ÅqMï3g{Kºo3šöï%M®þý"J›î<íýœ ]ªù=¶3 À§ä³UùB€°ëxy°>ëýbÎ×v>Éîî.<ÃH¾ï©³V}zÿɘŽQÞ£ï$SëIá)ÆÏÕÄ{ØGÕþ*_‹K-HÌìp}·îI€T{Ùç Ž/Æ!qìO³ž™»Î3miuL™9˜ŽŠYÝOëÉàn0Ñçäf 3`ϳÛ×ðKn*&ÒÚïE/îóU*i©n:¸@Ô3mª]†G—™’gÏ&ÇN?dùáLðxÊÞ>üsÌJ²áü`¿ByXùCEÕ×ö¬¿ßÎöã�T&ÉÉžèW±¥Ý`î$±‘*�‡—Û2 ½ñö¨e³yz÷;Ì'8Ͼ¯(àѶ‡Ô°Ÿì)Y°˜V“Á8Óë. ÃHz¼e)SìÁ–ÿbOQBqØþqWWþ¬ø{j|3¸”»Zx~ñ>v=¬?K2QEÿc{»ßCœÙ»’~VþÕ¼¼ t)ÆY~ý»ì9àT3«èÀŸ½_Ýë±¼»À‘³„qE™g�+˜ýƒ7hûk—é¥,ÉŒq‘L\€×ïƒI#þ)coáöwØçFc‡=\,¾©|€!6%‘QvÛŸRŠ#xl…¡4~–cI—–¨_ë|¹Ïø¸l}ÐmeÝP‰;f¡ÑQˆ+ļ´ÇδZïà×v9Ç,x³”ùJã(5ˆùc;ð|ý s¸ @I$1`b[õÊa\aÍÚÓ¶·ßF ‰­H×¹çPÓÏŠQ³l#ŠÅ[«Ž°Ác„­X<Ÿ³£�¾Ip_kŒå˜G)ćYû(‡‹ bI.�† öé1�§<aù`�2P«bÔ†À“½ha=^F¬72¡|ýàÂS˜ÞËàŽ ,¿MrΜóv\Z®’´R1}Øhî’ž‘¨ç…Î GU>u>2Äl®;0 4ÚöÖ e¸±~Ø3S s=‹ëp_-Ë©æ)WIñ¢Õgå °#é?pçÒ}G³ÒÜMõ}Uýò9½JC³Oâz_Ÿù~„wüØ?lßÏÇ8Fæé ××ÂP«Ü㋽MõÆ)J¢õ%s;»ruñZ¸J¥3¥5úþ°ÜñÊjÁ ¦ËûÏYö+H£t/­£»çæ‰ùÄúùXvì;=·ºBg¼i)Èu=þžéù1Ý£KG×í9zº¦‹Þ}ŸÀaëþÝ?²'cЖêº!γ풿ŸÇúWŒ.dŒ1nÀØ!6ð0™Wƒ¤kÔ @Xæ$w‹)öêÆï›É/‰é<¹íëm[o?oì�çÌðÅ@îIªy,½y°·ß”óíÎñ²�µÊQ®Óg�Õ=Žÿ”m…ù? /é‡Ì¶Ê&SìéÚBc\¤y¹íþcr€l(ÇÿöXl5_ŸÈÔäíÇ¥ç–å1Qвîgùï»±žV»=ºòì[î!FàQºÜ «ªu?òôu½Ôq,_w|W@h÷÷ª½ü62ïúžýüü]¹~[g‰ä!JþÒù¥“N€ÆZWR±U/cÆ ûÕ�cV*q„ãž1˜X`?®�ØÃS�ÛÐÇ?~4®c±ËnûsŒ˜ˆ×ЬiŸr¹'+%ïc^étPZSíºÈï•*ä¹0¦þ‚/ޙ䆶%•È¥«¢ä ú`È$YÖñèÒCÇ ¶‡ZÎ^Ž#ÆØé:ÚsÆX툲íVÇôÁï^²rúQ€Ž—LôG»©f½)çdÜÏt@¦Ø©uµ®Á,O |m­äÄü?®@Ôd´<œÂuÏ×ãØ_l{eïœauºý}¦WkæKç(Î;€~Ý4ú<Ø ³õ°£årf ©öð×ñžô€ìË� ´+b�Ù[y¢÷AÏ“/ÀPEYÍÀóíÃÛm¥~‚ó[û H@†1ÚÅatJÛ­’TeõSíîËy¯d"–çEþb÷û€•ÊÙ/XÀ~°Ë{°LÏÔùŠÌÚ…R¬Ÿø÷î°^±X·ùK•,¼æü=ûãŠ ÊÆa–2ùûÆ2€®ˆ¬y;þ¢­Ïß;+gÞC¹÷Bt!Ý=Ó̰<½Þwk„m(e,†œgêi€æ¾öU�[Tnð cê÷‹Ã%3`![xWH÷‡tÔzäŒYcÓU =ã*cà±qÕ±˜ïçb -æK ì†zî¯ëž ¦ûcqã�2ŸÙ{µudO�È>ÑxM• `Ò|&ÆX5®=SlÅ”›€€ÆÊ­6ÓáϘ_è ÷ÛÚr�Þ3�kÉWoL2‘ÏŠé¶êo·±¾êú®¤¢J7–?˯oÚÞYP¡™nÑáþûÓ.�¯fºå゚=’ô˜eãý},f˜ïw7`ìÉíOIÅxç)¦üV F€“×÷öY¾œ‰v±ôÕL´AÒy„û´ PMà©ÆøH»Wíë xáó2¢V¹«XX¹ß;¤‡çõ0¬}m¦ó.°=IÈŠÙ¥�?•^Œ!¦ÄÙw–R휇骘^ÿ€­úî£Ôሌ°V:Ƴ¬ ÄuÍåÿåöß_W`lŒ ô+¹”I%2 ÊÇûÃmÇpÒˆóü&vX öíáoFØUñÇ•Av‹iŒ2–Þå"JI|ÂHl±J³¼c`Y.-wÜvùÖpÝs!eŸÏâ—ÎJE½ï•çqr¸èPë2«¬áŠGþ‘~ØÖÀ ÆYŒ“1VL+ŒE“IæÌ(ÝÐq`×@œ–¤´õÙ5øÜŸ^UþpW3zœŠÚ]‡Àƾ©ë—9j c€¯é°·¿3©D›2¥,ÃÊŸïÖ:0²@þ>’ã6}u¿,#Œ—S3”ƒŒÍO/#wäÚ^bëûBé–…Ò‘ë÷x!CâŽ{ÀçA%]‰­s õ·@cfåæïó‹òRöà (C€Ì÷·ž´©-g‡ ÚYŒ»šw{…I€uŽqVëI(Åyý… ó9èŸ póÏÉ>06™4þ=IÅ`Uó­b™L¶ÈÜfR¾ÏáH,×*ϱÙ|ùlþs�–›1à­ålÚØøù¿Àü¥YY«¡­ÏÞ#ì³ÄzD¾/ï®tá½�™•NæÖûˆõVå¡élKÅÏvbRq¾<{-ñš¼©±ã  ¶ÏÝ¢ÿ{)žä*Aõ’ÍÛÖÝ¢"VÆòÕ’yüû­/çY‡+@󳄡0¦˜~bì}aÄ‘Ï0¬½–ã!ŽÓl¾Žh3 û/í×çÐÕòhŽa¤ üóªb¬ ^÷Ú~OŸå°ùÎr1f2ÎÔõØ.ÊßÁÚUµ÷¾ý¼(”y:<ÝŸåàÿ¬)�¦²ÇäzÄÆvðór‚ò…Åh€dÀ'{|‹†ÇgŠ>>ÇØa ÀòùG&‹¾ºóþ:÷Ûu÷I÷!CLÅÆSý}ChQóò×÷°ûb(-xpûŠ9… ¦Zš°+¡ÈËWµ_Œ †’†Êr«Økë:ß.øÊÛ/2È*«úá½ Æ jÙ”:$Ç»é¤@™IÇzwH)¦åyø×ÿëÿ—ûï·#¿Žß ÉÃe`!CkŒ 3̦÷-�_gÌ­‡Šy6®�Øøø—Às6°yþp€ÝøýôOÿyŒ¡^í‡áüÀy"çÍܽ0À}†Ìú¯3JZnЊx»ú°äéTŽúcù¡zt+*;8º}ÀÖµ=¥×³V{Vªˆ*ˆ4_¹}¾9 1hý)ÔC9v«+PdŒ¢êK]çÛ3g„éëóþulö»*u,çºK{ 6Ý¿4—‚·ÚgóEGÌ®KË6õQÂîyŒq~ðÌ*&1ÚéW¶cIü©qí6ò˸ðý´Sn[~é(cP­zœÀ;™\‘±åïÇ Ô³ÛÏf{"£ ¶ÈØæ: Ä`}VilyOâxÖnÖØ‚€Ëý\� g½”ó'3{ 3œ‰âóÁ ž†+_@w˜c¬ž(©Üu²vùì™;ùwó©ÒÓ³ä9Ùë”—­û ;ž™?ï˜.@… f½vÇ'þr¯ÇP/û;>Ïηëâ8býú í~ ”õ¿l|¼Âïë}¸CŒ·Ou‘•›'^]—„Y¡ŽšJì£;Ž^“ï¯N;ØrÚïµZò‘ÏÛõ‚6½° ƒêý-|%%P̯Î÷Àëíz›Œ)ì»ë^@ óaéñvñ�ÄëOŠÁcˆMCÖ쇸@´[ŠÉ›�Ùn,1^ÎJè)¶#¯¿uËb»£ÙßU¬ºïd‚=oûc,ÉÄùûdnuãÈ™�…/×}Ì¥ËJÝéuœÕÛ¶'³Wëø}¡9P"Pu½vÉ�!U£Ÿq},ÏÞxWùëòìè] ÅŸÝž6]ÏÀâŒÈ¸ÿveŒ) ,ÚÓ•öLc†iƘ/ϬÏá6Þ/û¯­ï±ØÞwÝ»ôòv©ûA¼¾c5@„öö‰_ëvŠÀL|qé¿û™_ÿ1´ªXbÿ^ísß}¼Úÿúç=ýÛÿcIÃÄvÏÿT:“¶ xÝ{Ý?ÿÓü¯_þ›eˆ+ö×M*1šgˆý€3»?™Y�û6†�Âþ‰}ü é[ l5Å›Ì0„í™ÿÓÁ˜éJÜÆ‡_o%ÚîÊÈ+ìbçf~hññpׇpcÔ±ÌØJÄŽÔÇL3=´£*“Š’8ÃÃÿŽ’Tq%xåX]AâŸÉõ¶Þ>ÿ(cëw³ÌñÖr„•ü»ðLtp©Äݘ/g „½´Ò© 9_ØÀþwŸ„$c8yÇ'®¸t_Ç–‚Ö@‡üÃé„MSý‰¿Ÿä‹¯Ž8³¨C‰Õ‡1ùìø8àä%¤3Ë“(…ˆÌ#%)‡Àè)H“)æ‰gz1` /d¦Úr`»-YdŒÌë€É€K&­¨�N›þšG^äüôçÁçåÈɘ/(a¹Òyö÷ù` /%,cÍ~×q7ÇŸªeÙzøÎõ»±ÃÔHé»{ªyù¾(Œãsò}�� �IDATú)¢ž3ÜöDhN0[ÐccIñ(a*}n‘±æÇê²åå ·paÊö½Ú¾V@³)•x4õ` ¬eÏ”¶›ï¡L*NcÞŽ]ÀËKgUß„áûg;ØÖ;ÿ½bžQk/ \ ½ @œÅy¹½¦×Ó®žª¢áýUïÝÈ›ùX‰¹(Ÿ+<¬ëü¸±õÊ0k?^€žz_ÌÚqt¸Õ�//÷ίAÞ4ð1-¦QºsŸgãcˆÝÏt›ógPv¿‹±þoòüXÓK?8ÐþÊbÛM Ì™ÙG�‰¯ê%ëöÚA¥÷&ê¿Ê‹±ÊV{vû+–^&šÜ·G(¯2SR‰÷:âðS3`¸Ç«’dìæ%-eÊ€™ôcÆÓ–ʰ_yIPÛ/‘ÉžKÑaE2“ï„3l'@XlW[~lÛ>]†$Â"Fú¶(9ºû|©íM}£¿Öý­gñ¾Wãè³ÀM¯}¾Êã÷¶ïSj·Ü_Å“[„‘Yv_¾˜ÞÚîÝǯI@@ªbría.½)©H$©%Ì2z°n>h_Œ4bÂò˜]¿9€ ]߯¾.Û?Dºî÷É s@^÷û7Æ×M*$¿MéĤ>Þ0ÖÁ\Ás¾½ð£cÂ|l0ÁzJi´J%Sî}Íú,¾Ž"Ö>UöÁ—K"x‡%~ØîÄ2Q+š«ëqe6K×n³ZË™f¦¶Ô—úôƒØ«v¹Xt ûü¢ÔcÞz¾Ç( UÅë–;¦soŒ3LG‹Éù£ŸÞ¬£ñ²Õ+”Ó}#Íö<.1žǒLd¥gÏX®e;ýì4Nå|°#Õµ¤Q×–­ø¶%À}ö!ƒ1¾jÃqrjþ~*ê‰RaȪàè±íggùûßóXp/rŒpÝ“8Ó×;2Qíñ‰ƒUÿœ 6ÍÌÓí‘•›1mPrÍ¥7èëöD€i¼ªô§¡DàÙÌ·ùøÈ­†ùý/U>ŠÑ»ÚKÅ*»wWPPÿùÂç5Þµ„d>n}™`û±â¼´l”ºÄù¦–’Eæ—_@t†ùüX¾§UR^v¨ú+÷ù¬ °=‡×4_”Úîç}Âòß•íHúùíϳ®€À,Æ›2ëZKª]14±tsa.@Âú{fS\àç·‹Ñ6Ó¹8ÌÏ¢!ËW°S>?ŸZÕŽu¬ç3Mgˆ}´3ŠÛÁœÉŒ1+ì¶Ãé¼Ïxû¬èÁ´ç¼¿ù \÷=C”Þgœéûú,Ç#H)®rhCàëRx,',‹ÔcRd{? £ÌÆkÞȘÇÝþ€×Ü’oùøPí÷bà¨q§m–Û—_ÇòÊmI òöÉZØ´Ø/3©B„f:Õ{‚¯‰íh¯ï�„vÜMÉDC ÏÃr˜ü¨4"¯w”^eõì�=™ïÆŸf0õ,·:öÜ}ÆGÂãM:Ñ—ã~éÄi½rÆØ\Ü>Ìç§îÓ{c\öòÛ4¿J@Ë…× ¸®bŒ¡õ¤$ßÖ·k?Ÿi¿À–d$6Ø]ˆ(qˆ€UÀJ™e†ö ì«rÓz| põëømŒ±b‡i¦Ø:Îax|‰Ä‹ý=œ÷ûß.Ç'61-xeˆý0L1Wž+@VJ/c+ü^o[4箘aæ÷jEÿPÖÓƾÈÏÚµ8Íì1βvÁÀK~«½ùJIíx²Žâ#¬h>¦{¡GiDt`2wû°eÒ^Þ1¤;@‹ÄJòˆÕÈ:¢.QJ3gƱT=�ÐÊž‡¯+/~ F  ½Õ38öÎ¥ë6¬²X1ü¸g¼Üé°­,sôSØÇ‹wü£ãÝÄ4š[ìçÖñÊòc€íd>2 |y˜¡àa™•™„F³ñ…�XKI1ãòq«˜O‘Qâ™vpRÌ-ûŸmgÆ Sí¦™e1VÜÆ:dYl,Œ!°ÇÁ úELŸ1í‘'zÞIö[ïiö)—2Ã>^à%Ûÿc¶ëª}ÅãÏ=Å(a%Œg».£‹d]ÀZIÜï\p`AÛ.,Ý2ÏPì}–Å ÍÞ_b}β_ Í÷$ÛŽZR˜K=Zã ÝXSŬTïk¾?«‹‹‰oÛó™çgŒ¬*÷Ï0|Ïþ|ì$À÷˜bûB.ý¶T"öÆÄë¼7ÏýåÕBd,ÎZz íLˇ€‹¥… $츎٥ÒËë©cäCùwù]-}¬v>·š/ñŒ%õÙqÑ×·ÖÜA÷yÉÉØ: K…Ô™‰™Õ…ê^a|F£Ì°áçÛ·«„â3ɼ«=|?8˜v¯ä±ß€±b†ùvYÌdèÌöä UÕ›ÁYÌ_½7ˆÈ ãLœÊ2i>|0è:øß @íg3?˜Ùùs_SÎ\þºƒ;^I7Úü²~ºúÓìgzœVóÿ+ÖÖ× ™ø¶ÉB'Kl\Ëé-}‰TŒ‰5ë—lt¡Àέ7~Ñ@…Ïqõ‹ÇÐñìN9{ýþ=\7š×û|A¥Rµ´ *Ï€tUyªëòzjà÷}̰wy^×vWŒWš*ýŠñ5cu©Ø^0ö‹¸ÎÅ�›F�,Z¾pÖe²Ñó¾Ü€°¿ÆŸã÷1Æ_c2©~ƒs'¶Ž³bhC Îø6UÇ#éØòLfØ®Tâêî^ªƒm/£Ì°¹Ÿì•§kQ"q~ŸÍ^ßÔA|y9jÇÿÅJyTŒĨãÓÁ%¾ÐaÓ“L96Ëå? sŒ9úª•;,Ÿ¹Eë¹�ÀX;Øó�ÔÀÐò¸<èùzT—éw ý`O‚KÃ×]ÇëNä(/ùì_þVã˜3Ŭû‡1Æ {1Œ1{Ü–‚»g8Îj8Œ§Á�Aß>w©¾?žÒßm¹,3gÙKÓAç)0YàÊŽ7Ä0¦‹µÆr_õÑ1s +ÄU{1 N净$\O´?žCûFfKc¥ämÿ…\×@[ö�@1cs¼’ë”1+Î'È,×RoŸ5.xÛ]ÃrÝR#�¨¥¦Ïâ:^Žø{|nØç¬Ž•ǘªÐÛaÞÅ89‡0ÑaÇG:Ÿ(à.cV*`þ2þqL‹/û,¿�{ŽóQžÅÂ!@ß÷®Ÿ]¹äoæÚ½°Å ÄÊÀ.H\À [°¨L» õŠZ¨à¯>æ%2½,#¤‚˜ÔœMç0|Ì0ËY§ 9³L3Uì¸c€eU?–^ÝŸ½Cçð b_îÞ‡Zz³[Ã]×ǘÞÀÌîs”3€¬c¯àøgýÿ¯øçc„e .k—q �°Êïö\y¼a·zÆ–WéÙr«ò/;߀¯Ëýó«÷¿)†X¯§)‡ü[tØ}dvi€ÓãG4Úôöcoa}b9Õû„'ða¢Xd.^Î[í1û¹¸*Fâj— X?“|ìõìød†}¼ž¶FO®¥ßàøO+†Ø2NW9b^9ÜÆ—M÷±Oª~Èܱ@Y4ÎÚukCÆPXøˆx, ¯~ù:oÃy/Þ»h*&ÓL´œ)¥ë·w]Í,Tšºßñëº�ceê å³ïA€ôKó:”HtÛFz­ó Öµ‡ÿÔʾ܀°_ÇdŠ-C KIZ`ìÇuÿÇíø”Jü;;¥?~ŒtuŒI$îXìÆ- … fXn÷èzà+Z”VÛ+O%’Æ[©ŽaÑ n™g*¡Eé±ÊÁË^T–4¾¨žÅùº訟+œíJç3Yym÷;wÑKa0ûc¨/—ÖŠõ˜íéÛ]µ¿Žác[QçìW6pàv:ÆË“`_HÅŠªM¶y tÉ,“[á¶eœ f•‡Í8.' âß§Äa‰Ç cáÕ‡pg_Ç�óŽbÖZÙ÷É�[Of‹9w?6Ÿ—Ï ©ji=̯–ÀÃØa8o) ÌKrž ͦžÍÓsÆ[ “3¿¸Ï™cIhU¹Æt<Îñä¶õøñ¶Äþ(. @©oñ)ГŽÅÔëyõå®ã»n%¬÷½RŠC\5àSEÆ9ñ9T HfÏ⺋a,Ãß‘93ëñDöU¹, ¹7ÿ{éÔ¸`%2Äv™]�aï  çff »¿kçò8¯OW‰bÈtŽcܱ�PµPtwä@FŸÁ†Ì®£8Ë÷[»`@sža¥FTyWyì8Yé|VÊÏßG­üáŸSûLÁpeûùsË÷„×O:øU{tGn]·ôº×óqjÝŠ ãÐÑŸµË„ìõÏ·œ.åç¿‹B×~Œž�ʬ1æØLWÃRµäc‡YúÀÎ:/2Pªöåß<FÝü?ëÞŒí¡ö¹i÷|>¼@¨²CºýôgµL°2fýr•›½WL`56øÂ:Ÿ^ÍÄâï‡Êñ?™bÖ*–çCŒæë¯ÃöÝ“òŒé#@3®[-U—½çÙùnÏv=µÕÈ÷¬JÂTYd¨õÚWQ9ÃKÇÃëôú¨áï«Å³+†2Âé6ŠëzévbÙíÙ®De%rR‰cŒ”y¥€¤_Šó(l4\ÀªöU:Ê‘Æ2»0ľ1þ2Ì/ŒyÆ0»Æ0ûf¶ûîÒûÃfN*QÅ.£Œ0¬ÒU*‘ŸY ‡A) „Œ°ùš‡+$‡~ᮘX=[¯õžQÓ•>Zí€^Ê!TÇÒBã+š£6úLK$,SÒAVú‡9FÔ =o¯¨µŸµ§’PŠí°Ç8kù§C K<•¿較“­ÄfíhÓ©�Dþâ‘; Tl‹Úí²çÀïçªá&ä鞆g@i؉K×Äß{Æ`¹§±b…{ˆíÁîwæ>`/È/�˜L hµGŒ]–È�Äóg,©£�&3S@“½~Í& �™c_>vÿÙ8B@ˆÁ Œ°vP€”šù¦®?…ó;Žw&µ†ó o÷Ø.Ü£¥ ­CÿHÎë8LlË"cì’{ŒífëÕ—ðž±9í!¶SgEemg?¼|Ê´€l¾`¥ÏwÈ%jσ3ÂvNœáýIà :v£=¿ôõ×ü}dîoŽûc•/Ô9›qòd¶Jú5«¯en²òxfÙYžÇίžß+–Ú4½PjŒèh^ï¥*fZ.]^-lA&Ð>©ûrgý˜•Cí³œŒ©ï íXËñý?­Ö U^Íóla›•ˆ® ŠÉ0œß3j¡ÄlOt[)É΂Ûn¼¾gxîéï‚lÞ×í­gtÏxóí¼òåÀÑ®{©iš—¾?öíuãèNyêtÔý›ŒkoW ë-0£âý˜ýÛníýLþ ,ûÇ}Ũ<\Æ ËÞã0ÆëèàϘ0:æ’6Óy Ï>ï³zøãÊ‘<Šã±Üv? *f´vüX‹Œ±ÏÙc2S1àéM¦Ã¯Ë�ȼ_å äÞÂ8œÖ÷Úôô齕ßAæü)•øñFΛå³é­þ[&^VþéÆ u ÇïÍ/?»Qú¸tbeDÀGI*¦òj€‹צ<ß½˜–«þù~µ$éýv\yþïe»`yºýv÷‡·—úœôá½Ì+e„UL1ü�iÔ* ÅÿÁ;ËìË-VدFÑR¶˜a�»Øßáì¹?°¿‡ócÌåƒö}ŒñÃ0þá¤Õu™uqé«á‡Ÿú}h@‰“®MŲà.¦¾K}Äh¹„†ÓÔÊξV~^ú3j:r8ðÄ_@4ì‡&ïS±É¬ñü1vwU±CT>«<>v„’‚¬í¥h¿Å³Žoí�Æþë{Ê}ëñmzÒ©€Î(8‹ó–q€LÁf5óFÕ›3:*cùQ&J%^÷Ï<’Ú·6PªÆ˜±€ þŽé8±1n²rÚ©€^ \EéF”.Tm<>q¼" Õë­á¹ëtØq ¸D¦æ_I¾À—–.´í€ý6cäU-5ûÍ—Å4¬˜h³dŒ1fc»©s[õ×.ÃÇ–ûTü¾ ŸÛkrÏ¬Š¤¨c&FIÖl¿¶9ó·J/: èâ{ƒ—ô{—’xÎË7óËr¸ôëxüžþd%H;L±Núl¥|¬çê‡{ÌÊ%‘í˯Hq&ÌŠÔ…l9“½où›Çžð•ME1>{¦>Ëò ŸJÉWßIc þ«ÖwËëq ̧gs¥:c/8‡ë|ûÌô#³ëɇ¶Æ…WÇöøò@Áª÷œ7<-Îkl¼í0ܘí,td-3™Uëè4UǪÊglI*+(>»ð™’1OX› 6.ÉÂé¨V+î£Ôcõ<aïóo¾nÇX1Åð|–Î¥t‘©öt=^1ò�±û;1ðºœÑß#Ñßtã­÷È´ö(ûã^L±x}.!‰@Ö®c?kŸ>b9zK)| ÕHF ‹¿Ž¿hÅ2CÞëíw5nl™’‰ïpÞ×pÝ£?„)ö %$=üýÆÖç¾|•ˆmÞo‹ý˜æ{1ÅœÒ@Dþ$z»[Ä/sMÅ Ãrê˜SUû¨ë¼äbÝ>˜®ÚÇrûú½{­b¶Ýg:fÛ^;Ôíæ¯ÓåŸL©»˜W£LÄý L=ü§ÛñV,2s>µ 83€W%Á8ÆãËí¿¿Æþ R‰Œ¡e+Î蚌°„ ºÿG \Ñe»ìFØÜÿÇ«t­½×ȆáJÈÆŠH½"èRe½ÛõAÜ[ ª$>²=vc)øöÅØm¸’­<»g²Áѱ�™3d1Ì0vÕjÑ™c¶¢¾ l=ü‡÷ràáycåÎ`@®(ï¼€°Øaõcth_òóŽç~ yÔ?» Gt€ †‚º®ŸëKztO˜ñ’£uhVãW•ðæž@×Ãb`)Ç92R澊}ÿ‹1Ã&3¬b U+Dý 6w¤Ÿ`9û<‘ýœ¡ ™€^2OÇJ³ù"ÃSåa¹N¦ÚÏê¥bµí•ëºyŸçêƒÐ¶ÛäNiÿ±åSé]æóÕ△ƽf´VŽøgSïuŸôÈ¿ëpÆ ›1æð8ÏwOòxoöíÌ{(ßËð1BhÚ[‚p†÷”sX `U·WìÉ“‘eÓÓpLÍ¥F‡wåˆñ `%툱9°dcˆ=‘mçNgŒLÒÙïÇòcL&Ž@Êlw›OŸù˜?×?) %ün¬çgR{t›~ÿx`Kx¼õ“Ë÷€~3có©b ­ïˆÈø±Ç‘YáªeQ’q•ÇîÇûz„vñ=i[Gù<²ùXüì÷ÕÉǦǀÉ{ÚŠá·ÚÇÞê–£ZŸÿXÌG °1«²ò�ôöÇsµ€6—朎s&ØÅ™'È€âmV²1{ÏWÀëñ ‰ßò5Py0°L°x_Pº.g)‰¼ŽGi<¸= -ù¨— ¯ñÊç—ÜúÀÏ^zk¿ê¹?OÒÐnï•Û)ד8/8§ñX¦ ¸òùóï*ìŸLʳ¤ŸFŒ%ö~Mñ}¼Aÿ}cï](•ø`ëó|ÝŸÀ:¶Ï|ÆŽóªÇkHw &øš¾÷évÝëßPòÛh Š{¤¿Vö^�@‹ùÄË­]}à%Ø0ÖØ~Ì.µõQÒ‡{ó`8Œ–¿‰T’Œ_áú¾ô¤*‡j¯À¶ÅC&UÅÌR@ÛÇÿà€›¶ðü àJ®oÆcÜbˆMC€JIÚý ýçÿ!�¶Åû¾¤‚â¼n2¿®Û#m¿`ß&Pf˜bÊ8祛+DïÝÓÂïç£8š|j…ŸV»�XLßÝ–}èò†¸BÙ®ÌFHâ<¢„š}ð²*¾\y 4ü€ÎbtøòÇ•âI,ãìâÂÖÇОYùmùFzÝIl£”cÏp…õ®köRÓåÓ¹ï8’ÐŒërT[B½t³ôEr:Ð?®û�ˆ 3L°èèä¿óXG«ÊŸ÷¯•¿à–#¥´ÐcÏcLª'w^íPå@Ü2ÛNJ ±ê}A5UŽSùÁás:±#w>2DzÀɧûÌÁv昣P1²ƒôIl±ü¬¿ÙØhÝ/·Ëwc ¥È$P»+·gK CضÏg#×,ëõø>S7OoÍW{K¢Q.…7ÞÕË«<P«êÑ_¦µJ®™1F7øâ<açXÙçzÕ3oÿyèßõB=*Ø÷àçÁ?7Õ{™Ýê3b;Øßïu¤¯˜W½¤°(iîËIËO¤ã—!0j÷_�„ùëDª^ÓII ²~³”ö}ÛÐʱý*ŸŸ}û"ÊIvÆùêGë;×׃ѵ›°7ãõ×}s‡Øë¿“”ârˆæoþýïq_²n¤“:Õøú¬-ǶÊ�Ùü䀯™zJèœ÷k/á¸�_džp&Šâi pø–8ØQòÍŽ›¾c›/®$™U=P’ƒ{1÷4C¬:Îó©y/¯âº×æõ<Ÿ7”Ücšç©'¸®Ãðƒ?ÇaƘÀäºO3?%­x± „YiħkŠs‹×›t& a(Kc‹Ùq8¥Y‘ÁˆLMÕN_0–“:‡¥î`ké>´·ëß¹ÝËÀÈy`…Å㦀—jþÀûÀ™M±<ŸãJ¯ô|L2,×ÏÊòúkiÅn»íÖcË ¤�'g(=XI"nHvc”¡U�×]Ò_èÑ `µ$§ý[k6¦˜¼H$Ns@Ù”JÄí²Éøº2Àn�Üd„�LÅËl=vް–¯H¼šŠ%fŒkFW+2»vÞtéÇ”Š#Ã¥R”­Š%ö¹uLcL‡‡ ^??\׬v„ðôÇôÃ?$ãJè•Z‡*’^ÙÖ:žP2óh€%tPáhL2&k¿]©³Ó•!#ïܼR¯¨Ï¥¹ºŽÙ*]- x¢Gu zíb­zѶû·r Ì2ÁT½m){+î§Dàj‡ œu& ¬q<?/Ò1š1)#kþ~§¢=½û”0Æ|º€³R‡ž©Íy;a{F�Ø:‚­„,2ûVÉØ}¨%r<p¥û=1_?F ©fº0‡ú9̯žñbæþ¹Ñ—ªòµy¹Õ§Hf1ÆÆ¸žå:}Ô€3¶·#}žìÆlD;•¿ÄçÆ ¡góyzo-ìs´J§÷¼S1 }KÙüžÉÖZÖ/ÏšÛñÂ1X5ÓÁ~¯W tŽPÏDvë 4ªy‚G&Ï”²êÆpbõ^µéX.±u¾÷I&¤#^3G­ñ Êe¿ƒ.�$.œ‹Æîçkø]IòçFŒA‡¥U }¬ ÃðÀ͇3ä½´á«9Ž×w,Æ‹ÌÑî ,挵ª\±_sèl2ƒ^—£·7ºïN÷_ò÷ÆŒå˜ *g¸ùM»µ%ÑÁ®&»'ë3™_…vÎÍMf ÞŽ™¶€f"PõÓ |¼…ëW{dïSó: àä  w 3`×2u"óå¾qó&¡ldúx�ë~f×®ï•?1ÿ$ÏKØOüõ90Øa@eóïŠñ§<…øåãþ΋=5™/ðõ¼˜b·qñ*êq� Øß_‹Œ·‹—œö5H5îÆë°ÐT)žöxÍywÜ,†J:vÇûÏf€òrÔ1Æzp ñôÞ›Oà.à´/ùØM—ßÇiïÅüõ5G P5[)Ðe,e”&×/Ùù£ˆ]6²{¶QK:Òã_3l +ø[�–3ÌÚïÃÆC‰DwÞd‚=|»œG™aY>(•8¯ÿaö;1Ä*Ôe:¬±$ˆtïSø3/ʽóªüÔxבWžÖ/ܼ#ølMjåµu�¢#(c(1» (åóœ÷Ž»%ÝÓËW°ÆØ|ÅuðNG€íÊkSç­ˆgª^|oì°~?äåÎ�!ož¶Ïäá5XŸçµ+ÁílccŒ1x¿díÐs˜,‰;î˜<IǦ*‡u°ZIN @³v`ír*öcy±Ÿ£´ß)M% —Ôá@‰räžÜ|5ËÁú¹o÷Å8ó û ?Ž>£©ì¯røZ¡$𲚗áµ,ÚrñyÍK¼-€“êØgõF›ÚìýÏ ”¬ãù…t⸵´fm~¡Ç³DÙºï òÖÏ…×hÅûû¢µ>½ûj¯4”æåÀ ]�€yÞµC×âyÿ²ùÛóÇÀþ›3Ú˜å�–wЯyÿœ: c;ðv>šyЗŸJéM€c:`ë…cühõ„ ©µße†p‰åØ÷ÆudUq xû¨€¥1¼tz6"Ùý´×Y@ó ÆÉx®–ÝsQImÚrå ;üxÀ…šcTãÉïkéy >‘ëc»®vxN÷/¶ïnã¿Ô�ZeKºo¶CÇòJYù=0v€+ûnË£c`<ĘxùûZæ¨÷%;Èñ… ÜóÂ,~¾ng¾6ÿ7²„8›ç'SÐÆpãïœ!fÎöºx\9Ú!žC^Íó~œ/Û[À c#Ý/Ö¹—¿g2õíó1«·–Ü‹Q´oºßu”7¦½Ý$.½Ç[3Q6ÞßÇdZM¦Ø¥¥¬ƒ¿ñ}÷Ì·UÎjÔýð¹u½ÿ}7Ö“¼XL4Ì׿§€‘.3L•d?’XÙñúú RÒ„#=¿ù¶–`äéUå®�§už·¯áüª¾ÝØt¡XŒ;u]UoÊ3Ç)€„@‰ñ…éþC¤CÏŸÇ'ðE�°°Eìã_Æ_ã8ÍíÈþ”ÒN3ƒ�� �IDAT‰VÑQ–¹íÛàrŒ°ï(2–™µosùfÀš»îö®<ì‹eŒxu‡;µcž ´ö?—®Èö£{ôV0ÆÀÊa~1Îl8‡6?ß×Ζ÷âÁXxÞùúშ3ÀJ;æ”cæ%8ÂX9U{FG®_aÈÒ³å×�- —µ¯†gû}®ßÖ[÷¥£Í;òOŸÆŽ¡å@¡µÖŠ(”T{È¥�Y~Ü” @°ôȤÚTV9êÍÚ!º+ ?º^B¹;ùÅó+ ÆXRÏ8õ̯iq‹±±ƒÅ1&¯¢"àç-G 8}¡óþ ê¯ÛY1£üõsž<&â ×E³éÛz?›r¾Àü Ú“Å\̳ÃÄ´�ÙIŒëЉÏt¨‰yÇb;äŒZ´.ãjÍ—½tµù'×ý ³A¯·ÀŒ¢ç¸œç«÷Ÿ?ã|c^ÃB—¼¿@ª§ÖüÇôTÀcÆØtöJù’ ˜ÌÊo??-3%çl ï˜fZû|bŒÝNÊqoG! k Òô6„ÑT=s¬[~®Ä12ÆbLÀìyÉ–^ñþäc#OcÒ‰¬?,·ÆÞ?"à Ís(=y†zÇödåŠÌIl¡jIWDѦ$Ï& r¯£¿úžý¬X°ª!/ïnéULïÏ[”ØÓÒzŒÆòS ’\þŠå}#éðñá[‡`§™:ì¹õXç‘Öìõ*=e è>ß\\ìÞïaÏÐÒ±‘"ƒiÖÛnY‰Y~÷Zþ¼ÅÐù9�•­c©ý>CgÕÿÙlß `jVÆ„B³L+ûo„ã:šÍg9Æ}‰Þ‡þ®3ù)ÉDc9odß½U=£yÆÑ’„Äëx?RL·Hâ€Ð. Wõ°{™•ï¤]2ë3­üñ®4¢š¾ŠçâWq¿"à¤ö{í£c}íÅ.[éªë÷ì=´ïu¬:Ú>ˆBÆW ÈB j7&˜¼h>Š1FÒùêƒÖ•L$ 1|ývÛVŒ0D!Sk™“Püø1þ~“RTÒ† €C³ùãÆÓÀœ¿îÕ| \¶qÅê¸îoPqfX3 k$üœhzzÙO?^xpåÃèl<FÎúCæK-çË%±^óÃÔ2UØg¼raù¼Cš;Æ•­ÏÏsúÂ3ÕŠp”Nâù¡äš¯_ŰÒ0/½yÜìoÌ¡lÛñ<¢4[žž2¾¢?“ˆã¹F†¥oÇþ8C``ŒSèÖ›> óƒ;–ÙùÞ»˜€^RqÏn«? Y½2ÉÓì:(¢Dá0k€êézÞóЀOŸóÚÏÛt@G¦Ë39¯cÒÏŸ›Ÿ|:È `1wr À¼%4 ‚íq‚|b¬¾À˜3Ç¢ã>J%æ@D”ädùÆ~†Ò1vdÅLsõA L0Æ´åÐÍî[ź¿¾?¾”#%–åäkãœc�vöZEígÆŸ¿µÄª:®ãªäÈØðÀ§v¨ã<ïã®cÐÀC[±˜V c+…êy’Ï»Üóa23T,­}SïgØ.c|F9BýÚU–ð¦ËAókHÈûzÆüºÊÑ<àu1{ß¼rB-Å貜QµöÅøÒóúd�Y†Ö«y/®€1¶°pI9åõFæýnŸ{¿O.ƒãíZŽåxÄýží·Ãëשü Ò±È€âŒ‹( ˆ�žf¤Ðïþ¸>AJ­xϹÚüç¼ZâÐî#@a¤œ©â@»Rk8ãk¥ Ë;†b¼õ�+Å[‰ÀK„õÛÁ;~a»êsì¯Ëöµx/¸×p¼R`û›g|ãŒL®ß’t*{¾¦X1IŸ®À—I÷Åüâ€5ÏlÜ=ÎXí壀ë¼ßDFeošŽ‘…ÆGØ:z¿È¨/‡’(ôõêyjFê5xÞd.a 4d4ñ[CîwgPdÔ©r÷L]_Ž»ÒzŸç÷5´E)�¶aŠqælWò�^Sêñ6=‹¬[`ˆM�ì×ñÛpúS�T†#Všð9>ÍK.þa“pŒ0%qHϘaÿâb›ý¸2ƺL1†ÃÚ_kf"Æ•ŽIðh»ëç2Æ"�w@¶Ú¡·‚NÇnŠ×=“+øº?n“ã(1VN&4MKõxI+éÆÜXPR}Þas.ˆö¾ûàÈ ÌÛÑ®ÀÎ_¨"ðq¹¾Tªþ=WâßÇDˆùûv<JW|ž[lÿÜ‘¦àˆ˜«º/8¢<SŒ™•l»ÙdŒŒ:&ÑãæP¿Çɘ›'�Y»d+@Yì ‘;–,#ƆÈòLLé—p}Ý.¹,g®ž‰4¤eE‹Ì0 ¸+ægâ±|/¯êYc£ˆU+F˜–ØcíÈ€ÊÜá˜3vxØyŠ*`Œšxc÷é"9$Ê R¨éD>ß{©D õZäó«,i´š!–Ç$Û7dÚô˜Ì8_iÉáUþŒá„�T%u8Èï—~„1»Îåu= ™3­Ôs¤– ÔÌ+å¸áï3zÁA·~ÖPâ.Jö˜;±–y}½9¼cyî3õž¥ë=†vÄ/k½·% 1þK.Ü£Í2°æýº8Ì'ÀûYåHDÆ.2k¹d ïÖÜ_¯% ¦òïã‹ÕRŒ¾ßÇvÎL·ïæö¯(Ç-:Žpü(λ¯tº¦ŸöH¹l÷ü+ÖÕºG½vÄY� 9¥Ìü‡#/ûؗĵýó]åy•éev–á•�$V˜gÚuÜÚž±ý •Y ·‘–÷?%µXKú|ÞÄuu{xfØ<y>;.³r?¥¿çí4Æð˜b9=¢×kÛ`ïMï·ý‹t¢eŽ‘qüÐanõ€c?N&öX¦³Ò³íc‰õîã[qüQ¾ù¨ØN~[K >н{{ºHòñú5œ×•N¼×Pzr÷¹Ø=ϧ«k*ÆXõæÉ%4§Õ€$^w(¶{Lµµ1ÄP„Œ«.Ãêgif$éù@Û/Ùþ—Á€.nà «)•¨öÇøÃV–ö}I&º}»ìû ó×ññ/ Ì�dŠy6àw¿’µÚ[R SÁyùï®Å˜Cd·œÕ®—RkñÃßoïYáçÓyº9lý‹ì }!î|Îç+©'ðc5 ãÞÛ‰¾pÛØ'0«™:óCýì^° HC9²ì}‹’uÕVYÎ [G?³s;§L¦Ë%¾ q/䬎¡4W h3`&äK¤Çc|è*l¥¿Lý‡iïþO Âž…@�2:Ru±<Ñ&`ˆÀ¸/·g´`Þ@@¡Ã/`@|d¬,Ç÷³û}m;ÒJXß¹]óÑ)¤7†¸N4ÿÌh®7-¹h3 Ö÷¯xŸ#L9<sÒ¦gó]Ï ëþ€´ž.©pÉK4Œw»oB²ÎH(>Èe³_%yçÿ;–ý®g•¨l>²Xí·¶‹í2Y0ÝþS¬ÿ¤¨b0õÙû‡LJÏ ^Çíüƒïcà|¦bžažŠõÌæ—£™ÏýõqÞÊ ÖáÊÛ%óÎéó+öžü}û ö«Ïc%ÙÞº¿[h})Ö0« %î»åBÀ²’:\¹²þ[KJç1ߘÔë—QJͧ¯ó¯Íö× \Ì›˜¶—Ãÿg¹ÙV{ôR¬ò÷IˆÖåòûѷ۹ KÝ×å ÷L“èp÷€Ùb¸½ºtàEiÍ0ògL±+CìíáÞo³÷º¹ š÷˜k°Aæ —‡«ÿàŽ£Cß2]ø¸ä±û&�þÚø~C3Ü4àÜ %2Är2ºõ»nþš±sŸ=–Àà^»èØqýYxý½ž2ofüí0Â`ãÓy ã¥ñÝùÀ€äq­°&�ýã4‹ehç dìÅÌRýܶ/7þ¼é3Ä$ºŽßÏãLª÷�|ùz, 3³öc‘ñöÀrÆöT±°0ݪyÌ·xgŠÕ -þûº1Ä*àU1ÉÔ}½×ãjDIE4Å4c¤R†­r }ü|éGjDZ1e’]bxº0Åþ¹D¡5 xE¦×ßo̰ïñüÉ ûøé°ô§YiÄCíáo—ó s¬²ß‡Nk_°š6?ôÚøüÃNÇ$È­ tÏCmþ]Iæ�š+“Ѽ?^0óné®ãÈ(@驜R‡(¡u6ÿy‡Í’&´åd@˜wäúr2ÆKeHÕã5°Â^\j4J¶Ý'5À׎ÿœˆzc l×ñ©G!º”Q’ìD÷%Ëfyûe¶ýC>øz¶ûæ÷çFºQ²KZ`°ÇÐñg3>ž]:1Ögñ¤SªnY9£%ûNá>çWÇúz m´8?o€S-¡V;Û¾;ãŠ1׬d£µ3Üç8Þ"¤˜]¾µâq¼ßؘCÛÞåxdó.JI.Ǻgâ¼ß‘Ò¼0Ç^äxðí«Æ®°^Ì0ö¡ÁEü´Š)s@¶Z/_ P•¦žQô%MOY|ªçTÍããc™ïß|~£/¡9Èñù\Ù}Î"°ßNá½�˃�ÙLU1gm5S˵”*¦1Ÿ_«÷bs¶Ç‡ÏdíQ}§Dˆêh¯g4c©U�X¢¨ÁËûž c`0€‡µJdhÏãG9Îþm\NàÀn³üÑlÌ!v­rë¬véßÿYndÄqSJ ÝürG‘h:¦ó•6ÂîÌÉn‡ =Øc¸éVÁ؆qÜtúÕcéÀ÷<òpáÀ-5d€]™bo†1–1±Æˆïl~^€kœ!²÷åš±³jôûöz+a÷48ó ë•·÷´súœ·@•g*ÝË­õéj†Økzݽ¦�¸.0¦¥ûP<»ÿiB%ˆ×«ûïß?bšéúñ¢Ç-_°y6-´�dˆé;ú¼˜c(©(뉘Lz‘·‹$&ðSßßlÜõcça¾»Æ9“o×㫟ìdùxïÆœÒ £=U?ÆÕž4`?f–òòñß-¯¨Þåï½ùK1ßEzº»oØš�Ò� D%]h®s6¬c”ξa„Q)Æ.# ¥“ü/ùýëÿû¿üÛÿøˆ1ƯI.ŒõílÚpÕßY,°&mø}dë÷«âM"™bW†Ø<žI0û¿Ÿþéá?“ê`Á©m®Vœõ?€÷�E”Õùò”û­¤Vî}-ó€‹y3ÌïÃ�%†r‡ájg\¹—Š `åQâ/_á†÷]3®Vù-°×oõ|Eÿqc¥»m?Ü;‡öíŽ;l¿¼Üû£:Æ8úygÛrÕ%aRqe>ˆ©Ä¬}X¾ž6ó}¹:üO˜ÀD&iÇÇdE*Ñ2<P±Î«¸¼=l;³öWL³•.'çf½Ç:(µ)G½·œ©ðBï[S®ú¼ˆû´¤/ýÌ/@P±½T{­…JºV3álÿœ�غúŒ²Xó\ òA Ì�á®´„ÚYаÆád¾©c¹k±¶•tânL1žc_ºOÕ¯ë1ž+ž}d|å1CC Wžá;š%ùø)öæ‰Ç8ÍÆwÖ~³œ±]ã‘§ÁÛ¿+©u9Ÿ3«þ ×cL¯Jk ;Ê~É{¨zO¯S¯j¼72b¾­ëPZ¾dŒí.´Ææy&u9ëÏÆ¦·úlO\0góëDààŽð(]þ+]¸õïîé…ˆ Û3Õº{[>6Σ{ës1¹°œoÍñ¬ìõŽ_î+ÿìŸ+ï´ ò÷ã•ö‹R2q7̰¹ïòßà’úü^©ãœ¥YÿzKÎãó‚–fTŒ3oÈ|åÇû÷Õ×÷­ô}H~½óº^=¢cþäS’÷2ÃlºØT÷•¦Ùë;þ¡UÏÈÌUÙ8´Žs-)Å}µ~ÿ˜@_”Ndû1œQôu,IÈÎ÷ÍÏêȼÛÊÞ>1R|9< SÅû*½ê÷ʺ×ïIêë¼4¢bhE—/çjG•ߴΛÌN=ï½ë‡åwåþ_ÿü¯_þí¶RšF© X!ФŽ'é)¦Y+&Yã¼V:ÿüOÿñ¿~ùoc|1@X´SŒ2´à¼W�l1Èþ.ÒÃXbØtSÌ僌/Â�ã 5]no\¢D^Û�ØÊÏ8õŸ£uc ÅõwªàÂs½çµc•ñÿ>­ü<“�v¥çü�fëY SùÎÔ­ã•I*b9Ñá…å»üUR0G¸žoÙŸ;¶òz—Ñ„±h´ã°;²^¶Î¾¿¿î1:ð“(ÄãvŸ­dg¥B‰5g\B¯j'åø|§ôºß(Y—;ˆ1Ÿ*]›Î<Ι¦±ÜØ`L›Ì‘|$Ç}=?„Á<Z®‡ûSG :EFìÆ[EKkÆyÜ_1°�Ȭñ¼8Žè̤­Tº–a˜±µÔ$͇Üù'Øã"¡h¯ëôk~öÏC=Óf÷%f3 S›Û´>CŒs:wßK"O çøUéœE½b»-æè<¿®8†’·ÈxïÇ ÃyR1v³÷&=Ç™bGx‹Œ‡|aS¾Ð r3j)oÅ´êõ¬š–3¤¦uß“3P3³rÓ@˜Êá8LëÚúAɾʰ¿çvî8þL©T}¹“âDÉE/I§˜mQ*/cÞØvD©Ãj¡ ³µ~¼êÇx¾ßj`0þ~¹îóØV2+r*™íļæ-uïïÓøÑ*»tÁþ¼å FJÕÔ{ „%-è�ƒsHwÏcp‡QÍx�ÎôŸÝ–ß7[¯¼ @ŸJEÞvßXüÈz”=6”jóªêºØj캵Ÿ´á®ô"cš= ^Ïì¹ñײŸ)µØúZiAÖž lFÑq>¥ßByÌþGÄñvYýÑÎ+Š1©û#‹Œ¦½y#2§í1‹lþ¹q1Q ð~Æ%ÆÎâõ{/êÕgdU׫g÷µóW¾€“ªO?œŠMæËõuóº\\ÛÖ“Kuêú¥ó½a` ñ;Ù5Ói0·”d¡È*¦Ùd°©zT€š³/ã׫Dâ´Å ›±Å~»Q’†^r12ÃÐL,±æwÃsÌ1Â,sŒ±1ÆøFb‹ñ|£±­×ÄE?âJÇ[©vƒF>hö@t.ýtj‡—?®ZI3Lü ü€ž \òª6&}kW`r`ʧÀïP:ÃõtƼdc¬·ßçÒV+öA%åë«'<æÔŽà‘o/tÔ`ì»=[½W19vcÓ ‘ZdJÕ¹y›ŒÄK9‹+†Ù‹c,Ùto[ˆcDévñ/î@ðú°}%måkéË•¹îY½kGÿKØ*À¥ª¦«˜b³d8ê¦?ÆÐÀ–Îs-‘aÏ›û¶ÜZ²LÇèË.ØR#Úaôâ}=A{cº¬^8>¨šé+Ç–«ç`w¨'©Rœ÷á·ÉcpeÅ„¶€Å±„òú®»Ôc©·=_+ÉAÀíKîIiųUlPÛƒ½çïQž¿Ë´äúÕþ1»ïf|ÜøX\Góü«$ ñ½Ê—£’¦½XAÚù¿²–ú9Œ˜îÜ[LÁì¼Ï›{ïÜX0è æõ%�ñº#ýÎ[çe:l|h¦fœŸwG ô Ïc}'N•e(>™ã¬Ü `ò€aî˜e¿c¾ÞøÌmÝ3» ½ý¬hd]ñÜ<×ýzì¦ÀŸ€Ó¿g*=‰D.ñöFFXöþ•åǤov•RD`€I¯U „lù_Éñ阯�*/å«®«ÃüýÊ×óçÀ¼ë>F©Cµ×¸~Õ×_Ï% ßÂ~•Þ½KÁ¹! óí™j°Švh¥cÍö'lÇÕ#™õ?ËœƒSBQI%šô0öäbˆÕ·Ýñ_¯ã¼K‰µS-•¨öwC¶*æÞ>o "Dâøkñ»ÒÛ[øñ.ÓS×!ð£b€ååøz¦ò7JÝœù¶ÆW`í¶T;4mJ nü®b|¡Q Äy¼`U[š7v™:ï‹Û›Œ°iȨúÛÉÈnÿpý01Ãöñc,†‰5fª1®ûöº;ŒcøÀ˜Ç;åÖ+Õ‡m\Ñ5Æ~wÞÞjCéÂ~Ôš/—Ú˜ûq¥c1ÇÈq а¿¹vèX½þŠeq)‡w¨³ØM>w¿ÒnJZánÆ´òùw_LzRV»12º1¿öËõó$èxúÓ?÷4P”Õ;;RµŒ}¾¹}'3ÌH#¢£MIh*`jæwaN½ˆ³b9Scº tb–ž73¬cVZ‘3•1ì8®ê1Üõi}?^J`íeŒ1®÷Ã�eãzÜmÝõ»’ж^KúÑ3ü²˜|™c"ƒŸñ>àBƒKê>¶ØË8ÉúõbÌ È„Ô¼ÃÕãã%n ‹1/Y¹iùaÜ3øI1‰Uû`9ð|n÷I#ªv¨Ý˜J‚˜KúÝo½ìóÕ3Ë#3œ-<°÷?_�ÄÜë~­˜FÓªq?û©O6ÖžgåLf”NÅ>2qì|ÊçåSëɘÀx>ûœö+ø+ñX_^äíž3lvm¾Ï.Iõá5I‘•Oìo0Âx>+Ös—îËxÿ×w¾7gcÏEÇ7ÚãÍá]1±}g½9ÓkI5f킱šÇíúµ “Íç¯I:äÍ—˜v™Lö|»Rx÷<’K¬¿’|ì盯üî§ãË³Ê Lñüh9ð=Ï°ÏæI»Eàk°}‘?&±ÅÔóbŽ+߯1†Ø«|O›ÀœOÿpè”äbœ‰' 7F‡¹ã߯”ïî|¿òÏ8˜Ú3E3iT:ÝžsFßÚŽv_U¯˜ï¾MéD_>>3¼]ûÝ[¸nY¶0I{µ'/ @š¿¿Ýöy >Úë 6ÞGdB®öðûWžUC`Œ¡±÷¤Èp{½1ázŠX[pÀïP¤Úzütô½JjK)j©@>îú�Œ’¸ì2¡Ô爵(S@Æ~ó€Ö×ÁÄZ:ñ�׫rÏöË%$¿ÊùP?Šß[óV SR‡ô<˜mÅô"åS×¹t+`lÆ8Ã󾌿Ɵãû¸0Ãf ±ßÝv™b†M`ìûXÀ”)æª?Bz߯Œ°ß×–æÃ¤Q:ñǨí»)ï4$:5T¼6¯y9w*Öµý ‰BŸÅÓ9<¥gåþ¦DåCIâJå‹ËÉ™�$K*{q·+¡3 lþŽ’ÅìÊ6gS^_Ÿ,[±ÊÜ9CF1_Öõ<·!Žô˜†];Çg.Å¥ÓQõÎÓ݃a/攎ÜkëØž@íÚáž;عtá)0£üxPí‚ý-J‡Îó"“‹•cŒ³Iµbf²ô,ó®ç0Žõ뜖2ºž®¿?5Ïø2 ²™ÞËí<Ò¾.ýŒr$�álÉçÁÇe0²Qv¹¿Ê^ _⇚lm;fóõÙ�`—ùŸ+/òy9psP9êg;«t©£b†!àË,[ÉŒ±žâ|ÁŸ—´µöGÙ/6wß÷Ùž¤®Êÿ^‹Ò…*6ÝIÌ''ÇüÎsÊk´�¬«0V+_2†~¿PRŠ0¯™ò«ýð¸_8󭤵|z÷÷ÀÞ$õfï™ »î<ÀÎÍzè|î*Çü>ºCb~™¼ò”bùÎp}´ê¹Ÿ÷%B>%Ñj³ýìõÆ;ÃñUþN9 öé°þçÙ}\àˆ¼©vW¦�ÎCGòrL¯ûù¸»ßÃàpW=0Ôåfôša²îWŒC»c¾‡D û¾óvý}ao:ï0˜ÀÔz½îLñÌmSªn2Äù‚�+×›HW—Ÿo™eù>ŽÖwƨF`ÍLÉ¡ò}fË+½nSþûç³úx`·'½Èö}ÿéK¾Ùqg+^äŒpê~dýbIp~}'ŸR)EÞÞ°±Ñ2¦›od¬òÒq6-Öê>€ô½Ø·5ÎJ‚1Äöá1Œ¡åÛ'–¯b¾í26+©À¼Üñü®Gœ3Lw¥UL±šq†ýq¸ëûõVÌ7Å€p¾JoÖC•ŸVøû4 ¡Ä¡ÈP¦˜gS±Ê”5ΧÀœeˆ]�° ‘ÇCIÃW�ì[Lœ�×<þwwÝú½ŠeÆ0+•øûã›ù=KoÅ*CæV¾2^4Úø=ÆGg%^žî}®ã0̹;¸b9ží?ÕJ7k]¦‚g´¼BFÅæ8—íëƒCŒ:D™Cø(ÏmÆ QÒzñü¸o^÷:ûŸ‘^ºç�²Ý˜X©Êßs¼ÚðÞÔ>gHe@“öAÇs×nîõ+#ä¹@ÀÊR÷\‘‘tq¬¿\ŠpØ~΀‡)YجfЉ“µÃŽæú1Źí3üNt¼á¼r§[…�^/p|îS‰Dà {aÇ= `ÌüžšýpYóÀ”(‹ÌÍ*6/ëûR§W¿—òG E1Ùóeöÿ�Ê À~)šy¿gÏÆ í¾*`oŒÔw˜Ñ6ýx÷'c­'e[K'V5ÔP\'ÿxü¾'¤Š%¨¥}ç|ý²õ>0F\è3-cžy|ÍÓ˜;’vdŽö^€å³ ¶FmÖ.È$;p—mÙsË2•|4ãŽ1G¸jÐ_^�Ù”DbÞÂ]&L]'™8¿Œ1,uêÍïç¼>¶gt-˼Ä%`ž‰9ûËJûÓ<˜’Žt¼,¦U.‰Î¾/'à ÛùÉmWHŠ™ÜSÆðÀXGŠKÉù‘ÐugFG÷¥Þoá¾ç1áîç—ð‘uOº¶¼n|yÙûÒ‰YãÇÑ«œoÕü™9êoŒ“ëŒðxÌTŒ!UŽ(z¸Ž¯hÍ|íù‘ys«Ö¬†�� �IDATpÇ3éÈŠÙ“¿ß!ÑoÅìÄvEÆÐn,&–N~|¯ÇÖþ=oa»1ÀbþØÛû�” (˜õ‰¿W@•ߟ€‘¨-P[Ƭ~�[Ðã³Û¦å{x4[dXÎ-k÷·Æ<’-0Œ ±ÈdÍLKjVL$oµô æ£Ûùò<Ò³îµwÙO9£m«Úëkx“írù“þ´×O“N¥%Ñøü׿÷{Ì©}[` pBÖúÅðúGvJŸH'ºò(iÅÉðRé�Ö±ÍÆ—bÞ~%1æ1€iKßÌ>žÙþ=“4üX�UϾA ±Õ„ c6bcd~¸’–¾p&1ÄW†K0ܯT;WpçŒe±Þ¸ò³ïøy*ζnJ’2[ùÈ6Vˆwh¢£þD¶–ÏÃ\gù¡yqå`^§¯ÏmtU¿UøÊq•;Èîµ<ͱ ! p¥c´ôJÃ/y}'óá”üZçŒ�r§þÈhªòõR&/²2IÃyýrdûñeóßcV))3Í cØ–ÑÅ™6ÞŠÒ{ ¸¨?6½5Þ¼TàñêÀîÌž&ŸDÐ22¼Ìñ!z�dŽæÓ]ù›vÁüˆä¢¿Óbï=¥Ž‘JÂÌ–³ÔxŸçüo À‡é@û›rræãqÔ±Æø‡ÜÉŸ „Ùû€çOFZÖ.1„☓!w cZãÒ_³¾øœ±-MÃÝý¨=ËÓ‰OÃûž_Ÿå X ÓSÌU{›§‘©ç÷¢£™ìÊ<  ü”eü>°§=ö/Ÿß™:§­ö|”¤®ä>&qçËßï;6ýöÃ%Ëïá,½ÕÎô8šÜê»hÊ 1ß/ð{!û>Qï�²1Œùû²¿Î~°R®ïµ01­Ã;–ø÷§b9P¤Ù™ÿóà÷Õy¹Ä}fœñy¦Ï‹þBP¾üþëqÅ{¦^Ÿ„ß{3ü¾dbe_ŠýØžl|(wí:/ù Ð¥ö៷k,±[þf?cÊ ƒmÃJò1¶{~L ,JÒqOñ”T±]ÎôýÊ–¾0_ŒIña;¨öcéÔÒ‰=†•.WUNlçÏFWSO´×ò=ëãû¦ÿ*®÷±è˜¤¦¿¿¯·qw闯пêöÈúË×Q÷/åÇz^@ØÜÿÐ />Ã#€VñÓ.íÁ¤ìvŒiÀ© 8äË×oÉ^ÇÔ“¤Z>x1 ˬ]Þ% äÓë×kW¢5¯O±^*6X·ýx»Äz>ZiÏœô ±4f—Ùþb·Uúæ:šþÌæï@CûK_¥7 iFËû3üÊb†©ýW˜•J$1À¾ jÈ8«lo? �æ 2(÷Š9V‰½Ñ•ƒ¸âqÛÔÝ~,1þ½+I‚åéJGªØÖ؃jM+\[> –­�ïPz‘ç³ãëHÄ¡¤rT2€Ý5êëmI%]º,¶@—)7®íÉ™KBÌ^Ÿ­x~¦G±¼÷1Ãôç`s¯¦{±oT¾G9ßhcýJºƒ?âŠø1Æ9ÒŸ'&ÓD1­|Œ"›¿ïJzËK*v2[Nð;k;?°XJs›¯¸SŽêÅä°í•µïs”@œöp @Yy¹ôqlW—®ÙN@ÍýŽ1ÉÃ~÷ó+2¯ú ž hy#Jú}Ý?|ºÃ¤‹ýÜžg%ì:’'«_ùþh™bØ~èø¯òcÄ;EbZ PßG͈Æöâç¨-Ö®:â¯Üræ€xí6Ìm—¹‹v4ÏK_dæ1:ÇPýøï5ÈÂz†â ÁÞBy½bÊÖ  ¸›çã8Øa¬D¦jÒÙuÖÍŤ۪¥žîu/B‰¹ŸKL—cWz°eJA#ýnò Ñ<`u¯äÞë-lÇ8³dÌÕJq\!Î0R„1ÖŸÀ Ë™+?¬ÿ¦²q­Æ3µÐ¶‹Ù!�G··ã÷JÁ)@”Ø>0ÌW°ïñ2C椖2¥Ì,ÙN‘“ÊÞoÁÄbÃ]ë1¨„Éñ§ÁåÈÖKË‘2«üw?gú ó(ct0E*å.ïA3ý⸷7±aiÖeˆ)€îgÙcsÄepEÞ"à†Ì%¶p‡WŒ+lŸlÄ€ß߯¿O†XÍ ¢óÄÀ>êöðõTý«Ãˆ²í5^B²ª—^ ŒÄ½¥@u{ò•óÇ2ãýù+l±|_Ûé©zîÅ«¬–ž¬WÝ7Ãûê§Ê¡À<Õþ±Þ= ²Èý"ö» /eŽ)6 ¦Ù®!�GÊ›cJ2ÆWFØ_·íÆ2Æ–ŽÕõÇhú#ÿýÊ3ûÔR ÅÉ Kìûõ<•®ßŸ+æ”}a)Bòë0�îï‹éáéÙA¼è×õéÿš½ª�Õšu¬¢tgžìYdXiÇþüðcËŠá…ŽëÞa–,GQfQìÚè¨E�Íž 3VcæX8ßtøKn\í®üç02g¶ðíÜë‹ë±ò×±Ö¢±q± ËŘu±Þ¹£qJ'®v@`J]w©¥—˜³ÏJRbÖ·*Ÿo™Sš‹-eëiÛÍÚZ9Ž@^‹!‡ÀJ!ŽÑ`4üœãU>»ŒžÅ ñL ü=¯—v$�W” µ€Ùdº•ÌIbp[ãvÕ ½ª5¼Tâb–z`Oò¡ãE@•š§Ú™aþ½h—)¥yKÅ3÷¢9p}¿wm-ท+†åBÀ¾Âl}ìó|ž‰÷‘Í_gÓ“3�À^ÇÏëì}ƒÛÙ½WÙ#sÁbˆ¡!Àhbñ=G]w1»P ™; ˜œŸFö¼âÿ~|h¤ÐKQu·õ¹ß:_}¥ßM ¸Š�Ѹ¶KÏâ:[ŒÉcòª÷fÆÓõÀv[ư|<L;ørÖ€Þ0ìuú>ÆöØY gË7÷ŸÇ&? èÆë{Ž#\Ÿ±Äî]2̵hùñ{€Þ¬=ªØzcp‰¿å€Eæ“Ƙ„«íoá.<Äþ™I vb ñ{…£{ã 5ƒçU¿X ðv¼µ'Ÿ÷Öy•1ÀÁÆj²Ç5“)ßáú\ÚlŸá‚én¦¨cEñ|*Àx 5*fâ$xåó? Æb©vʤçñ÷¡ÇãóµÄ& €=<š-aŒÑò]ÆÕÁÕo‡IhÓŒš5=N )o$¾ÏÛû¶«\ Zæù?‚db úØS‘åcH) ék d)ÆÚnì,<ž3/HêJ ®óM­î?«l(ÝíŸ5ïw^“QÕ•…4a›,MäÿKó¼n>´¼_Æ_×ÿ~€ú­š•´±Áæ>J&šë¾…ó}ºòø•ùõíã_nRö¸ê- Ž@Hú"ÒX™¿àôP•K¨^é›Yƒï½XW1ôÀ;CÃJ•eÀ KÇ:01Èùr´¨Øgù!Š{þ…I9`|LÛ:ü¥§oÝ»áÚñ…¶Ûª§w\î»iò5ÿùº9fè`¿¹¥fµ£9Ï•×w9XýJþv{>�@-Op>R¾_/i,ÆdŒ›\*tÖ×÷¯Õïã}˘VâÐ^µ˜C/¡_³z°»‹L#[ã³8ogöÅño¶F¢ðsý¸o-¨c‘=tà#ŒK©#Æ‚\1ù<ðêÛ±†é|ý¢äâÚ猓XMCǨbn±óWª«<þù…@±Þ±y2Æ|y;w«ÃøªÝ…|$hØSq5?k(ÁŠ¥ëå#ìÜ LðVbŒ¯ èG�-“ œ9X�ÉÆìDÇ:ËÏný8@†o‰™#3.R€wôŸ“ôpáçs=ïeïKšÉƒ¦cÌúZ 8‚1‹xì¬}Çù,Ï™ÍKÆLK´µÆÅG=Då ÏóÌ&ûÝTÝ?VÞ{¤ê.ýë,ç}|I"1Œ•´ –[—Ö{æ¿ÚÍk™2‡-喇ßGl~9\Ëù³€ŸCsdhÆÇ5vUøE÷ÃlÿÐtà÷ÜŽÚ^a¼¾ÊçϬ=re’óŒ1]J÷äUq|œoÀÀó¸H%²rdÒƒÈÜRL.=—ÈÓ1¿æù¯eúÌÁ¯Í××Î °.Ú“´µž;^ÛrÈ+à íÎÇtöòÕŒ´ûê¡Û!¶0›ÏY?AÆ¢e*­ß_o€¥•æì3à^]z @Šž³ÆBLY?ÖræøÀ>ÞÊôò�V²ÀY}3§_v¼k×Ë3mcJ„ÔoW9Þܯu9g> �›[Åèz…ßwtðúï?á{ùj@ÏïW¶Ï@«Žÿ{IîYlŠ, “kÚ”<¬˜]&¶×?`_Y÷wÅTSRŽ4fؽå¸Ä»0¥þ¿1~5 1&ˆ’‡+†Ød„- ërÝ<þ‡=þ¡ci#ŒcL`ìÊû6FÉ<³åºsJ;ŒîK»ŸÖï¨M¯LˬLòæžüÇðZZòÁ;Ì× \î¸WûùÀÚõ†¢¼±ŽO[¾ÌáÓ÷Ž£å:Âñsø ·Wk›b)æ˜wtwûýñ昋¿déh&W㫟Î.Ãf÷,îÂöè´ãåÃrcŒqºî¿<ÜÇ€#¤Ê‘ï/Z2Ñ–7Ï:ÿl<ÙXPÖá¿FU2ð ›k­ d+`žÏÚÑN$NÞ1KîÚ½±éº¦ %Z³îj¼V1²Ø¾í«¨hU3v×év?±ö\:ðæ9�h©GäÆÒyÆÚêDû˜I–‘FÛecÜ玜CçÍœ»…_èqew¹Û7Ò«,6}†\ö^¥yc :4û~s–¿GÆúÌßð|–^<ñräw6k/5ǦŽd%Ÿõ{MGQ –ŠãOnÅDãèL¯X ¦U»ßåÅêGYÂÜ´dd:2ÚßEÑÑæßƒÙw›‡c»�K‹¯ùe”z\ù1G7ˇõÓ)ÀÆÌþ®˜=`´í?Ë‹éÍñ`6ßžg˜_ºJ$h¯âè«øu/†ØãµžoM@©Š0SÏÏrÒë«ö‰¿«/‡³ì×Ö³éõ&8MAÈ8ÌÒ·š:Ï×­b«jÌöâã§ž!3`à-¤“ÛÛð�2ÅúÀ‡blçó²’ZCæËcÓãòóú^´û^„$fÜÑÜ-w?Ÿ}³À–ò\�*w™è çÏúc¬º7s?=§Ó·Œ°¯ðûÚ בò9`Œdküñt|}Go¼O{@ȸí3fžJ§—š9–[”Òëæã²þ¼í11άÂr²öÊ®Ãók€‰·_ ¤ùy™lï7@¯çóÿ>³Ç:ûº9í3º†í%[My'pÕ•@2±¿0½ ¨µb‘ -qèòåN€²*}w¾ü¾Œ;l2Åþºýö'•œ�ØÜ±¿þ� lžïc3fØÃÀr�™®Œô¡än±ÃPñã_Z1Ȧe8oò"¢$7>øî“>‰± üv7ýŠ¬Ë± „ñf;lÙ‡›5î(ŸR8+†XoåË* g”ÕkzwòÉ^(©ÃW~ëò_®óAzãL,½££rU¾„òÚmmœµÛ{ãgëiëzNÏU{ú$“a`|åv§&®_<DG?wãçC¯ŒG 7kVzî¹qœ2!=S K§rû[Š•>d€DÀ䌂Lè’=9¦•;ß0®zârÝÞ·+¸Ï @©Ç‰ý^ÚúW%e·˜ZƒÿY\9çµ 0––&½Hg 0Ø]\žáϹD|vÛ“)Ž?^n[?N×rؾÞSª®åø¦é²zž�üyÆœÜo„õ˜ó}iÇ|„–R™æLÏÔPR—±dL­bd¯ë4³×憱3;ÒsX>›O¶€h ×âø¶óÃé-ÉDõ¦ß„*¼þQÊoŒ!>w÷íÞXzµ›™B~Èk'©•¤ú9€‰ok›—L)@ØyÁ@1=üÎÁç+·fˆiàªÊ×¶kNÎÅs0¼þö}ùw{�=¸_CAÆÜ4# Jˆ/æ~€½WqOË´³Û*`vŒÈL™i”fã%:¸qÓ6Žô¹ucÌ|ÔJ&]ãL•èW’‡¹i‰½¹ÍÓÕÏ3zmJrî zJ(êZu{ôìçJ/*éÇJz.3 hi†%2‡Ü¯¤ýu¯×ü`=¯÷@œ¶ |=1ޯ̯ܼu$?t¢±‡ÕÿQ:»È ¬�=køáLÑõ{Ï&ð:ËÓ“ý¼ñžý˜c]C�(¬ª˜UÐÕEÆÛ¯+9% «ëª7äûaØBà®w^?~^W2òZn²š¿7¤Èr1Ä6$ÿÑ9nÊEºC­e_Æ é×Ûö·ñû¸Ä«˜[߇—(œÀ×p[w=`?ÆÈ~'éO)Ä™þ(O`š=üív^fX‹Áh·\' ѹéÞ ºJ|ê Û]Ó+ÏÔ¾?Ú—B‰Ž… `Bdzý€´±]üù§òÃËé?hq¥#g¸°úsÇUdXaz™äVt¨x�ìÜpt)‡‘—°[宼ó:ïPºVTUzLj-;>ä>ϯ^ù®÷½Vð�·^©ÝlY„Z>´£þyŒq~ð̾þJÿéÀ÷égŠì42£C=èØWRpìÚòL @3ƒ°\ÈŒäåéØ3½;s¿ŠÆ­ŠøeÛËïù­>úé-†Ë`9‰ùƒ3¹l*ž¨nxíqÛ.|ÞõדùšÍ¯(í9c†½\®SèOyì>Æ cçÝzšÊek¡ñâ^éÀx1¦ ¶¿k÷^܆r&Y 4éXbOE:~a Þ·U®. pY ³bèU�œb/BG>:ÐsÉNŒë¯Í>vûƒ 8ð¡% Q™ ’DŸùßgÈ;‡_ºõ÷¦¥ÕÝ¿#–æ‹À`d`¡='é,é?½ ¿/±Á,/…öJ:`eåÅqà%!}ùí~Æ0cnë'×®ë~!n÷µÃ^3å°]ø¾2îðy-ö+éD£E1yýÕBÒ˜»bº©öTVI9Ö±ÐÔw52;fÊϰ¯ÞëçYªO©Äa¶`ØùþR©`DÀ {BI<S-»%ñ¢­ûÀñÅÔ\ãzÇj�j/ŘÞ^L¶¾ù~·�,Ÿ_`ãåÖ1Åò'뼯ÀB@ªn—0ó3ÃìOLZ°b8z|Æ{ƒóVË' ïCÌ”Ã0Å83LIWÖ1È.öNö9�·kЭÎËʵgµ¾Ñ_µ¡´`µDC=y*&WOÂpßr†VÌÿ³œê®4$_h£Ä Ü)ÉÂÝ¥l @Ã|ªzƈR‡ pULŸ=†ù|Vr±¬UR@ŒQ¿Þöþ”WÛëP%ÍùP5F”jÌòµùÛãßÈ9 H[Ý4jX_¬µ–’|ØõVœ}v¥çžrxfýµ«öì¾Ã c#x;À bö‹+ç/©z‡¥ý=Öô­ª2\ìñŽÃRt(5Äy¼]1Húú=cRÔý¦’zÙvH]òù\ ¼Øï»ƒÜáZgÒ€¾•ý]¥LúÛŽöÍ>êû±#I§Îc1—`Ê?¼—Ôé–qƒ-ê¯gÀÅ,‘•PÌ�,ؽô|9V 2LtÜ;^*Ñã„!Æ­%lè~0Åv™’1–:UÍžFì_(©[ʧ‹ ©1â‡%›'Ï‹î8)Ó]éx õáçÕ’¼îyñ@…Š%¸iƒÊ2‘×^m‘ÿ¸Û£mU±ìêñyÛ{Ï«ß*0æ!9ÚyKã@W87Ÿ/VRÚqk~åÏÈl´éd’3‡§ácjæ•>ï‘IÅLóççŠa…Ì{f™2*pû¬HèÌ·•5¯vn-ài,$ôíd%/ù{‡±f|¡´Ûñ¶Ùö$ÕB´ùûúíÌ?ÆZòßPE;ºqñzÝßQöxú;—I%¢Ä!î3‰Êz!%Ÿ—êïÞ zRçqS’rÑQÎçû})CnS2q2Ûúßÿ>†æûš�`Š¡5’ýåØÖ%D jni¾zJÞŽå|ÞÞa¹J©3J2Òšíj^PÌ» ˜Ž†Ï=¯íØz»Žp]»_AÀoîg¥ £Tc_ÂòrÝ+ìÎX ±ÎýÁ~4÷‡î_¼"³l¶KVëÀŸL±ç[Ьåj?šzo²å™÷cÞO%1ÊÚ÷Rnj¢dœ—€ìÙ*ïÇËvciU9úý·ô×Ìø8ïKüà:¼ðU’ˆU¹½þ]ùZ¿÷­÷¦¥óËß”êrÞÛöÛF™b*ÆZWb±aÿøÌyÄ)àkž§˜f_Æ¿‰Œ'ö̾ûKXÎC3×ÑØb—*zéÄÉûv•Hü6êd=;Çù´Ï®M΀¾daÎÐÚ]ɇÖ"·ÛýÏtü°Ã|—åâ(7W0w¥ËzK”ôÁécþúÃÃã W+R‡s±ròri9ªõšG€YÓ™8„±³Å(ýÉËq¯Uéìçǹ7ýˆcÃÇôPÒ–Öz+à—!£@®Ƥ×Nd?sLÍ-ÆÐ9FëGxœ’x#üÂê‡Ì x¿“ðt?:–ObXÞkÎ]€`/R^°{¼È¹-™¨™ˆhƒ÷s6 +Ç2rÕuU:“ÑæëQ3M,àŠ EÖX6nl,Wä ±K–»÷ïæë½÷Ø»gyö€ÕúíŒÏ×ÇÛ¸­²*GϰÉbZ=&à€H”hõ ø¾MG½uÄ/†ØYÎûØ®–¹¸€Qm¨a?åÏ_N›ÿÜN@£·~Üä’·ë|½€*¶Ë÷,Þ¹DVŸåmSÁ"äxo~™”f¯|ô{/%5OÍöÏ×Ác-[h¶$/«ñ½Œ)QØZc?˜ýØö§ì{'ÿ9Ã{¼V€PûJâŽûšÉõ<Øw#öóØR˜¬cŠy †s³¢›«çøªŒ=†æ~Èæëf˃R‰ñ»3±þJZÎÆBâíy(¿ûÝ0ÞƸI)>^gƬÊö·v<„~Y}ç³-0^†½£0Ƙ‡ža¦ës1åºßï”3–re}¼«ï³Œ®hí-±ÓPzQGå|NÒcíÓ‘èc ¯™ïß1ÆÖ,ßÓð@ç§Ùw<:Þ߇É‘(qþˆínÇG§Ÿ $¥jïçÀ®=ÊçFÈ~-ö—Õ3oýk´wØ~5�¡=cqåR†5¦�JŸÎ½ö¾y¥wÑn=cy*`“ša÷Y&®*/©…€RC2q°ëÈù÷2»º×+éÇa›ßi̲i_Æ_ãÏñ}°b Ë€¯o·m”JîüÅK€«‡Àìš@H'N�쇑H¬¤°_h[+×tÊesŸÔÐ�BÌuïJ»Ÿ®r³ ”,a+¢:Œ« ˜ñÀ–*:U=2GM1ìþ4ëh:“•Öüƒ¥ÕJô³L/[qÏ?Ç­eÞtcѸƒq·—¡4âJ'wñîççiûŒ~ßÎ.Yf¡9c%Ë…3b޾_`L$륂lbLˆTR‡Ø_hñ¿ò­Jw~¶N¸b2¬N²$ÝžÖ…wòQYÃ.¦˜_zåÄ}g\tWÄN óyðVâ5ãxöÛ X@�½wN¤g>XÎü9±·2X2“ c4ûàÕ÷Ç¢bÖùðTLL•WhkÿmjÐVÏ)”¼õ€I¶¬¨·Â˜÷+Å8ZÛµ€‡2 †Xn`Çü±œ{@Ð9-×øØ$^?¿,Ièþ<Êíû«ôxÏ‚÷ÌÿçÿþÿÏ÷ÿ#no–#9Oå{ ý5+­Í×oëœÆc<@>ó»©Á óý :º};wܤ>½s)SˆÀï„Z.¦3¥Ð<À…Ì5¾ctY`ïRï<FÖcÓ!°­÷fcZ\ˆw2sf%‹¥Æ ÃÕ@XÏá¯1~‡û¼|ÄÄØg=‹÷ë>©uå`µ€A¾ /Eôy€±ÁÌ à®»Î:6“:îW#ñÈ¡Cú¼] œ›HK ¸°ý·®_XÀ?Æ„ëÇ ´õصÏ2¨ÐÞÚý;Æ”²×g€Ô^úq\>Ãñÿ··×n$É™†Sã´Hê¦^o™svÇÞË{vÎé1æÂDRmé3Èd�IõóÁP©ŠUùW™UYˆŒ�k_Å d’š£q=³\Qe•¯«|d[Àä}Ü£(™ØQ¤¸ï»Xb ûçBl¿ùBòܾI�no ³p×˜Š¦ ®ûVõŸo°]Æß‹?¶c|©|�Ûm·g™[¼þ±üŠ9‡†@a7¿þR˜[yðºn:»íDÓ7Ì/e» ¯§a•táX@—b´QéGŒu¾_ƯcE7�ìWókÆüŠ±Ã–T"h&+ÌI*~Æôî[„±�¸ŽDbf³±Û $AËeÒ’þ¸Yÿ“*³È(É24ý¡]i¿óiZ¼ "ë%3©DïØŽkÍÑAï'‘YÆÊÅVÊV”âÒŽ1}æ¨g÷‘1}¢­û—M”R~-Át‚rt‹½˜*»£¡>¿çøº´¯1´ú¹°üPzëIŽÜK”`Ë&Ø_w,¯qˆÀcJ"Àb¼ùq~¢ãƒ~Ådô’YñÙë`ÁŸ\ríçYÎ;gׂ{Š/¥Òs¿8†Ù6˜bZzU1 UkØóÏô ]³ÈÐR-ä-Æ<ÓŒ³Ì"�·Þ³Q<ÆpwÂJKÚöê,4¹„… ȯc“Ô-ÀŒKÚ>/°‹�¬ß>k±=â/Ìôúo|^-{½z£ä kA~|�� �IDATû­+ídç7—¤œŽ3¦XœMF©9_¾Kpðöé|Ê–oŽßÉ£iö³õæ¸<†ç{Ï*@E[»­ë†¸„~ГL<”zåwùàwR²°pÖ[1^´„]p-·"¦¿¬ã˜‹µÇ˜[l]�–—{@ý`ò ³vð�ÜZà0]눊ü>Çþx ç[ægŒVKû±–ˆîìy¼ç˜ŠîÈn?榿[åÏ$V:”µse(åb*–غi~9¦ó¹ „M¦X£Ìl|ÆÖFÇü5M/H‡ûñëãzµ�¤#y'Ûça¨žvM¾ y»+G·Š~×µ®£c_íÆ�ó’zZº±gÈ{%?6°L?ìïæxŒ)V?‡8–ÍÇ?ýøpgšå±üÐ,�0²7Èan m_Ÿö¹ñ±ÃX}çøùxl€¦ì Ø·€×ÇöðxN=7în%t»±™Æ½±Ù¾EÄß_]yž5 ”MSƒ¸žKýý€ñŽùÅë¾ |õb¸iÀ)öC>'Õõù̼ËPû&:^Î:õ\F�‹2Æ’ßGq¾³�—–ƒ�Yóøn ³p÷‹ù?Æ C†ØÉï3v˜´öûøZL²?3LØ÷—ÿ<$ǸI&štÚÀØ,~ 5mãÃ-‡¶åè^cTéYÊjEÒ^JÓ± =qå ŸùvйãC;”Ù‡-[Á­VÄ¿î>Ș:fËdÎàJòÎgÆ�QR{ìî1ÉD]{1Yª^s¡-žKOõìk@spgõþYvl:¤”=J÷yæL™Oó\-PÅûo„R€À™'1þ–4®ðÏ€‘`U±¸<£Ížýéðù �ÿ”~ñR�Pm4aÔvyºuhýL¬3 4~f€ì4ÿü>géÑV™�OÞ/QzÐÇ›××1¼¢„¡î®zt€…U%]ÈLp�×JÖÑ;m¸‡®Ý^¼iƬ®?ý(ø´¹„`/ÂéÝ~Õ­Í|?­çäs ›Ø,ŽÏg8cR/<ZÆ�µ`Wš÷˜b¶¶·~¨$>ó÷ J 2 hdXÆ 2ñcýù}^Ïó=s¦ó9fjᑯߊc«^²;Û©B¤WV÷ÛÝ9¸­b¦\ÆXßIm¦˜„XúUŒú».Ã~þ¯ºÑúÉöSnh dpG¤†@˜m/çdh1þÒ;IWÕÃæë:5Ÿåǧ„e¿?_ï×yÉÁCã ÚÚr4ÖýÞ·É#žwM÷÷ZÁ–ß÷“v@)EÅÌóìëã,%UÈç' �{7©Ä÷1ÆëçÅIÊu¤Ù÷|ìÏWp˜_C}QòÐÏû+fÙp¢$^õ^õéÅ÷É<Žéu€c}¼×Cº‰˜îºŽa5°Åcí2ÄôuWwÜš½_*Æà¼Ï‘Õ«O§Ø—2‡ wúÙŒöm¼f–P}AæŒÍ|üL`ñ•Œ§ãÍ¿I¿ÆÜm¿~“dï·ºu‰›Eà%ëYvo— Éð%™Ø•üC&¯GŒéÅÏ×)à‡KßÄõÈóåÁXj;oj¶UÀUdŒùvÌ0_¨ëÆ`Ó‘®¾ `¤¬Š%–M*?óëاF$qÿÙfcŒ›dâ¿Éõ�a (SÌ/e·ß·éMàëå7Âûƒ^÷÷˜dº<h|eNóC°O½r§¯ðèÝXb1†XïÃvå{tÛêCAIZ{£WøúÇ…µ±©Î?w„e–opÆÍ‘Ò//Jó n¿(‰t+/2§ãèBË_µ›–â+÷Ul]C?®žUJOÝ.cŒ ÈÒ£R9& ðíQKî!CNØ9£rÛ^"P˜IyYÃþª-j…<:B­#r9ô+Æ–‡Ç«¤I-ðÀ>Ø£”]ÎÜD HÖï*)´‘ÆóVóü¶‚iêþZCpU ¹d¡/ñqäŒÙ1"£ÏŸ½Žp¦ÕÊÏ¡*ýXþÈp¬$³v™“ç =·Þv\`,)Ñ‹b–FÔòÝåÂjÅÌ|ÆÎÅ~d«Y~TÀx¯>ÏJù~Åræ¢?/–+¾Ù:™*FP]®“phh†[ƈékIav}dŠEE¶à¢+ùŒ Ų\½yó®õn¾b9HŸ1Œ~“çǘEÙ<ù Ó™v ß)j\ „¯ç±ØúöŒLC^ øe|£j…=æï¨É‹=3Ì«˜m¶½³qTš,_ûß”üùã¡Ê¿2%•˜K@ÖöE% °ÈpéÅDRµe1úX¿~’‰Ÿúý£˜šÃ_ ®[þ�£GŦÿj¶c0&P]Æô±ét˜øË´Tg>Nöbý uÝï•”\-Å©òãŒÍØ©ÊÉËñs!˜Ç¤Eù{è*®‹å`é0&^¯�leVBñÛC"q`W¾•ùUÆ€älü[�“{o‚ç%8ãW—„K'vËóÃ�†¹))Qœz ¹XžÝXXUŒ-^+ÌNʺÌ5p!à¨Ûí*~N²2Ö3ÿ=\ŠÁU1ÇÔqÓ«J¿ê¦D¢‘@ü—M§!‰Øbªý2~½^S*ñï±iŒù5¥#3ëwvý'‹ñå¥c~nŸÄ»5Ùüù CÆÛÍpEÜ’Òè·Ü X´™æíI“ì+ªö]DY~×ð«Ê‰AUû쭘̻Šá…ŽC¾Šù²®·Ž¥é(²À…¯‡—€Àt°|ÖPr­’@¬€[ªµEÉĺðÍÞ!MK%òú«~ttÛþŠý™*u?‹Ñ¡…ÛÑ39¯R%V’QŠéWÚ‹ÁsfÈ„\ÐqÞ‰8€Œ)$ØïVšÍ¦c‘l¼Úü;™ÿ¼äÅe»e÷Q9vmy' KFÆ2 \1·9T¡yPª}òóªë¬ùöu€Ö “ äíÇc2¦GçùÇlöhBùãžb(Úçd”ÜÀ±Ý_w•Ì'ò¼eÌš‹8êÿùüsp©Ý³ÿ/ž äzYÍ4Ÿ+Fg-å{¿Uòš×;Ö#.dàŒÚX#ïØ^-ÖqhãóùgÀÈpôãšÏ³æ|†Õ×·ƒ_ àÎÇf–ÛòÈ•~?JÆ1[¿Ýr©òÓÐÚ¥H7æ“Ûµù]’‰ 3Lq u>9y–ÓǰŠ1z”äè2þüGf /ÿ¢Ž©£Ë?† -éÅ£pÀæÏåÃãz_ÿkh‡œY8ì¾RDa ·AÏ<À¯=‡[%Tcõìù(wÝ. ·°Î뵄hÖ+fÖ.£‰—ûšœÿ>FäˆNIÅÿ¾ÊÁ~\O�ì�ýuQºÆ¨@`ö'—{ lO°-^1¸ây¹”¡Žt¤J¦ò¯Ú3¶«Mgm•£'©òÅq™[«üþ¼ƒc–±o\ÊïPž‡Òƒ#9„SlÅ{•ï‘èþdý}¸ýkx®³qnÛ;©˜a½q_õK+«òg¦‰½7ÏÇ#¦X^N•-ݘ2¾–ULѼ}¹¶«}ЕLŒ’†¹dlÅ «�®ª<˜NÅS•Љ¶o j�YÓþ[—nƒ‰F™g3¼^I$ŽšÁ¶eK2ñïG ±?bŠûö¿âj<î™c+¦˜·?Çãóûø½'•øòŸôçïðûwrœÄ2{ìÛŽ1üмœá”>°Km|Ôú~vb}|� >½®ÅüŽâxÞ`éö| <²v¬±åXõ+ê1·}‘³•Õ7@¨Z‹®W°Ù AåðbŽáÓ&–ær/÷ñ±Åô”½¥û¹K]1±t?Pކ½Øw1U%½†åSå÷Æb[ùÔv£…éT9²ûf¨·1Æéîø>)¨e,y&åÄsÒå±Òs¶µNä|d/F¤Oòz– e"‘¶ÒUfï°å’’©M˜Â�aPjÄàò€¬?Úgþ(€"^‡�Žc¶M�ﳎI5Ï[%mwÞiWW3Õ_æöÖo½Ä¨­·¦|ý/æ÷Ûs^ß1ÖOÊ<“þÊ$èäúp”F1?1Õj¾œË¼¤­•^«€˜,¿hŠ‘Ù±™Yõ¼Û$óóc].{K¯‹Lm>N4£ækŠvÛÆ"v¨˜,ýÝüYù±|Uû\ÌóÅã•:›- âfq=§Š|¶Þ»ë:æïN*¾]:¦Ö¯F†\‹k‰îpRB;í ¿HPû¶¼×�Ì 2FT†Àty~Ç0_·ýr1<pÁá2îHô1¸¦þ“†÷gÞ¾ºÏBßjÁ§ïÏYÌè[éð/GåX\nÊ.WØç¢-å üÙ\¶X.¶ÀWµG´½ò)ÉËè?}€Æ?>=€š9€=ô*%iÇ$u¿8@=VMß龇6]\XëÛ ™”{3@Å~ÿ\ÿû×sOѳ�³’ëK8òrO`I׃K&ÎãȪÊÏ™a‘¡†À˜Zý6lì­õ©$ Ù|D9ä-Cl¶@C2‘�ay»Ævâ±Û:õ¹Õã–N”ÌûG„ÕÌPTºö!¶>ý<ÊM7Q²o7¶—ëúkqÚÞû0Æ,ë–[¥×½¿È0«�<d€Uý„Kþ÷OÅ>kF®�¯Ó ÿ'K·°¹|6$»L·ª\Hûeü}ÿï×ñ0§þ’’…v‹±Ã"ìw¹¯c.ŸÏÿùr�Ðõ�Ԁƀ6 'q"×ú H¤¹ XÏJ&àŠÏ‹v™Q[èZ{íÓc1¯†<ç;W(Ú©}ܰ ¶5.™Ã%ýTùêÖ9¦–ÖrÀ ¥¼PR %äÎr‚ÏK‰꯮áæÌ(}2}tKdåŠ ·ç,–£ÇM¨Wì# ‚Œ“Ýbû()Nþtè##g:¾¥ÜK¿þžq…Ru>¦ÕÀ˜C=vì¯Ï« xCFPÎ(âé³zxÀ}Å Át69¦˜€ÒÙÿÔÀë)=º+tX÷^ à  _ÛqKÖ3 £ñ'¯§ò¹Ê ,‡ÿŒ§P—%9}yHèÝdŒ=ÊÀÆÈ{ô“?Ž;Ò‰@PÏi|¯ë3êe*ÓÎéõ_5©k»uÔó'%Y-ì@†ø<ê™ïÙóû-¶ß¹¼^µ›b¬áü;cÎ+ Ëž—K­þ’3ô£„Õ çëûß•j4¯‰wÆbjDñzb¬°øÝÐ*2ÄÊØËVÊÝ“ÏÚ€KÆšö.¶ymgú‘á8ÛMWüý¸Ù-‹Ý”3Ï8 Å� UÓ·ô|þ„Fà±ëÆ©¾Œ—dâsޱå�­ÆgNö²ú>v˜’*å嬞4Š¿œ ki¥>åùÀ C‰AÆXãû·½Pf÷‘©SK·q&2l„ \XÍÞCK‘c3öl9ÒýÈÒL­Ý†8Ÿ÷ãÜí¯Óý€5ë³¶y¾˜d©›·‡*?;®úÙ4ìoùB Œ¹µÊY1¸0?/•8·S"1…`>¡~Œú{wdœ¹éï'kþ^¼ºq¿b:}MTú£z{ý^3±^‹í‡ù»ÃXEÃØTX.Œ‰5îçñët}ñú¼<:Öîóû �½ŠÙ¥ÊS1¸ô¸YŸœÛýCþî¥(¿ \öê¡Óçœ*fU+v‰ 6w™[”q–ÄC l‹!¦€¿_Ìÿ7FØß ìß_,€ôÙ2`lÜ`æzÇ{¹_7·Ÿñú¸E€î¿ÃÄ»ec@›½î·Gz?[ëþV­1ï'´Š)¦Sñ³´÷á¬4öG‘N-£Û•°iMyþ¢Œ°›Ã§ƒ&:†ü}º€ÉK¢pcŸQ™”V&IˆR; ·€4”ÒFlåòŠ-¢DÜuºÃ Ìì«+þ×Ý;?•^´sñk_,¯ÇÅ9L:ãÏJ°IC.’9Τœ˜$cÊXwý­çSLMÄs‡¤ß?æA?³þèð·ùE@ «ì)`…3'×vŽ'å�NÞX:7·s¬«]WB±o4Eðd=×s%—&³ö.°hŠº~¾ÿv¤$™#$.XXr™ã™g‘‰vn™Ÿ½þ1nIÌ0·?Óƒßëö[OZÿþ|.úc ÷ñ3úR‰Ä÷5IÝ äçyü}§Z‹ÅÎóíÜ­ˆf¥í{çA] 7è°q[Í“Ðáó”\Ãv¬ |9}:ÊñÆçiÈÌ™¿³yºbÙ£»_1Œa–›Îï¹ñ{‡­*_ÌÇ‘–Wˆ(9X3¬X?´Œ>+Ý£€êµJ'.IÅ $Uã að¶ýûÍU¶ûÊŸ•SK&ò:Èï^_ížÿ¿‰cú¨/ê\ú·üK¬ KDfã´UÎl!s´¾»ýè�äß߇ð¤ŽìÏøÝ<göLL"«ìÀçî¼R1^¦C_I2¢t¢j$ÞrS÷/ò|@J@i¶§Ž‰õ5Ë%wb¯ÑuV¥¯�ýœÉÌ, ?Ö?ð~dég@.ƺËfìz´ öÊÆ;VÔÜP뙚ú:_>.“={(q¹÷¾©¡Ü€ûJïŽÛÅþ7ÙnІVŬÂüyzU9«qª%Ÿëu}* Žç‹í§_»Ò–`ëŠ0S�iPˆêJ*€¬ËÜú‡Ÿ¤£bÿ[U`ˆ-IĿ9 e&»ÿ›Ùzi „ýn¯›�Øç÷±bˆ Á.=o¿ö8^4ÿ=_·ñf¸bðç®%Æ•*VWìÎüvÅ`âùUƤ_x:þx::7Ø t"›hóÎäÑ+­SMdâðóŽ$žµƒ/¯w [ÉÁ7—^½‚“¾ÇðA%Ë�‘™þEv¼}Ÿs¯D;n:z.�P\`1^ΘkOzñ Žö®»õ�åªW-ÍJ¥ÞÉÄA®ÇvÌÎãrSrnK­$ý¾¾ž—k<òŸ€ÃdÂøü¦0Q߯šÉäcŠša„ÙšÄò~x=—GÒ–0Œµ=@A…ë9ˆÏ£Ì‘Á�œ ÌòúÄ+*àÒ3¨]ågÏ,?2#ñ$%œ -¤Þî@÷1w€0l-4¼/qÉž‹?öâ~Fl‡œž•<ÔÒº>öeµpHoù‚˜š±´r} Gìù—0èHb¾—�P®÷­ŸßðòÎ|ØóÀIqÞe7,öX6nŽ0Ÿ²±GU¹ÇÐ1& Á�”LªìÙy‘b`u%¿*õË£ìYQÆx=ëÏ(ÈÊ¡æóx_nÀT-Øi7”.g@ŠP­i‰9µ²Sm¶×²XyàÛ“gË]µ2湞¹q˜TÝdVÅöÜ‹%ŒÕ“:Ï­¶¼<ÏEÂYå‹LÁ¾TâddÝÚ%®,çÒ€“‰u óñÇyúv¿¿€d™4}ð5ô[®ƒ9žÍ+1¦šŽet…ãš!ÕYà´ž>Æ!ævøâ“û£ �=ë€WÒ†;÷±“þ.ЙjÏë“„‘‘Áû…-–Lì9i%§ã­<‡p=šòŸùü>Û¡Óù¼ÿúr'¸°¨bw1�ª§”t ¿÷€9L¥{ J»«6+lµÇÏ2%ˆ€’ïÇ4õ>=Ë„Êc–ý@Øž£Ú×õ¨¤ Uúy¹žTcÌ4µ?-  …Œ­é=kÿjn«|ÿaÛDºQ0Äþ61Ø4"³<¶ØÂÌyḭ?šû¬<ß“ëT9ÇXAŠ£TÈÏÂ8Ð…œ<ä_,ßJÌ W`ò”÷>b;à‡::¯!Ëcw+s$Û•ÑžYkÂ>T‘ÁU·C×_K&Ú‰½-7:Ž-Çšm—›ãJK'*Ç?¯·ÎÇnûý¨J/)V¹mbl´Š vJö´E ûŽõÕì~aÌ®‰N5ÍM_Nà0쮀öýöÎhg�˜¬å+ÖÎnü^[d†q‡ñ¼06Ô)�gø®c>u>dc?ó±uŽc쌻ÞD€Œ�f�4ÄJw2ÀVŒ³áÚ~Œ¡ß"Õ}9=úï_ñúl%$¡µÄ§ï‡1æãY<oG:^ÏCõ‹SúA<KFÚËÉ3À¦ÁxG©ÄÊâ˽Çûï_›'Fo +Û¯Ì"½ú_Üu:Å3,ÂØ#cÌ:»?†š·DfUÅ4Ÿ {ÔsÊŽ‹ã½Ú÷2W;ÏOͨÄyJœ(Ç«2>žç8ÖåFÀÅ2r¦Ǫ̃Ÿ¥<‘' ±_¥wiδúëè0|#J$~Hÿ †1S*‰uƒmÇÑì•|i³ç Rìw͸šåŃ ™€r&½…€‹ÁæËÇcDÚï4¬-IJ\ðµ×ÏÖu˜þá¾EÆU'ÅeÑáxǹU<“šqÂc}w°x?k©D»õŽQÒüów2Ä®¢ÿ,»}w€Ž< ªy³Œ|¸š­gŠ]iŠLl—(ÉÒc±ÈzŒ´ã}<åÀ¼Šg9¹!slÈý^z•U±™tº¹T!‹Á•Yì×(ňÇU»UùÊã`½éÅ|o××oø|á¸ú¾ý€ó&cì•õßÉû¬ÛãöÓÈh¬Í–‡1l|½ë'¨}n}„r<Ç«?y?žX ` ÛC]“Ù¤JWwÞþR ”œù( ¬?=ãåý[L_3Ôt«'n?ÄV×÷Ùz+€Óß5ÌþÉ~ÿ‚ýÓÜ:«b”éÆii̱_ȱ¿ÿ)¦Øyì0HýiOØËoƒUŽ)Æb~­3ÿãò±±Ä2�,ÚZú„¡&>™ÞqÉDõ˜©‰Û*–ׯö˜mq˜Óãºñ,¤ÚKx\äDº“Ƥ±ŒƒLšD­X¾„ý㢪Æ<³Ì˜a¶1æU=¡æ>(å¤c`;rG—Ê÷üp”±v¨Zjµ*‡ÄªtС¨c«äÀXtl ) ákÒ[GáÈbÒ #j˜ë¥!E6QÎÆ ¶˜'0ÅÜËÈE Î¯à?àU•Š1Äb¬>Î@Ëy„¼–qÆŠŒÁ°É›%0°†Ûÿ<KzåàW¿S� ÿ<ݯT{Á0^[%--ó¯ãû‘)X-8` d ĬßÙóÕ2mÿÒ‰œIŒåšïÆ”ñ+°ù{D1Ä”Å^¬ŠùX/ÿPý¡XÅ~¥¶øüÿªt¢²]‰é¼ÞGRþ“öòè/3? dŽŸO,}õ~¸„÷þ”ŠÙÅçKkž`Ÿ·G³¯Æ±}~ p}õû‘™”Éû=¿èšg‚ô#f( ¶h«zëúS ­ŒVÕûj¾Ó¡×a`)†U lÎ\Ö–/üXÆ(qÇÜÓ=I5; ÷àõÀ›gÞE&â’XíHÔÍü2)Edä $•]áŠõ½ü¬ÃçvŸb,±=;4ŽøòVõÓæï/ÆÛ+tÃÆ'g\^gYæay§ämŒññrtÏß@õr,ßÈ�›[ËÉ$J½DÚÚÚú~˜;Æ‹xýŽ¡"έýjFiWúÑ[ïñ<3¥çÁ©Ýý=ÇŒŒ.a¨€ÂŽ´a~<2—ªëÙï¯$d@Y€šågÇË·ûö‡dÞî[_®™Ž±[ÌÅããäð`ØÙòŒkú¼G‹1ÐüvÇ“˜Ý‡ØÿjÊ‚-Ÿ¶WqtÆ›�Yvv´(™‡¦`ÃÿQޝžXóù¼9ˆóxl--‰Ø-‡ßÖÆ=ñ53,ãºwlG{§=¶Ê“0À¾kì_Eúª<©‘˜h®3†Y•δ_Ưã8ýJ€°?’+-ÓëÁc‰Ý®ŸR‰Z`íó;Ê“Œ\�|=ò½K(2ãõ‰šïÃí±ÿ¬å×Ýiýå‹x%Ùë­€¸ì¬›å+¾Ö‡™²œ¡Ë<a׫rÍÞIzÓJI1T'_N¿­Vv³ö`ÒmY;b>äÓeF=?*òµþUº*vÌŠUôó ®bXì9Xñþ.•.“Ž{” be�YUžïò?ÓòT1¥l;N).ÞߦCõ\Ž+šôg‰ØøÄ˜cˆpžq¦ú×É=Ÿ6¥dQBÑl‘A–2ʆ\y'�f˜`ý~ÜûÐS�´bú1vÝ€ë±'8ÿü�¦æñ欽Ÿ·û»úçü94£”¨ê—K*.ðÀrÐr ÉDdŽ=ÃCÛq̬Zå@UôvÄ8?Pï‹>S ÿ› 7¾*JWy3Õɨ]¥àó”p—êefl^Ïg_Š8é2g-àÚ‰äÃÛ!2:oûþyÓ½ÿ]à$¶¿ª{•Ç|ê'izÈ®�íÈÁöèÇ>‘)¶Ý‚ׇø?c{7ç_Ë–ßÿž²ý5Úb¢YG·•T@gV­z¼C:ÊÞÈyñ:¥ˆá™™Øm¼s“ÈgÝ×¾Gî~?¿ÞËùÑÅÌL»›¸CjõRò߀ìÏjüõ¤_Ã6Žtdˆ±zË~<c‰™‘ÿ>n 1+E÷J8¤3ÇÓáÁÜšL1 ì±vŒœ•¯ØV £è €k_–/2¢çsJÕ7çš9u•åùšå’‹Óöy/ú’c÷ ©Æ^ú0ÅtøñÈ€R’‰ù}Çû¸ú¹ßr[À€ê¡«ùï’×Ìô‘ÈÔ²ŒÊ%Izóɘ=þMô»g¥æ0¿U|ý¬ü1VØëýèß³šÁt…ó~–u¨9ÀU U1«rIÅ. Úm×:šès w"0xýÒyÑ&€„±¸¦µ˜`<½ü?É0K¥ ³kËL>ÿØtfyL9C ±àô·9zŽþ‚}ÿû÷±€°0u“F\@Öï�dý>†º~·?¾T1¿@×çÿÜaŒa†Ç;æ'úê“5Ïi\ò¡× Ê‹Çkó’>]wL½Òõ9ÀbMÏ+€ËÇjëÄcYŒÑS9XÕÄTIMp ZJ‘eçàHõR>§àˆÊVÊŠX �� �IDATŽÆ»tõØsÔYI¡JjN­”U)wÎÜwKLi6åpÕÒ™¶4u¾“añ\L¥ª].›Ö�|¡|J¦£œîܱÂ×ç@¨Û!s˜®X4Èìª%³qxépI/ °tmÛòGYoÅDÐ …•rDo\Ôh 0S¼>‰iM•Ÿ·#2®"�ÀÚáÇ;À¥:Oe9ýqì/^:ÑÆ$܆l=8Pæ¯9Ó÷qÅ-…Øe-}‰RÕ“?9O告áÇŸ[ÑÝçŸó‘¹ÌÓ­˜bLÚÖæ{)ÞÙlÒ3k†çÎJÚñHÆÞ:Âx<–ó![ÎZZ—303@¨ZÑÌR`­ÌŸ3žÁ~ñµîŸ~îØòiÅ„½hº}%ög*Yª]©Ó.C¬xW@˜ÙÏëuxä³/?ïßû° ïT~<Ý ˆõ #:†2ªzæ™lŒñ¢‹ö<{ßüïȔӀ9+ÆLÜYˆ¸ï&â±Ä*÷Oªï¤<†X]n®ôúgו«q÷lÌ©%cˆùû¹�¼póâhÌý M÷YõýëŸË�Cé46¿éfŽþñ¨¹Oß·ãÍj ÅËà´ó.3qæ–Í3£$á×Äuk† O§’L¬í ×} ëÇ‹Àž’Øœ¶Ó^“ëó…Õ‡ÇÖ§Øz|{¤° |ùô4”ù@ØžyÆ˜í·…ß–Éô6£é[ ŒpÃØÑž‹EUçè·„}©ÉۣϸÚmÏ^ Àþuþ¾Ö1²òüàµÏ ûj½•·s·|‹A™Ç2[æ$L*d9àiÚdhM3écŒ¯ghî÷.£Ì”3Ä»_¿š£7 ëß°Ïcs}¿1¾ÓëOw|ÈJ&št>ÀúdŒŒ1~{ùÏ-ý;@6Óù[°u˜okxñØb_·^L€gm÷3ù¶êƒ±#£S?Ñ[+^•tb&™p1Žõ¹r¿ÃÌšf¥½£ƒT¯ kå@B NMì'pÇ€=[žT ˜k—{¿µ<ûá[s4¾%çÍò”Ì…2oû1Ä´ôäÍÔÊ{_Ž>°|v¹ Ô\&›Wϋ҉ޱÃTí ´áå¦~¶ßeTYû)€ÐJ²ñ²˜/g׿/qŒ1^" eë?Ó[+­Ç?Ρ~,ýê>öûi ÔwŒ+8 ™_ðz‹×OCÉÆÔà·Ç×ø:ËóTý8ó뇸¯îg&1²úçéÁè}w¿çé©h'Ò*†š&Òþ‰>Œ}_Dwñž#íDþÛ1k²xuAë|Ü÷ÏëÝëm¹àªZŒ1®ÞGþV÷óËc<2I7vÛ¿`øÏgÏUí¡¥z¹Cúò�öôüŠµÛš.�e ŽÔñëæ eÆY Åx»ôó~†ÃËå·PÁ;K$æ{-ô\D‹›Mf23º­‡RJabn=àä¿Pò¥±ÖA>¥Õ”eL³ìû ¯Ïæoõ}à!¢;kõŸŒQÙ¡ùÀÁ”H|-¿`#0™—N9}¬°ËûmŒUžù/>ÄV*WñôÒ…Lʳ3¿­cLÅt­èîHÔ±ò cœÅ›ý‘¥c¯ïÍç—$é¼O^2¶sžî”ä=4Â(!ÈM3Tz€Û.Ã¥ k ËÛ«ÜV#v_Ó?Ÿ0Š�^_ÊWÚÏtyü~Œ…óõ$Tßÿd~ä$‡ÈPâqzocI$~ÜŸ'u,Ãe(I9% ǰL¢á¶•!ì§¥c{Oì:ß×Öþs‘Ät{ìÇÀBÉÀ\bT[Ðæ@WŒéÕ«¿NG•¯{¼*wUžþös®7ÆvÓR˜Èà¢ÇÉùÝØa*ýgÏSŒ2d‚µ®!¶˜aÿŒ1þ6@‹%†Ò‰µý9�cD†X”L¼3þ߷¿ÍýGþotÍ3×ÔŠÄ㎣c‡%A£Ñ´tDn|å쮄¢~¼}5|}Uþ!½~˜Ä”]éË%¹ÎrbžI'Ä•ÿÞ±´êCH¸³O ÄzÇrÝÊ»bB̉¶ßîÙ¥`@]ÄÊýNûÚÖüšP‰µ¯Åøj þŒ1ª˜/;Žg›3JrUõŸŒ¦v~Ÿ|%|Lh‡óŽt'^Çì<ËìšÀž”›5v†tOC3Ü–ãõÖ¾ÈíSµÚer­ý÷%©¨˜c/EI…63Ç12¿&v‘ý¤7RÎä?Űz£×Ç匶õœæã%Ïo’‰Qr®JǾgB¿2ШâØÓ<sÀêý}††o­iÏÅÂ;–é`Ž*Vçž­… Ï¥¯Š©gŠùva°žâ›µbjtŸKj[y¯Æ0†˜·£œçØôp!“*/ k¼œ¡œq<g’tQYÏhž!ÝèG·­ ë8ª÷˜m±ÞÊ(“íåøØ:Kb«å&°ôNΫbí¨X]6æRÖÿYŒÝiJQ¢Rœè1Б‰µJRVÜ|=W;`My;Tßi(¹®÷ýv~W¯ë/Ìáš´wTN äÚürŽŽÆ‹;þZ|§÷]z±\v"‡pÉÀÈë�Q €bÌ/k©¤4iþw‰Äé! iTdõ©ú»/O,7ëWŠcä(ws诘S(¹ÈÒ[†Ïÿ<cpSþ¼ÀØW °ª�ß ¨–pçéV¶îÃÏq¶ê•K¨Ùóm?Ó‡¹„Ûëê·¿ëºÃCrP]gíÛàó³%¸R~ƒß±æ€½ß±¹½W̵)™8ËÏÛ•µ¯×dˆ!`s³ŠQSq@ýÙÔ´×£ÚcnZ>ÞU,±.ö­ ta>ßB>Õõ¼ýëØiy=+&—*ŸfÚõúaÝnÏJPªß»1Ķނ™5ã ™dI¾JÒÑO�5ðèõ¿ŒÅ›L±¿¨D¢Ý¢MÉÄ1˜dâŠ!6Üþ­àwFÙçiöù} ™¿‹Š¿%×åæ'ºñC—N¿$¯<«ÎÞÈ0é9nb¾{¯K±gîk²gŽLõhV0£c¼’Áúgðƒ¡[+èz’nÖÓæ}Øû­îÀ¥ýáoÛQs¸ÃN¥¯Í—·+å£R‰î”èxüšùúOG;Jî )ZFŸr¤0«ÜÀú�æØN,À™²wŒz‡þ©LËjÍ QÈL2+“(L�§Ç˜T­ú`{)Ë™!û̱ë(àÕ•þë<ŸÖsIÛ hÔ@•b~äRo'Ú?“P×c6y‰OÌ!@kŸë XŒ­3ÍOÅÌB�!´ë'ïç'Sжƒê|{ñ…+}éDoºwW�5Ïí"Óá¦btÖÆÀ£hŸ¬]éÍË­cÈ r½–<Ò~ÍÞ«Šñ®Zã͵g H3 lþ®bü} ¤k);dTúq·b½Ã~F÷%Ï~'¨XW]f˜šGÅq¼Ç«?«ÕˆuÇI¤ Õž^Úó€±ej~€ígÏcL+¥ˆÀúŸ-w–/G+æ‘nW;žÈ»šß±ÜlkóÃúã÷O¦€±Ú±Š‰4-ö3Ïœë9úW¾:š]Çø˜�XDTì¶Ÿk‡/§Ë¥ú§2t°{f‡JW÷‹!Îcߟ/Gï ¿ÇcL–Îê QÑ—H×§bÏö`ãúÕ0xºógž>JÂ~Í^@v(ÎpþÍ4³¬Cl׸zÏ\7ý~,3Þo:@ï9ðÚJ¹æ�åº>ú£*Owêa5¥øz ãí˜aœ!†ã”{6?à~î�?¶žë=Oc¬Do€ôVŘºÙ>Slæ»Cì¹÷à*7í@N¯Þêü(Ú•Äþ„±Æ£¬fˆUL«¼žß$P7èñnºz¿’Ääí mÆcD JIf˜ŒDaz–¯ÐrÀرÆ(Ó퀡Tbe6–Ø÷ñç�ó@Ô”NtÇ)#Ì�^Ÿ2ØË@7Ë1™d u€±91o>V>³úá�3®ý_i|×åPÜÊqÓ³])¬e£`}ùÝz/³/浂sI í¬À\¥ºˆëâ M%¦Ós¸¯íILˆF9‘¿•Î;.;Ò…^ k9 µ¹’ÅPãíø\Œº!®^×Äyüx̓<‰­ÿ%u+ÕAÝßéy½XbÒÝûÀð}ÿòy†~·€PÌ–�(cÇ•¿’À;·>È£+2c8³ä4òÛÌÁoŸ?ÑâÄ} MÛãó<†|®à~öa¯{«]=°y¦Ï1TÙT5³ŸK(±‰G}¾ö ÅØšõöŒ]ÏLF;…ô=PÀž"8XýcæÃWZÀünû52Çr‡Îz3°çDeæ:—gÜrÅXs•å á]†Î%¼Pʶ›Ž~Öùû燒d@™ÿ}ÎpTtà£åÌnµ@æ,ÇÊ™‰ïn»®/ÒË=ß«_!†Æ¯XæÀd Zv#€áµÅÙ³øÚc„ÕÂAqII¿¡ ¡ÒÕ1¹øqãjݯ M€©ìÄÒä�Ü…9†�Y#h^Hfêìüun'ÆY9Øzeÿ½œ3”¢{çÒëØŠÁåVÝëuŒ¡ÊòòöËÁ¾}ÞÁ®{î{9¸=€b_õ§˜aô9o¢Òm&¦˜ÝÚôò…X±‡"0–/¤šõ^Rxüû;> 3ÆYVîìú €ÍŒ)©Äç.µ”%—|è`çÇò?›Nm0“ÒcÇ+}Å`õ@ïwözµÀÓo=pg¥1;ãÄ�[1‡>\ú‹AæÊá˜a¦ÝæþçGxnøö]ý‚3ò^ÅuvË�ï(˜Ûzîóþ»;óý!ŽW%Ú‘ŽeåùV�CÚrÎsWú¯ÏĪ$Wwc˜u¥};)Ïs,! õC¤Ï땳ê7ßýç§¥CÓ`£ 0™ßÿ×WÖ•bD�î_›é©z§Ço’‰ÿK*ñï$I˜þ;#l\‚$áï˜bæzÇC Ì_ûŸÿ ’®3Ƙ‘PÄôÐì ¼] ‘ÚøŠÉgC⇢rܨÜëôVý+1¼cúáÅ>à”Miæ8ÏVWmL¬•¶ŸL‰Bæøòù`Ðùäý–Ž—\ëÔß;`06LÕ‡ºr´Í}\¹îŒ]‡~.ÁµSA&‡Š1Ó­~.¶7› 1¹L—|æï—]ÉÕʽ|®ç/žQÃbܨþò>¢ƒÿ\œoïóXgs?Õ¡uôÏô–ãÿ ž}œá>2& kwö‹u¸2÷žwœÂÚIÙ×y~ýlyƒÔ#ã¢[>kØäL´)8d¦ƒÛUžSê É�2U?[žÅ›Ç§”!ÖíÛ÷]äws Áõ/"VÞgßÅ>¾ü|(2 :ù_¹ïJ]n¼=5ÃlOš1Ίò’í�p¬¿¡Ÿ«ç’rCIgU¯º<ó:‹k ý|·�àqè÷ /—zÎÒËÊ¿ÆQÃÐZ\ï0¶€¬³  KÌ×|wp¼ßªß*éø¼&q\a‰ÒFŒÁ•—Ÿ2ú,€£Ñþ<÷­!s Z™eÂ=v~¿�¼@¡U@.�åß =;€î"~G '¯<㠮ߋ!¶Lõ+J¡SJõ˶ëxÏðySå—tþ¨�ˆéÈœí·Þv¼’‰÷‘ÿŠÑ_Žé÷©5;Nw âð�®ô¼¹ý(Òc„tøˆéT 8“¯~.W ¼\_•zSõæí°Œå#  0ÀÛßÏ=iU6-€ŽýÌž·¶š9¶óœµL¿p¤cû±~1c‡M Åopþ"81ÕÏÞ!v˜ªïü}Ö#k”ª´õáÌOß.‘yÃËSOHÎe$~´—\ø’ÔÒ¥U='ƒª;óÈ¥Uu»öbòÕùó|+Iþ” ªªûØvpçwûaü=ood˜UL³¡ðTIšßÝùxœe”Q2Äh9&à Ó'L6• 8ûåñ߯ãLý:4€D¥ Åù‘áõ;½þ”9F‰)&íqÝ]B÷;f?Xv¦ {•k">¬mJÍqÉ95}× -¹÷œ)€§‡RUŒ€è0òޤìÖ:Žìï¸r2›pLAcÈpAø”è:e丗Ì\Wîr†Ùϱì.#ÀèËë»åÁû ŽEe»ŽW• ϧ ^ þÖ,@Q—#2on¢+¶Ð¸ï#€ë%âÃ¥ÝÐñï[5ÖcÇç8@ÄÚö™Ÿl¼/FÌ’.EfÃÖÞÉuš'Y@(Q‰1øxÊÞ³ @Äó|yÖvõïô<ì_“Ù¹qü­8¶ÌaŸ²of‹ç­}¼£DŠœsz�q³ÿð¼œÑž $& e~ÚT»@hçÃz]÷œ¤kü%—´}þ½Ä%ü½oøÞÊßTÊ=¼àxá ¬Ú6nþ½²ð¹ãß±8.üq].<^Íkfymÿ²ÌwêU>³ÝÔx´ãz”éÜ,2¶b{{ëÍÃ+Û]'«l-¸QÖS¬˜ÀÒAéL °”)ÆzÙvé.± )«ÌÁû%jŇ¼ý(`’ð¬ãÂÀšY• K¢p¥_1Æ;ÇÑÎ÷» Bcú<VØÁœÑ±è–ì}Ÿ^Åñù9 ÌO˘/vÛZ¾XÛ x} å0ËÀˆ¸Þý7Þ¡x0=C1¸Ð@ÙÛȤÓrG)‹ÅæËŸ·3‹±×±š µã+¤]ñÍžeŒ=+½¨F«=Š–XÄ|â>zÀ굑®\#3ÑK.V@ÜÍ~ >®˜”TÍ`÷å5ãm_skë÷a�2Üæï ë*îÃsÏá]�7as¿+Fê÷_ïçwá4-ÙèÍ<Ú#³ô¢´aOê­Ï¬SåS±è”ô!¦£ïCÕ=«¥çy¾E̲„ öûÝH R&™Дôa”UÌ3Z>ü=©'MÿCÌU |ý•c6f×”,Äßoö§�¦9)E-•ˆ6c‡ Åáò­cŸy«VR |Üÿ¬?8ó•@ýàŸëã ò½†‰öÞ'}« ~àÎ-_¹¸Œ;ö<°ÄŒMÀ‘ sù¥úàW+²Yy±<ÞA³ô=fÜt-‡—ÜÓ±lmvW”W°it$s#®¼·–;ÆŽ7S°ŸSŒÝ%ÆWvû‹Ìãå"ÖP¶nüœ§ú'qL²Ë_IFèlM}}p{&¿gé¢ôbž±ü”Y‡.öOënó<Æœ‹–Ç^ÊŽgÀ šJ±ýÞDzYûd�˜’tygîgy_:@ìÚ÷Ï”0Ì®gå‰ðF|2d äÓa‚ :cˆY&hÖŽ1ÿ‹ÛãÜ4–3ju EýeŽ+{ýÏã»{)Â%sÁ ¿*gÎu l9“ÂŽf~›õã(ÙyrÀRU_füùŽ1†æ^d¨牿îä¶YÌÓÎóa×á¬æ9]›ùí;âór,ÛÈ»J`ÚVÌåL9¢»`Pǘbž »ŒÝ×L2qÜÓaåŸ@Tßýq¼;ú/p½ÿ^³ ;R…Q*2BÈ\aíÓEiÝüù¸£�âÏÿ4\¯¸ç�Ù~l' äþϲ¼œšyp½“éGX5Ïí0!çyíËQÎ÷ó…K‡ÇÖÚ÷QRÓõçßÈCfKd ½ .¥Çßs*F¤÷»Ô1ör{•@gtÅëq_‰èöb‰é^3¦”JÖuÏ”@é7ÂN:¬à &©‰Ì)Û™áÚ²qòmðòY‡¾b„½ßKjÒý�yJ%¾Ä~¿ÆOõݱó]µLyJ{ý¤€÷úI?6Têý� ÅÊVþœé¥E5Г[7X5ƒS@T¼­bU×ûü#£Š]?ÆÞ‰Ê–¢²=Fœ’RüyF*ŒVÅ kÄC£éIÅJ"‘¦ÿËã¯1†Âpµ�²ÿŽ€¡dábŒ!ög�¨þ [à kcäzÌáïh(›+æâ ›¥šø‰õ£ñìë:P—æ>~x×Õ‡@'þÂã@ÙÕ¬ˆª€¤›£i9pr‡£*§fÁF?‘¿Œnyyy&³¢vXû ü>Àu̧®#©2 é™ûï cà¯{¢µã¶Qí~þNïöûæ{sˆw€d„H`n:È'Sì�Ý.JúÊJÂY‰º¬¼¬> f÷qE]ƶӸ_ïœ@òÎç§x󈙬¦ÃÖÇžªbÝ\3²Ÿ¿•‚B‰>Ë´ô@ýòªö<ânjûßÙõßxå®[¿ö4±XÉŽèËÒË…UY>zÆ-ÿú½âÊsÇç;6%S™tjîÈ¿‰°N{vùXçàU± uŒG4/ñ×}îWðAµ@£óÜôå9¥é0¦ì´Éô°ý`§${óC|Îk ái±?+ã ÍH8º?¸eÆ�ü»ÀC•7“tŒÇ/9,•U ãöc‰áz`ÓÒxiBa´Ô3lwažm¿7r|4Ú~¼ì9´Ê­Þ^âM]ïûÖC —íö“ÃX1ûfýy¹9pÝn16!Ü:1§:¶Úá9G¹f¬ä@^ß͆1·¸CëYYL­7.´cÚÁ\­ï°cÈè•[˜ì;ú*» 8^Óïg–¾ÚjGç΂8û¾`~¼Ÿ»½ûõqg;V’dÝtgz»K*ËkØ•8ì–?¶7Åßa±¿2&²–!Ö‡dþ“˜»ÙŒ¶€‘#,rÖü¸ø°é¾À÷3Žçì©ò[f&cªVõ²ÛgÎh?‡¹™xjIÆ+=«†ÏªØW#ýýG DõÚé[ 8å÷åÇ6à3à|Ë웸¾mþš$㪶O§+Øíß»ã!šŠ5æ¤ ŸB¤R‡åP@\PKí&™øß±¤½dc põïpµÆ€Åc‰QÃØaZ2ñ.…ø�àîL±ï÷Øb]©ÅX>e"±Ôáç™b¹ÕŽ{‰•!3l•#çt"ð=~(Ū®$ÏÍ–#y:Ê«Óêw_“K˜Ð²òF‡2æãøÇàø;97+/[q=>&ÕºÎK00†\ÏxŒ®,ÖPþ‹ïÝrD·FlO[>å€Üþ!¦bõ ëíKБæT€C*™8±”ŠÓõ÷ãd1nÏr"Û•þ@)¼Ù¾U Q×ûr[@‹Mç–Cë Œ¤ QiJ½'Esåê1Ù4ûÃ]?Äy+½nì¬Pe@­Šõ…é!‰@ÙlÏyNæ†L¼áÒÒlùs¼Õ¯NáªJ"qŽ;ö~ ãŽg׳´IìÀ¸õ1>/ãèÚ£kê¾vŸŠÇÑ諜/ÛÏá×÷b-U¿Æ÷‰‚ 9°dû%—Ä÷;o±Õ¿r)&œ¿‹q-@bó®UŽ<vX_¸Û¿w“™l½vÊ0¦W¡>ËPT̰Ýu¨Z©ë¡òÏëßtÍï¢-¦ϯ’<T×_Jå L05¯ÇvTãÓ¦ŸC<>Æ-ÖoÖK·Ûï|áãUöÌ^¬,cËÛ‚猋nŒ‘Ü^‡fö¾`º±Ï°ã~µ€ÆÖ;$í\)§xËKdkcûŸÝÞ¾+Žtþk% «òMC—m×|Üy«•ò½„é«ýª}ž]ˆÊª=iQ%©¶ �U¦ç$£]áº)­÷\ì/uü5|YùY:܃¶Öò~ÅëùJ¤» °ÇX±Ãâyzi�ùþý�Ü‹˜““•÷õq»õY1šÞgºu¾?ŠýŸe«|u´2{V¿<9#¬f^åéVÀÓʯ¼TyÑþ¯�Ì<#K·Kó©îK•Îÿ•íÆðšÒ‡2’‰ÿ×¥û‰Ô"–ó‘ÎÿI;üòˆö÷øë¾À׿óÊÚdûÛðR‰ßÉùƒ¦ó§Ýÿ´1É2©Ã�À™˜a]©Dû»]™Ã�ƒiè•~üƒ·;AV›ç%‚ºŸðˆëö䎻²³úð½9Šxì æ®�7ïX©?0ØJzü^æË±ÃÓ¬ãP_×­•Õüz èÙöŠ�Lå;…ëY{DÃØ,±^™ÕÒpÏIsÅ•À§bË[©ï�F€y覌¬—“;þ¨õK«®#¹7›Î¹�l,§@}!ŽÎé UR‚YÿÎÜ¡&çd¼£Uõ²Ó¨?”yKùö¾ˆç™Ý·÷-‹Uöžä£ÛSI¸¢—šdŒ0ºðyÃ6¬³O÷~´»î’�·ç¦/f6=?ÞçÇJàÆöõ|¼ÂŒâ®åŽ'dª^JGUÇÖ}G†‘ŽÊ—•®4| ÑÝYÍ:%{Vç§ÚaŠ¡—1t5ó¥Š!åûÎ[.öÄyÔÉ=‡³…ù¼‹sóµD+—l­ŒžrÀ®„9ö—]@•vݙص>E-i—åP—ë8F‹Æc6-¥ _&ég¿ëp!Y[c@kÌÿ"®óÌL 6ýE|i©GÏ4C�S-ôã_rЙֽ îÆì¾àã+¶Õ—1uþ{5Ûo¿á�Ïûl<zGýͦ#Z;´¯á¹LÁêùx[wo_Û~ÊÜòù¼ã�n,¯¯÷UÎïgþJòmÕÔÿþ68 ‡À_Ï–Bޝe,¯µZôkQ(Wý*�šMÝXL¢œ¯ß{VI?~lŽÏ¬}yÿ¸ÒþŒÌ2�qÉÄ•Ïìo³Œ•ñ6¶•ׯÛóýwRôåçÒ‘³þæþVŒ0<ŽÏ…§¯Åþ®}[« sæÀØWMc˺@–𠱝ŽW3ÆüyÕV1×ïÕs 9¨$(kF\¾ùÿ<Àì)`i2°›Ò†IúÈû‡¥ƒÒˆ» µ—ÿ——û—ñ÷à °¿Ã¹µ “•�� �IDAT�ªTÍØ`¿?ŽL�ÌH¾üf~7@Æþã;ÌÚ<>%+©Ä‘þî?”D·î2Ã>c¬ ÿÁ±¯M>\::öÒž)fØnùjà£>sš}ÁÕÞ^Úk:f" ‘çÇÜIHâÒv¶V¸¢¾³rÅ®Äf@k—™£Ÿ8ù˜KbHKQ2@"Ö#sùGÛ„¹tb7ÅTÓŽþJ² MIEõöŸ[ÎêßÙüƒ$Ä2ŒÖ?²ûáEÈšÌS)kýsAKtå~Ïa·' ö ï Ë˜ÛKOÅ(÷ãUl¸p ³¿3 PÑD(Z¶¤8U9;RG�çyŒÁãZôçlëÛØþ ð•íð ï…Oþ|©˜‹Úü°+½Œ¦%÷�¼>°„éÇØ|6½:Ç*ÿ¯F%SÖOåÌq_N{W³ñÌ$âpÁ öç¹µó'5¾Ø>ylޝMß.á½}.Jl|êX^@Ȥõ¾b]`L "s­›OÌwkfÖPÎàßEWØ>ߢ‹îØ<ÛïëbŠéèû3ÆJ£/jë¿ÒÁzU5ZL¹7ñ;+Jáé~¸/!š½+;l:ú—ûñâö÷—âéev-ÎÓíßDÏ0ð"ð4Òšyçß/z–z?/t9௟·ïÒ×;@ÆÜÆÌÑ=ûï¡�쬽%éiùd¶,<&ú1³*óÀ=SÎÁúØ|P*ñµ²ºåV’yl®ºþœÍrçŽèÝzhÝžtâhÕ@ J*`KµÊ&ÀfûiÖÿm,1þ}1c‡}ÈóÞ %_4`x óÍÇø‡k˜$#³óiî?Ç€Œ±Ý¾Æ<ÖÀFqý_3Ö"ƒ«ËÔâý»Ðtt~]%Å8M3µºÆëõ­|Îñç¢ê‘qWYà«r«vQ1¸ZF¤ •Ñó’|�F€·ÉHSéVåš×§¶b¿>ŽýûÓþí�$”&ÉC³ÿ'�T¿[fØç÷±�°±¤_~K b8ëX…ƒß ×;áþ¸O\_*€hw¥Ü2 âøÅ ýZ‰ÉÛ£šx×¹øÍ`¥:Ó!¿BY3G¦qGiüýæà9¦éàÊcæ@«˜'P°ÒYof_•Û¶£ãzëœÃg_¾Úµù.Òѹd†%/ù¸›^‡áÄÊ­êqIÚÁî×Vzå:’ÿ:5AÀ±Ä €™aŽY‡h'¦Öô–qS16ñ:Ϥœ±÷4Ô¥$üæÖJ)žÓ3mú^Êï, °@†R‚9ŽÌ¾Ø9³ó,ÒÃt4�¤¤ ýU¾;ð‡’°dR‹3F-OÎ(öý%àŽ²Ï©#÷¼·ÒséåÌd\ÈF9·oã6®ßìï¦]X9YþÞžu¢u $jUšn´²]CƲŸgí: €¤ÞœÙŽõaÌ”i¹cT¿?£ÊŸ†qY?HSŒud†Ùý vª˜ýY;w™ÖVúËçó³ç•i¦ÀŽÕ jx‹ôó{  j|©Ø:½ò•Œ•Pþœ‘ßY¬^ޯǽ^^Zn µ Ã3s¯ l-xÃt²z^Íù3#žÚò™wOÕxžÒx*×sRj¯Û"éŠÁ¨Œséá÷*iþÉ<cmërðùèÀß“´R±úÆÜŸL0ñw ÌzPªù/èÖõ×tžö1ªqŸ8ó¸uä[†ôòÖŒÌL_îžækØ~ HªÍ§[ñ_ö/ ¨í¯¡¼5Æ�›1â}Ff¡í?³ŸÕLÌhöùg™zˆí2R>Œ1¦ˆ´öw™b×b~êËgÛ»:4ÆøïÖl~¯òü3H1„´qèk_*qh¾•�Xw<ñ7Ì€GË™i*¦æ³w<½²~{ï³öóýª¾0”hì¦ÇMlü>oæ“�EÿjîÿSœ‡ù¨ßÿ±Û„1¦�.ã¬äýb˜`=b‰±$­Ù˜bV²pî[éD+…ˆæ®?í>`4–Øc,�ìå?·óï�Øo÷Xb³<,¶š]%Ò‰òF¬0îâÚ  òAàéÙÏv DõVh²Zg+ã‡Ò1¼ {¶b¾”1æN¶2::\<0cW~ÚôØJjeÙDc¥sÊ1žÞì(¡xLëÓ«cÑøtøùÕÊ`€Pò§²L²ÒÖãHVŒûü”õ$ºb¬œçbØ ³WxÛ’v´·€ÁÝa~R1Å>ÏÁA¿“u zÀú]:�GTåRKòn2,žÅ~òŽ#î˜Òy~‹õ²nq”hôÏÃsá�Ž×«öE–=¿R”4"2¬D^GÚc>÷Φ·öÑ€sOŠr¾|¬¼Ë(‹ ÀN;c;e±åüÎ8dÏ:î@˜eŒ½ß÷17îè\Ï^¿ŸËmé´Ãs¹rÉÞg™h8Ò ¹~IýsB„Ùû¼ž¿õ$ÀØ{þ\ecp WþXn´ŒÉ˜:–Iƒ ¼Ö (Íê¡%WŒYœûŒöÀ£2”NÄrìÙ×"¿èrñîX VßG¥„b”øãÒ‰ú> wžUx`€“b†ŽºáÂ>/÷ß*f“DcÀkŒñ¬-¦¬±^1€WÀàÏàqC¥^ª]¢!°´Ç AÇçbô¤m;Ô¹±3tï«ãû Ë»Çûx�=Ó±·/»®?âs~ŸŒ0Ûß>îÀ˜r”[›ùxæåÕŸƒùE¥—9ð?ˆÃ·RlÙeFÞJý³Ô©ÞÊ^?*=͘ãKÆÑ¡¯¶Ú¸çéYé8-¨[Æê}mƒxý@ÜŽY�vö¿W‹«£@´bˆ½>aþúWØw̤ÿ™\‹I‰Ò†¶|¬ŸTß±šyû¿9àªû;æw³b«ˆýþ>Ý7IÞ/¿ÉvÜ¡*Øó¿–˜Réâw¶Ôý®¤!ù›½ öÚgÝw¿UÒËv%[1ÁŒ9€¬Ás†ç'�2ÇÜñ¹_1ÂÐ~¡L°¹EéAdjYIÃÉÓ�ÔŸ°ARÑæÊA`Ž¡6²†1GÑêÞ rN²þiˆóä­ÿx‹’8·Ô÷\Kj¸®mo‚­%U{DMò¹íL0à°±€ŒuD‰G1Ÿ„Ö26¾$¿÷V0/:¾« › ­÷˽>|%¶J¯ÿY¥4þzÝq¾?¿+X3 ¦å’Tê¾ëöà+üWoó ¢ VSO›÷ÃΖn>ü̲Ù8VL̬Ÿw"ºUÌ3Û.3?Ë }×±t-Cìvö4°½ræU~ÞÈÙØ>:ýuœ3×ò h©…€šûºvÜü€€!ê<ðµ$6y+wëÏZ¦¥t‘ÑÕÓæg€ U½çù•ÄÜÃÈxe©ÇXmÜT,!ÍìÎ-0´GøÕó>G@-ÆâêXœ7ἪÏËË›·2Ím:=)¨%u‰Žn,Q6o`¿ÏrçãÚ—ßÇ�¦˜êñ l¨j¡‘•œæíŸŸÈ4`5³%ÁöôŒ K¶kul fqüª‘•L\¯b)?c™;ŠQ:±ŠaeÝÓÁlVjIJVBæ<`ãL1{Ÿtb°Ý�2cãëóÕL6–~ß½Ëkm,œ äkt ¿ð–¬ñ·.O\~úšãa&~Áîuã‹mŒœù¿/< Ę~óþ¦�Ñ‹_ðú¸?(ƒ¾5sÐ2rØbÑAhóEÀÃ2y0'Æûø–¤;FÕ¯cl:ÛŽÕóM9Б¸ G‹Ž¥¶“¾6Õ¾»Ü`ž®>ö”òvR€ëÔ‡ƒy~ºÞéþû6Ÿðû·QRÄ0fØç¶"½ƒ“ŽÄvÔ’‹UûxfγÀÐ룟Œû¶·ôá[±ÿÿ—Õ ¤NôÏeª¿Áõ5Mµ —\L°êyƒ†Ò\ÂP[à¦b‘uŸG_﵇þ9ÛŠõ5­’Xœ¿ÏØ`Ý|� cuc‰Uõs¿¯b5÷%—f@ÕÂ,0æÏÿ^7+tg–MFاÖh¾(‘xß~¿·å©Êoí:Ràk¬•y[€Ógü@ýY+°#ƒ‰¥ÞÍ-NŸ¾ëLÇÞà1#2à-g$y†ØZù¿³JR WH3@€IÏ0ÈLOKq ¸˜úI®ˆÆt±}½4XloU#ŸeËõÊe-™ü¥Ÿ‹ŠW9N/‚AP­£Îlª}n#óˆåÝ3ö%5hiî °°îßH&2Æ�knýqœ02Ë“ xG&2}" ŽŒ±œq6óWÀÜI%§&àk£˜WÃ(8”„aÔd@S.‰¨ÓáÏ5 œß€%%9Ù‹ýÈòaõ¸˜~ƒŽs”6ä ©†@72¿ãåg�2À2;'R‰Üò'Ýñ‹ó”|™„µ“«r÷a ÉQœßoÄ\’½¬ÕôHb@ c®W,§ŸÔ-‚ó“á¶ñx‡ï1¿«ÛµÃØíö3í~‹ó_~Ïx¨èt{&?¯ú vþ_ç“–%ãŸfˆévX /el<D&Fý$aýzG Þ;´bþóçõ㌳Š!7†6÷Ùx󌛞éó¼’F ”Èã<fÑá±}ÎÁ¿G{nÜu¢ïu®ŠVI›æ#JK¼a{Äöf‚ö,Î`_P¸_Ðsñ噌±Qr>ý•ÿÀ®Å¼Í§‡ÀÄk8¾< <õ;¦—/„E… ( [Ã\2¯êIÏ:N+f„Yö,³ ,d¸½6Ëc©©ûßø…p¶ŸúçÚbZÞò÷é1�ˆÏçð:?̸Ì�Xd,ÙXbïƒK'š-Æ ›û“!ö¢ï³¢à¬Æ;ko¬ßöV¬¤ç€Ón,¹ÊÓÏ‘ÿ¸oŸ•UÒ‚ß༪j_K æö£¼ ÐëÝ—o`ë>¿>ÓÙ©×·â<]ï¯- ¨9˜þÅŽ7®w ­Û‹�hŽ!fòëšÈv™`ª‘!öëøëñÿȦYF˜5»o0”Fôö»½žÆ CfšËw2Äî‰ó¼ €ý6b9;Œ1Ea·ÖXIRÅ#–Kô'ÌÏÅ\ªÓõåÌsgW+ÎQšÑ¾þ»+öoÆ®™dW%YÅ„Vj„¥Ç˜<<]\i½¤ý¨ƒtT~~ŽÅ‡{eYÊQÞúL¯®tUÏPÊqW@¨ìqà«vPs42b,›¼]* ÆÆsãì³.1ŸXŸœ5Æ8Ó ³ìÃxÞ+ÆYŒµ“áÞÁ{úCöVÎÅ{ƒë±þ¬¼lÓ™€J(²v9Ëôz�f,? Â¼ß1v–¿òÚßîE÷»gŒ±öTùŒÁ€’sxÞ«ç,æs»úä$O¦>“1Æ�Ó™~Ï¢>v®bŽº?Z»<�ùÞ‚‰Pq<ö«çP¯ÓÏc’­víÇŒêX•Ž~Ÿ T¯:o¥Ã�•1´ôeGRæÒxßc?½ÙjGþ|Œ#ÓŽ'ƤQŒµœ™¦%¹á \¸qjµ[ÆÊ£ëݱî÷@ì78®ó+*›C™Žû½ÁS‡>?d¤Ô1˜:6¿zÌ`ý„:ºûmVûwwý‘~wX†Üd’ðúÇúXæÉ!a޲ôêuå±çÙvÊ…ú¶bFÍ-ÆæÊíCîïAÈÚ=•—¤£¼Ì÷:j?Å´›ƒ~YÆ0ú #IõyA/Üòz÷Œ tbø÷Çd„yÀîjZ¸Ë|a€E”ÂóRpøÇ+.YÌ×ÛøŒÏãæ’~Sð×—4Äôþÿ6ÏàQ†’Œù“3þâýœ–}¢4àb]ĘRÖfzìø�±ŒiÏ_€ÑÍ–c~-HÆÉ ”{îO`ì“Z ¨›R¬ëþLà° ½ùû·$ã0&U#.Û€è3&�æKðúD1[¾a¼ï½i¸úQü>UiCþ¾ Pq M¤Ïnµg^µw%a˜/4ˆý¹Ç¤U’žÑ&`倫Ãk‹IŒ.'e8™bŠYfòÛbtU@[U~´_Æ7àè×1£)™ø0Åþ@×Í&�5b¿ßï1¼~Ï�´—ûù+ì%cv¹}Kì1(P¦ÒCOÔ@H'Ê�3@Xwb½7W¶b0Ìýç6±Þ—â,»¬›®]¹i?À抩ú±5 Ë§ ݰ=ÿ¢¶»€’ ¢cÜ:¤Ó,3v>îŽr‚—çÓƒzØèé•_ÅÌÚ5Ì]¤#–×c?‚ŒŽuTçæk>Ûƒ3÷ÚåÔ8>°Û Ï£Èæ¦ ìþ*àˆIô‡—ºC÷Gd°½ 4L)EeŠ¡5·(y¨$çI *‡òL—¥g&¥x&ç1G³îý¸\¿ÎßxYRjìyÆ8C`Œ†Àmþ|R@Ð)´·-'ÂT»aº¬%U}2~.Jä½±Æß‹ŒÇñùè·f¿b"Ø-JÕe󆎃æúIXög'9³wm÷ý¬<Uù4€‡ó¬Ç ®Óó»� þî¥;Àš:ŽÏ-_^|nù…G³ååΙ) ›½"SÍKOÇ÷—¶eŒ‡1v×Qú™½¿ûŠ »ó¿{Æù8ûù Iy y�É?1¶s·\^ÊrI%.ËÞ'LºÔ‹ËK9Ày=+åˆËý»çŽ“ö%×G{wí{|óç¼@:€Ìâ€×³nìn:&Ò³O|o] ÇÃÈy>¶Ðíz/˜-pT~¶Ï~ ˆRé—µzw†X&)§]`u0ölžc „cpÔ{i¼W8:¿oÆ'7ü¼Šßu¬¤]‹3›ÿWÓ•Žç]S—ÚßR_ãBIµ.†˜?ž+ sÚ¬#p9#Ñ›–HŒ=çÆ{µåûdã“§w-ú-2Ý´1 Q5CË×22B¯ÅÖ[7¿e~„¬r¼&gõíÛ£}ª÷¥Ú¯–D))EÞâwýÞÞ¨¾µï‹ï»íµ÷úV¼5€«$%{A–6û%ÆÜª[tûÒAæØÈ®KÌýþ3,æ–dâ´¿ÇŽþí¤­áñ)‘è™\Þ±È ûïý÷?–4âç÷Ûy-¦˜ûb‰}¿cߤâ`×ÝË©w[Ÿ°„ 6-ŸX?ÏSùTQr‹¯nÐ^/ùVÇ1öÂ<n°LsÞ_Ò‰¹´ÏºŽ;ØÇð/ú£üàXíÁR3}&µç%ºNbb³çПuÇû‡},¿¢Ú3é&[îq/oÇ2æ· èez=;ÓóÐS�ßÖv‚½sòkÇ”ãºn! œ7þË)w½ 4¡OwnÙݪ>,IƒŒ.WÎĬÃÑJßÝöO¢‘9fÛI¶”{9þèQ Ÿü½‰ãx¾Í—.–áfËû6rØ—9òN À[\ؾì,›®ú ²÷ƒI?ª}Ïpñ9¯þÛ9û°c@œg<V#9>‡¡f™4›Œ¯‚©yzáíœ+çµÝqÿe@²¯µÿ/–°žeÅr©Ø[½…ÊÖì¥U yÌ˸_=Á”´¨’ˆ®âK2yZÆdWc¹Ão6nºå³æß#K2n¾Wzï—ø¤ö 5øó~ž—.ÇØUÈZõæRšq^Öû.ˆ Ær;Âü í*žZwc «™~ë;)­Í×8;Ö‰…L,¦�tŒ§bòaŒ'Ÿ¦|Áb‡û~öĘvñûë{,ÓcÏ }?bŸõÞe0;„߯÷¿½RI(vK¥s;¤×Õ€Yej!é²lAEl鸎+Ü�vì²]>aáèËÑPwÏI àóznýñk9¯dö1âw**–yi¼n{G›Ï»½çü´(ùæcVíJÇEXdÏA‡ÏÚs±z°QRRCúÌO¡‹b|àu¯p?SÓ?g#À:ÓáÏãCH'cÿ0[,Ç[,é‹e,Æné{·T#pŠŒ¹|áÊ ö3Ê´g¾Ð%ðPš²6ì¡]:öcxàäGqÞÏ–Y{¨™tü]1ÉÐzR‹¸ý¶ùÜÒ±çª/ƒgÓÅvéÕ»{¾n×Ë0¶*£ç¦5s|+Ƙú=‘xÄý˜ûåñßßæ(¤þM3‰B{¸H>/¿Ý$‘)6Æ(b&ÿÿŽñ`†ý@»N•Ë®Ä{òñ¡‚Iõ‰ü¬„²(µöÕg;RuévÊÑ•ñ ¶"›gëzŸžb¯VVz E%7�¬v:=ê‘;˜ràAÇ‚éÇ¢z/ÎR½™ë[q=+Eín©‹xŠ1Å­çµé(—°wœW̱º=rG¬r|žÆt¤Oi6ClŒòŸQj®bÒðþê%õ&ó ™jç2ÿ;2ÃØø­�'¶Ï�;~ÏP+ñg÷ã*28óóUŽóóPõôfo¾>¸€@1ClJ¼߇¿¿ö¾Z�/û�ÊÚ ëð®.µ¿ç¨C ±/…g¯/´/'7.‰¡•Ÿ³é(nÙ ³Ùï9lÙ^ìÆXSþœ]ÏwÏ<ëÖGKZ×"Ð쬕šËa¥ÊÍûµ*ïÄÚû½Üj!¢<p…¡¬<lüÙ÷Üûà­ÝY½žÿKòÒƒ%7ÃY,¦%v|w„1ûZÄ�«Ø°÷] ê•,@x#*eàwP"¥è¤ÅØë?™<0ä™V™¦š§²y†Í‡¿¿–Ò…=±x=Æ:>Ò»ÕãÇ5õÛÈ€ì}¿Åþ§ž;_“T¿t×o+ÓŽÆþL¿—ÿ’¯„–†Ø©Ýv}Çr³D0˜õåà·Œ+¼>s«ùÔms_ð$x0µ>sæ0+‡g„Êy_ÎS�ÅÚ‡ûšyËãŸGõó­úºµç”ê›¶s«ftqf˜’b|žösìU`9pƒõˆ¿#CŒ3Í>H¿Qùræ#Æ>Ã~~ é°ô Ÿ¿u˜óò}°ñà¤ßcŒ1c¾Ý3®ötfíôã^ÿ%¹€•Þ‚ko0^b Ený˜a+§™ƒß~УÝq³aÓà¤Ú»ÇæïêùÀÏû!ž#š9…@_úóCœßʸՒœ»3•ãk·<Zš±ËÀª€ªôwxýS¤C÷§„#avQÀ ™iʰûÅü?a=¶ÿuû˜ún¶ÎSÛ›9�Ì0Å\:)cÌÚ÷ÏÿÝÒŸÒ‰w†Ø÷Ñ3;­$ ª8ОíÓÿªBsœÞï¯�·åÑà^¬‘Kã—\¢æ(&ªhç4½xü$?híùË¡sö#¨*i£‹Ã3F¬ƒ×^!õS’X¾õ—_7K–kœ!‘9ÄÇxÆáÚ•.é9Hbì™S±?¯;‹t†8¯fØÜNãܺ ë‹�g—¹ò©µÇyŠ‘ÒmLRhZ0xåÙ´ƒÂtì(žÏP™™(åÀQ¼zÒÑ!‹�™ÿýD�›=ßhÂëæ–=ŸFÒoßá÷ptrûÈøRÌ;Vn-ðy<&ÐqTý[Ý×oõÖÈèõý":Þ™ƒÕ¶ö8«ïÃI˜Î\l;žY‡A|$ÀNöa™ó½c®zOt-O7ÆêÂr¹)€p×4£X1q!Ϻ®#ÝÃòE kβy‘}Ù~žõ¼Û·Ó›Kc…ÅX*v\X� çOü¹p~<|û)&.·+™ßÛrâë±ÊýŒí®ë]­Ù÷ç%Óù§)§‰#](¸ý « ÷ÕB²œ)™ajAÜ€ßó9_Ž#ô·(Ñx»^²ñq}|ÏÅòv�Ç:–ÑQŒKøbº› °+¤ô“$=#3…”ʾÆXè¦n™«þ9©¡xËÄ`ŽWÿxŒ¢ìyDûŸñ;ßnQBŽ1µXþ#œ‡±¡"€0D>³À �ÂîBªlÜÂxÖ–û?8 ÕÚ§™UÏõÛ}&f/ÆP(¨óßcœiS@Û’<œ†�ìs†ý3Á°[̰ÉÓ@’{BLàË1Ãr o™e¼}ñ¨L¥{+d ùñ¿÷f@&a”yù&¶ýüü“ø«ŒJÍXÛpž“NìJ*âyß £c‘U±·80×0˜›åê1Ãúí¥ê9D:~¿.–«´¦ýS§ÀYd¡Tá?b;Æ RŒhC` mt% 2g¿¸=/Iøï‡tâÍþ ç¡1iÃÈøúÓcŸ�X9€lÆcŒ°1iD›ïL÷· ”%å#J.©‹È5IVô%̰éàõÏ~2û‰¼ŠÁÐeÖÔåÍÓA‡E]«¸ÒÔ~0ª˜Yj7‡PŒ}ÄÉ\*%ÞͨòÕK¸ÞJ:¦®¨?=êqÛžÊv`@×rôéØ`pþŽ+À£ÃišR;BU­¤»ý¹b¶äL†ýXbÓíï«r×nbtØ¢Ò¾Y@â �ÙðyÑ_Ù¿¶9pÀw­ŸFt¸æÒ_ÀÝh#àîëÄ2³û¨@É:ž´¤A¶€ÂxÏ‘üe9¼À£ò± ‹S8/Žæ0ggç½sZ®‹ìXAÀAm×Yq\Îvõ “JêÎvhHFfæ)fÇåûÞÀm½mñy»~ÉÞ3:V%µ‰ãÏ·ƒ†ÎbËŸÏë½[µÌ…^|<O{ïÍ`ÎcUZ�Êö«l™›gØ C}2´ØJ÷£¹“Õ|€=g:³X5BàXáów\(tÛžÜx‹ ±i93cUéuåøÀ™XûRËÏ™˜ê~œ/Ä‹ âÔ‚¥ãý(SŒœZÒ¯cvß\h¿gãˆ[”vì*:ðóÔsjVSþºÝï9Û~Häõ:nÝeQ2ßÄ}w=Jóå1Ä0–xßÍÊ¡¿ç<–š/ÿ[qbÀðþ¸˜Q³>CŒša†!PfßG,æ+Jo.ÿÀʽú K‡IûÝŽ¯š7eÀ.�� �IDATùë| 1¼nš®Ç¥=Î+À€ÿŽÒ|Ï1?ú þf|Þ¡ßãDWéG‰Äç,¦]ײþÆÚן¯c’yÀ'ž_)bÜV.F‘Nœ1Ã>î °1öyïïŸö¹@rV¾)ýøj€§|á#g¶i†Ös”‚%mÉcáuÓՀ˫ØÃžöš\Å $rve½ñ©�,æ"Фê³[n%U¸Û/x¹+f¬ÒT»­~ܽO»€/¦Û•B|Ê”â¬6b~ýSìo7€YZÿ öÇã×;ì×;�ö÷¸H?Îý7ÄÓ�“g„ýþ8îÏÿóklD¦˜“Nd±¿Æ»ï?®»K&~ùO(7š—NQ.ŽSc‰mÇC«»=wE‡@öb‰ÅæÚõñ>vô\sjó̸BW<³m&Ä'¢øPæ’låô¸—ºÞQÏ+Lº¥ú�Å•¨ØîÖ£Œ·_4-Fw„ª#ú>¨ó* Eå ì1º¼5<ŽÌíPî”ÂæƒÌ?]6áD æt%Ƙ<.‚‘‚I6n‘…ýˆMì™D]W‚‚èèbR¦ ¨cíéÍ^§ÇÛ–P§ûóà4püžÃ¸ç¿{éÅó#Æ™w|[¦Þ,©ß®ól}ì}y#û#¤Û ™{x,ƒeœlªö¯ûË<+sÄw™ŠÖa¯VLò•Ô �ìøç.ô•;p‘µ»À . —L¬*•Ž/]õ<ï2c.íã¹Åó'ÀÅ^Ä÷«ï÷ñyÄŸkKo–ž}™”7?/‰LË(¡;Ëý>ì8ð±À”2€ñü¢M Ï3âÎîy%iÏ4õù\3c°ØÚÏÙúüí¥” 6JT­ŽÒ^4=üÞQ�Ùg5ÿ‹Ç‘Ѥçã¾¼ñwÅ<C†&/Z2ª.Ã3{?,‡?ÚGù~ÁtÞ»¿ùwa‡„é°ã·TΠÑL;•³€ìI%~=¤A¬WÏPü5ˆÝ ŠwL9¼c‹öG|2ÏH¥|•d�¶û< j#ùݶ kÙóHŸ~Žø|ë–¶Ä,× Rûï ½}µùôú�TЛç½JGþóÌ7L!3Ñ32IMÅÌd 3³.ûÞEÇüÚÿãk3ä;åEÜß—WSMùÙl.XÓ�!7<¾m0Ϭaróçû5SŒ÷ôÕê»±Äx쬚 Õ­¯®T’*_ €íŽÃgßÀ_½N] àSÀUðSåÆ~Ÿ×/JD¶¤•ÉÂÄï©T"aŒýK¤C™]ÀM_Ù ›À—Ž~ã!8î[ËË^g%oÛ?ckÙï÷߀°L¢q5ÉÿÛ?Ìö‘ÏÌ&0å´fW>­‰/_!Ö±÷/I'>kŠ)òµOó> Çöò•²jÅÔÜv¥x©0–Õùá8y'¿‘K-. ®èÂ}¿ìBî :®À„åô€_lÇÞŠÔ£t”*Æcˆ¡j˜ýõ`@£†ã”KÇÇĈL‡¼Ÿ³X(vû³¤²4C`2Äãm°rg1WØþÃ]ûéƒóŒaÇc õèU±Uby|ì­³p¨+¤x½#`{kÝQ!s3g¨i³åÁrF ¨uÜ–ã±™Iìy°úÆ8SŽnl^Œµ;2›j›€AdÎpi+ Tî8XNä| X‰LÎèå¹™¶|ÇO�2 6÷ç8Ô­”�×¢½Ð±»ËÏ#yeWø’÷yñøG  K¿¸­ûUa½XLø~ÎZu—AÁ16ÝQäŸQkJFIÊìùÇæ œQŽJ ¨p°öªç«ŸéÞl~—E>à×åRu_Õ}˜VÏ»’ÒÏÎpžº¦éóZºüy¿ð1·f:×§ç‰ëøŽ£Ú~7y`K[µ€Âc¢½ÓóÖÖ¿u¬¬7H'gžñPÓþ]ƯÁϱåx¬–¸q¦è®]Á¡ö|:ªý:@7]ÈoIU"cŒÞßû“àáà}àç¾Ò‰vËû?2ØVyðøéL@+ïQŽ.ƒ)Ž/¶oõ¹ÈïøÎwF7–ÓÏs(÷bˆMÛÊ>Šß»öA–täçûò2)Iõ¼}‡t`U€+gZaL?”ú<´û¹ÍçÇã÷ÈUóõúïÀ KÞKŸª^±þ³+ZÞßU¿»nͧwbþù|¸õcŠ¡DâkzVD€ð¶í2$u»ZûQ¼'"`¤¤ Ÿ“¶ìK2VÖUl²Øú&Û©'QYßíÊ™kßd»+�+é5bl0jäw*•˜0ÆT>]Ƙ2Uog–!6™a9fدæl”DTf)„Ùó°AïÀÕ'‹ýåò5Ì/·½`“)ö2ÇDùõ ÑýOÚ7*ØMWay”M‡Ž—Nüêù4ý˜é9êïíbKdWÞsÂèÓ©l}î)ÎI|àq[%E%§,€¶˜ ÀâîU1Êâõ~ÿ^ªR¥£b¢Ô ÌÅo5ƒ²ß¯vì(Ǧ‹7 r¦ûÝS1yº5_±B| ?3î'àõ6n±‰�S1T>=#H1 50¹öÞÝþ99Û§_}H¢”Ý­œ>Ñê×'á8>7Ç-/JRF¸À&8UÌ'Õ.Ò±÷ól€žUkÆ\Ãò!Ж›Ž5÷ý�£Ë—Ýû ,¶?Øúòç)g–0�Ò3V|ù.J‚Ç×”0-Æe¶ñ÷*zŽ0OصØ?Îò—¬kà@ÅÞ:·Î«¬\ä Ëlê9¼Ÿô„€uÊÇÌ.Zסdâ€3@iãYK%Z%€¾Ô"2îê~€Ž~{Üηoûýb¹JW¢²9ï­?ïPä ˆvgš¡ÖZÚÔŽ_×ûûL¥Ù}e‹7—îÅõ³îaŒ;þ|å Ó1ßqÏðùÂÅ#ÍËß{Ö½å¯×{Ý…>þ<”¼÷û‡q)¿³x¾$}ÍÁ¯š[™™ÎÝK:^¿ì GîÆc11,##ºc£côþîÓµæúç HTN€ìó"çoù|fŽ«Ã}\\ïýü�ãAÅSÏ÷ûèp¿:€â¶²=Æò ÜR™ãcIw•/l9—bF=ÓcØù—Z ¿±ñæË‡ç÷´ž½6ðªÜ¸¹†~Û­‡Zgºì~G&gdFæ ¦×àù;€la3f؆Tâ’ µÀJy2 ±cpèÆìê[5><S(Æêâû±Æ³=|Ûg†á¾Bú1¦°þ½˜~hJ²ˬBûÖ”Co�œ×ùí¾ùçKÍÛc$ÖõÁ˜zÕ— <) ìŸbßmMŒ®qßwFbz©ü¾ |QSåÁrÿ2¦âßw&د÷Øa¿>˜aÿ~lÓX^Æ,àô�¦Æï…ÔâŸáˆbtYàËJ'þ1�6íûð�]Vî›ùX Mq4”H,ƒFÛüìï‡ðA8îÇý¶(qx}ͺùáqü Ô�N̹ŽyÅ&¼ë6Æê¸9‚ªX<}ÆAus<iú®%U:èèÒ ÓP1äìÕ³]kG&2qº–÷/K«JíÒvás€ŒõkVŠ(éåÛ¥ó°ÕvÛ§Š¹ÖµÓgd3ŒÄ8R¥³ŒFg5¶L¨U_>ÅLÊIžié™H+_/Ñg Tƒþ>èqV.û\A)Á mIêÇÊÇ€Vw?~î\Õí% íBé_ýfÅ\B†!:Ü+¦,òÎãTœ¯úç™ÞÇçŠÝÇÕù…3mù;’BhȈúú áç˜.…Z2€L³ê}TµG½Tƒ•32´j`ð-I¯~Oz©´#I!gâFóÏiš C»ŸßX©Ü[iõ y_ÎZBkˆ}o5CжƒýlÀÃí¸’ ÏËÑUù}e¾Ài-”Ùsð+³1¸|ziº †˜¯Çº¨Ð±~Ïžsë;iÞ?Ôö¤òâû_-(;¶¿*æ¢ï‡k‹�ÛŽ‘1Ã<P˜¿OX¾9ãrµÿûè-,EÀÁ—Û;˜O2?j ìgÙbRÅü±Äö–R ãùã`TŽ3€Ùqø6x}²þi²ƒó¿€5c¶½3€�%ë2�‰1–$og,¯f¼®qhêƒLGµ2´öƇn*Ç-¹Ôwì+Ç®—ÜuÇòôÑŠÙÆR|~âû%“F¬æ5¶­ëuý3 t¦÷í‘î­Fßç!ä7¥_-C,É×KDÆz,iQÛSÎÛWcwq‹ #TŒ¦žd] ¤Äv¾ý}uG÷1d0=;°{~dbõ¦üéèû† ¨ê¾øô¾pYÙGû©zîÚnŒ/VÒ“±œ] PI&îRî|£ ^ôúêwRÞ1ƶf½¾Šm6í—±$o�Ñd†ým€²0õWÉ £±¾Û?ŠÃmc¬1[àïUºûï㻑HT–sXÑV}€Ír^üvÚKæØ¸™¿"~¸àñ=ÓŸ¯ùÀA¦4Ë“‰‹,«c/ñràX6AD³/äUoŒQ£6eŽDÁ»rPp\9Ü[)‰Ra^ʬ–žŒ­lË« ~¼+Á·ÒáÀÒW¥„v%¾ôõhµh¡ÍU¹OëõØ“!æ·X µ¯Æ—×ÞáŠ1îr†t'¢£þ€„—uüd+­}ŽòýÞK)"s¬$²~š,³Ü�;Ñ&eŠùVŽ\dr¡1€,¦ïï\ÏÚ+c½“tíñá®óŒ)&Æ>ÜÐî˱ž×#¯j•Ö¯˜åÈ>Œ—$o¬·³9žTyAª”õïN¿Z’½?gŒnÑÚïÁM™å ún”xF†R?¶æ^;ÄùFö¼`ïwæ˜ß‘däé,Ƭø<ÆóÔBŸ·aß?ë û\±ïs5ÿÊæ8¾.å ¾¿$ÒoÖ‘¸³¶„÷bzÕó~d†{¦XwœéÏi ¦)Óï¡öpÝ®BDŒ™‡L1_Ÿ O¹çû\’”ÅX⦔A|ºY¿d@c@òvÈÛ׺¡,àËï%*Uèÿ«uëhšá±Œb9Ô>Ú¡}fe(áÈ™¶kßÛtHk€!:ßéy= j´Ï‹cŠ ”šÝæ N¯†ØtÈÛrfíÍÊ«¤í¢!�æ<ºŸõ$oµ$i,?75BžcPêô}ºªÞ}†×@z6†Ymtút3©º9~üuuL³kÓ"£jµËì÷›‰sû@~¼\±òï[|n\ÓçC§`=YÿÿqÏg‡Ù㙕Ó*FOΈŠ�¶£!<zßîøùñ�€ú rãý;JæíÓ—P¬òï2­f9‘©Åˡʫ¤õõÕy=`UKKâïÏÞgxQ`)aráï*}´V,/•Þ¶€ZüQ[’‰cÜ�¢_ïÿÿjÎR1½ ô›ÙÎØaþ¼ß!?%ЦiN"aréÄÿšýÊX0í „x£Úé*¨4eŸù ]D[11Ô‡q_‚„íwc«U‘ê•nÇLJ`µ“í¯˜#$i÷tÔ ãå]´§b"í€+¯ý"2Œn¦”å+Œðx Ê]}+C ![ñ¥yÌŽ´N~^o¥'ÆŒê3žÊ.¥]'õ¬¥rWð‘0ÿ²ûÊñâ%OSì“3¤Ô݈1e¦éöV�:v»ŒMߘ?tV¹¹äÛ¼.2,T¹°+FØ ç猰ý°ÆÚ¹#s!À{ž®óñø ž/þùÍêõÌêrºžŠá¦žwŠ IÛí%ÆÂSL°ç %Óðx﹯¥3«¼äýõø8ÎÎO¦ƒçñɳŒ9|Îké¾³;o9±ýr& /ŸG= 4–ÓŽÓ¸€hŸ-,Ð ~Pª ™lGZîLbzÐCï0uÔ´Cˆqæ¸Ð‰·ïhÿbmßýçûñæKÇÑàâqu­G*‘زr&^Ö.v|D†Y?vë‡ì»…}2·qÀóßqb¥L@Ø\ØiÛ5JJÆòtÖ>–ÇÛôøøñé(»n@ÂÌöŠÞ’Šþwø•^×Ô¥RcÏ«7º¿ŒQ±]ðUÇæé�d¯/÷þòrëçüQRÊõÁ~q€í5iYæ·ùr¦ËÊï|åŒ"m¼Í÷ 2pžß‡ŠQÔ‹õU¥=ñz4ºù³XQ6[Ч³oµ¶{~1Ï;ù}]cø¸þM˜„ù÷ËbTô¼ž! ñã~ýSdŠ% ¶)øR3 y»¿š~Ê)Ýß#òVŸþp_ϯJÙ¡©ž</Þ’_ï÷*&ß×õ­�öœ!†Œ­.`_3Ÿð÷] å]&]7fÚ^~ßÀÊ/í¶/‰9ÆH,dPáïCüþÕü•U±Í”U@ÝÿÅü?%oŒ±¿Ç¤þ} þ’F¦•’&´öý€ýþØÞ,2Ç0Üw ±ÏÿÝöï�Ù£÷ã¶\ €ÛYÁ·Ì}4b8þœ¶4.â¶£óñ´îð뻕¸ƒŸÕ³Z!é-ƒ÷ŽŒ%¼fiðØKþhà4û°¶Òm¬¾ëº¾kT} d¿w.³¼¶qå?®ˆŸ™m,½Ú|l¼8*»)åÒˆzŸ•&î¯m•ÏdŠð˜P(Ó M ÜÚ~k\¿f,#�ÆÎ(™ø)€¢O/=8ûJké’D‡ìÜ2�Ä–bÇA’Ÿœ ±­–ôØt,3`=cŒ 3®ûÔ]9Þmo‹)2Lý0Ÿ5.OÁ1í€óýwß¾+]Pvß'LJÒÖ2ÝNûÇeÆ”ÅvÎú1u\ÉÑÉüb÷™ñŠòi\x±âìýóU¦Ø¹<ÂôóEIÄ=Þµ£˜¿=a‰¥Ÿ·¾ç-kwE¸?9Òíx˘螙…ãLt cyæ8À…7ê|À­ùjî9»÷ÈúÝ?G/£Žy6F¾Î²³`¨~)û9\Í.ðv)fZjo&9êa‰B»l‡©gfL+…Éçç9°9Ó½ $Ef×”nÛ+7n9£–—m=ãqÚr¸{Å“ ŒÏK9^ò…8èÈ¿ÜÛý9ÉÎåþQ1Är‹nÈ‹;>àx´ÝX]=Çá>Ìw¡©]7Þ¬ÖÁ>+8A¦LÕoq\u¯cö:cЉrÛtgÿµí9Â~Îdš¦%Ûyæ±W|X�d:úW?ÓR­ö9±+͋ǕÔß2Þ“;’Üz ‰L"ϦóZ¤³Sì5ܯç¥# Âþ¡˜”·zO u™ú®ã÷cÂ!K^¿Â¾3ù}ÞÏš�ÉwÆØÓL42«Eß6ž¨hÀDëÆÊªÊ© âz´oSjO+xü@÷•tß´oò÷Cì‡èªöí”ÏrÈ1ß®§[µ7¯¿Î¯{]=CçíDë‘�YÈ�K™c °¥€«)±˜šI·ËðêgX¿ ™x³_ï’ˆ?Žüõ8®�©]f׋A6ÆŸyF¤_î ¯Oh¹üï’‰| s,c’Yˤ"vÖ€›ŒZú<Ÿz˜çûç?¿ã Ã'ÚA¤V×cØÎÜÎÎ;$Ëñ:s;e/þÇ>2[.KËØD%ãì8Ïw•{ŒøÁ®ôj¢…1&.°_K#ZSRŒÙ¦ÚÇ_ %jìWBó³êòG nñ Ò娮?%{y ð8¾.¢=µ¹t&06Àqƒ ±O]Ïjœu>ü˜YéœîÏwÀCçßsðhi¾ÛxöL(ÏYÌ=_þÈ„óŒÑ~Œ² ÏÓA�™³ @šõK®?šç€9ÀÈ€¨Šéf38ævü ¿ŸÇ}¹yR 0<žcŸÐ 6ßf¸œÏŸÇšÉñn~ߟìF•›¹rF׳ù^dKU¦˜`ûb‹<Õ³H%Ö_1 3¦E´cpœ[I¸Rª3W’Žg9þ˜¿s³þkç9ˆóµÅ¼ó�|ÞOPJ®^h¶ZLí9‚¿ ½ªÔºÌÏ=L!Ž û^Ží£ÌÆް¯!4õ^ç�w8kIçºý@Å€±Š±nÓ[ ¬¥äPÍ—¬c]I°]Ç%<?”M -ŸODÆ‹ßß7˼ˆn Œ-Æ-ºn[Ù5Ô«²ž£n_ÐîøäuÚ¬ôÛ«‘6³¿³}À*å‚Û÷hä|úï“—cñ¼_­§˜¢·qvÀÌK,2Á²7±ïB.­‡Ò~p}tðOÿ ýõ’»¡Æã�÷bëEÛõV3Ãòò<“ Óá±Þ¾Îü‰’~–á…í°Î¯æ7XÃ~È9nÌ1ÿv/!~Œq¾È<p2Ä>?0ƒvb»(�R—ŸÏPž!¶Ú˯òÓíù{–‰’³¼º½& Õ•ü›é_a?·oÅñšÙ4ëáË»|r†Uû­/†¼Ónuz‡ÖußäõXþnþ@Â[æøÜ*ÀìŸûVS)Óë æ2Ü*éFZŽ_ÜOÈúuŒÀ ›€YKlŒ#ë1Æow‰ÄÈû=ìÿ÷€Ù†¹_7Ît™Ùã3¿ïw ÌJ&f€Ý´Õ=w9VO­¤™Ä—g7dŠ= apj•/—ô©d­¨�8¾b´’P9ÇÔ9|�w¬#£>\§õV|óX<ó<UŽ(ÁÈ%+GÇnç>¶_d\p&F•NÏ1Ò£_w7!P±_n_ž¾"+Å3¢i¸ò—•ØJ„eýÒ`³4¬?,/u}Y?F 9‹åÆ™@çPîù2Ê* †}ø_„Áž‚ÈŒâõá’®+½séHÃòç‹3<WNt¼WŽûY®èˆç ,&EÛðTýn�¨l×Ý9Ÿ“¼¿™£”½\º$ƞˀcgöxf+_ßójÇxþ¤´íÇM=½tàWi:ý^ •Ðì³0Â…0=³öaåÆçÝ<fþ>û!™D Ú¿¥† V¹ýs‹§Ï€¡H;›£ÿÙóîó +ÅÜyŽX€©•Ù÷k/’îl!»ýÙv,¶=ÓëMSä)o¶Ýòúö9Èߣñ÷¼b½Ž´Ÿ°gïò ›ÿú>ÉÞg‡Ñ'Úaž½×íw¢­w-ÁQö<ÃíÏ%~ގˆgp^Ýu]¦XÓ¨rÔï¹ £]¡Æªþ}wgŠ-ãã… ¶ßh‰½hv¾u ÇSiÄG¾Ÿ—Ö{Ê·À�ó¨÷ ?®™qððí†Ì;Ö^Öpao%-ªÒy@/FQÞÃo¥ËP¦™aÐæ¬×Mà*Þ/ɘq4mÿêrWúÝÔ6²ïÆøSý7óÓXàb]û(ǯI2Ã>ísÃç€qàcüñˆY¬^«}±ó8o¿çú‹-oÇúÌž*ÿ}N˜Ïï�[”ÒS±ª*�¬XUíó#ïJ^!Þž&´TÕŽ?0Ãú~k²±°|bð/»E¦Tbdјb0û§sÝÏg*Æ™a°ý Îs†€ßÄþ~�_ÿ¾_KBÑ`¿Ž^l¯ßû7 Ä߆6“>e‚™ü^~ƒab÷í÷—ÿ”Ì6kUéL4nϪë~ÖôÅüÝ·9‘‹Œ¹ü<v¤fì…WóÅäB�JåéØôøÊh”¦‹Àà.Å}ÜË™IœekÏhñ¦Vd_ Waån¹t˜îKjaÿBÇ— íš^éß¶¢#XZ¹´äÚ;‘£ýš,fˆn‘·\h¾P:ÑH*vÕŒi–;æ ´ë*7gdŘRšiÕu8{ÀG1.N®ü‘‰¤ È]�ØÒí¦Ûý–~dJÙ|c;p�`9¦Ï­|™u>Ð9u&Ç{ ;C,“n³ÏMɨ5ã@`XŠwò{&•x/s!ƒï)—ôÍËö»vÛ™*—ÆÖ_NtJ¯ÿ:ãSÜ{cÄ«”D°Š9øcv½Ÿø‚ìzÖ_W,ÍÓ£ß#pŽ6ŸWêùX=Goí™Ë;ÀøÎ<2s<]¡GEÇ5Où(æEñªgGžمNv×”4[üîqõ›Œ0TÂh+c àÆbç U.�B‰@,7SrÀôí}öçizϸ‘ÙÂ5[ÿjÞ±wÞzryGü¸ç›—×z³¼¶=®¤½ªúçæR»×GÇ+JôåÏÿÚÎkxx�aùº¿ð÷Ôú‰cÛý•ìß�%evuìNyé¸TRˆ/G9ŽßÇWkÒïbVb~~ŒiÄûþxÇ A¬]Ç”õ _:Ï=¬³.C,^W·#;?æ‘ï‘ѹÇtщ ±ÎÈ@gwá¡o—(Eiµ:&¿>æ³úaõþãØß¿™’L`Ìïñ’ˆy¹yùWz×Ƕj,‡­÷ræöp¯—0ÕåxÖ83J1ŒP‘ˆG 1Þ³ÌJl/e‚õŽõÜýí1— óó˜W±ÍËý Ú!¶£žr É.ÐÕmgì—ðDJ:�ªëë)©ÂßÓë0Æ™äɦêebøúë±?†%æ1‚ä¡=n™\9�õ§½Î1ÄÈõŸYŒ²ÿŽ€±)•˜rÌp©=ÎW ¦Ÿ~’‰Êas³>Ò¯Œ¾à`מbÆÉÚDÉÁi—OË>/aå³¾>[9:¥+öE¬q%-Ô›È+óŽH]¬?–ÿ[1H|{ô$ ™ä³¬k*6wØ<Ë“ˆŽÎ^,±|ôZSŽå%ýgsŽgfK„R“Súé˜Þ'ûŸ^Šî4÷ C ‚7²¯úqt +&FlO;ÎÎ [éñ‹”<kÈÀ²õR1{ŽðûЉs�· .áùpv×]À‹n ¸Ùvº�ï¿{¾ãq}Oº­¿c.Æ~`ë¹ p‡™’]ÇÊ9^N­½nÅ2ãVK%úyIt„÷ž°ª•NáÈ Ÿ‡ÝyJŒ~õ=¡¤}×¶×^µT1o§,ÆdÕßY 8_bïÎ<æ�»¸¨~­�� �IDATÏ�á ÞaÒqŒ1Kçæ {Òƒk^S]—1¢‡ê…_¼ÓÓ_ÿsºeŠ?#åƒÑcŒÈ«öƒÅØ9\".»Þ:œ­‚Å ‹ÀOæóª%Wû°t3ÉAd¶yiº>sR)fp&×bš"°õ–^ÓÇ–ãë̪e¸~šƒ9Õ8ìÇîºïå¦=Ðãuû P¯âFËr-†˜nÇ78ž=_mÿv6aèù¸K&Z‡?—lÃçôÜ^ÁÑ~€úÔõ³f¥Ò™ÂßÇ^².„r&çŒí÷µ÷�:Ð?š=tÀZ%Ïóï^¯¥oÖPvêÝeÌÙØp|>…ž8ßÿ2†ïïzþlG{èbÙwËÇï+e_3ìåu¼²ïâ [€{~|~3Ÿhœ!V=9õ}ÝeüÍú0C`NÙ·0"<4ªÚñYÆXdPõ�ŸÍßUºßÊq§b‡aù°ÏëSÅûyæ™v?Šó°Ý¢='íÙgÀ©Øph]`ê_cPéÂ4†× sëYK^$š/^¯¤£d⯽ ë8΀.Ëà" ¯1îŠv¬ó)àõÇ’J¤€™Šqv«úÿ°ö]' ?ØæX3–jé›m÷™ß—NœG¿Æ9„ˆÊ‘”K(>SÿÎJLkèнY 1à‡2JƒÝêw‡Ht€ð•§1”ü™’@(ñeWhÛÏ$å°Ê%)¢ëra§}ƹçêºwr×ÆÈ™Žáç`ܬœç'Ó9û*—³ÛßgŠùvª$ìqÙRW@hcŒ|žC¿wç ‹+–Sµ+2„؇öîÃùÑÞ§§´z;$”Nä±³.cÞ¾Nîyû÷ ÚuÅÂBæ‡z^X©´Ìý§}Ɔ2öÜR@Qd�žÂyPoû9ƒÙ©ƒòó,Ó™¿Û|³­ÓN@ˆLáþ;n¾ßk@N=·ò'RÅ£×9ò˜ŽûÌ0|Þq0–=÷Þãýð«0ÞoöWýÜ3ãO­•ŒõõŒ\#‘?ï"9ûqt Œ3îHD q2ÚyÞC2©»È « òûÚ_"ó[¥‹’ÈÃzkwò”HtöD¬dŸïr/îAè¸.FŒ˜ÀÏ>ã Ïçýsõ À!@UË7wùÚÖØ¼Í~'©…ê÷ Àó–3¬ºv ÿMfØnL e_ýuñ¾¼ýó*ϼ+bùQcl¯h¨£fÀ¨ldˆ™ý.ÃQI¢Ù~Í�26¬[š9È_I;T’Š–)V9öÕøfí÷̼]FØky¼ºÃ(wé¨òúí«�"ºÀÝkØ*`M@ö¼›Œ1&Yè c{ùómùÔ<Ç39ã› ûm'ùûdŠý0%ñõ‰‘Içò}aí�5«±>¾=ùBˆ.0…í¯$F£íÅpÒ "U ‰±rjãÀà.Pµÿ{~ž¾Ðª… ”ùý0új¬@΋õUÌ7ÕN½v«%"Uû¥@¬Àž÷»Î�NÿˆëÐÒXd_ˆ)6Ëóø=‰!6c„MFF·ßÿ @”¾2×ÍnŒ°ïfØÚ*iDÀÑã/ÿy�_Œ›T¢Ýgåf†}±{µ�!üp4Ò"ù‡*®\U}ó�Á³’*õŠ6ÌõØ8Ëw¨¬q"ّزù3‡gfïp=/gÌ} ^È6oŸ+Ã; ‘áá™6,ÌçæPŠÄÝzùtjËîSýt ¦wUeúüÜ!¬×Ÿö+6Ÿóƒ1Ö7ÞÎKb‹²@d® `Ru“uúÔL+dÎŒû~¶â>>Pšû'7¾g¸sÆrб¨òv±Çó•¯çÒ!çbœÁ¡b[­vúÿˆ{›åXnh”g6GÝÒKÝÝDŒáñÚçµÇöDÌî{)©[g¥»èfHd`Iß½X¨TükV‰d&8³1:°ß ½=ÓJJíXT[e¯÷öŸ�QÕï&ãÏþ>ocIPú;4c±z¹À˜Q’ �=Js¿·å9ƒCÅÇZö9‡Ÿf¤òþT Âu°•J…~–)¶Ú·GýåÙuP1 ØØ06Tª<ÈÜÎ0¬‡Z†›òYëØí oI6w%¢}ÏÛ÷œâ+�|ÖD9(\—3ÂVýð?Gþ\VÓxÀ´í:ü[R«(‘¨€° €¬Š)Æû÷5\ç5,¦ÐÌoO©ÇÉ\Jñ$Þ,v˜eP"³m2Hæ>ÆJ²åfýxšŽ©Ä‘Y¿óõîõëØaìºÓ§Z7{*\Æjl«Ê©jº+Ô´Ò?ÓyðI~ß»1ć/J æå+ì.øtö�¾å÷*³,Oá ž§ëckŸCŽ9Ê•ôš½În_FÎóíåYدÑiÿ£±T=ðø“„p9Ðô´ È]Å}»o ^Ÿ÷�¬Õ@˜ú};©òÒùNGZÒ2«¬t£b^uìǘ@Ø*Iœ±ý—Å #1ÄFZ®w�N1ýXÏȘ›€Þ€ãcx€ ó>ѱ唋•U—`øÊË”£1®Ô %ñ·›Î®å@Ê¿f’ùz}/Ò©êÙE6šéìI*jÀGȤBà¨eðB‰Âi&&™‹Uf€² ˆÃëéyc»1É(`bÖn€Ñ-¶ØŒ1öÓ¨cpYà鯙b>Ææwk`�Ööa.gF2ѦÿóÇnùÞ·5pw³«X¡e%UØLM `æ¶81=ÁDï¨]`€ÝM-rÝ©î>Pñš^'\]É>�зɠå Ä•¨~‚šI &’òºódâf·zCyÕŠQï°ç’AU,&Ùö6Ûÿüèß=¦X4 <vêqÜ-Çèyn¬€ß‘Z�jt°*˯Ϝ1bŒMûÐ�Q×aÅû©–Pœ-™§ŒÊQÛ}~;ÀsCVŽX¬7[A¨˜öþî{G­|W[k–9õVBÐþzªœX_Îl|®hÈ�ví$€Û tÍ~1¿Àp¨7ßÏÊ7F-õÇ$|«üØù·¡`9¤§aTúmŸQ¶gš ¶7>Yßo]Ÿ·_ÇC»}_1&ÜçÍöÿõ>Áç#/žÃþE¼øB¦*½Y¾e|AÐbcµ3.¨:môµ@Êîö÷ªÜ+%™?A•ƒ>JFªŒ1´4b)™8I^ú0“F÷¿Û¸ß7`•VÌüžÎþÈŸËÕ“Y8*öc ùwQź”ã 6Ž8=Êuýÿòç³vSëòs1ëx¼/h5è•Wƒk [Žè»„_Qþ®;02ÙriÄ]Óí§€1¾°€ñ¼ão…¾-—}øùïû�{8¢ÍùL‰b Þ¿c)3¬SîCM=úD¦ÐܯÈÝ ×Cl×l{Úzuê×ç<Û]éI¾m%~ûôØö$‘onkßëÉfïÉXþ ¨»Òï�kçWq¿MŸÕc>Ï™_&;þrOùÅÕð=\o¶ïf;îÀ>ó÷ˆ• œ¹öž› èqfØä¾Ü* gzP3•<�¶Z÷ð}áDŒi&Ñ´]˜^8#ª–¸Ü-GU>o•䪒äÄtüóù½<®îÏËS›Š¥¶ËœS†@QLh CììxÂà:[¬qe¶ýC&÷Óð±Ã~"±Ã|Ì1ÏØúÙlǰ�Ô¯ýßïû~ëìÛÏc`ã¾ý­!ˆ1ÃþºÇ›×ýŒ±Æ†úÐð‰ÃI:é@%õ‹Ã¡JªåXL±c¡ã3ëŠ"ñØeº{R)Ù RoK:¬g=àa9H.Å€d1t8 QIzÇÕÁ¶õ»+ðÀuÛæ®öë[W¼[KlyGO·o>磑;b¬n±~ùuõ4–;$­”ßgL9΢£ö"ûOö{Ø_ya¯Ã��2”qÆï§ÌòþŸ3†¬TÜÜŸÌ%ë€MÕ¿ûÌ²Ž¤_']Õ.jóÙM¯ªßl¿@¥)m;?ßßwÏ÷} é÷+à¾ý]0ýôuŒñ|ï¿o#lÀñ Vªê¡ßŸ“HÔ½V]‰ç»uŠ{Æ�|vœr‘¿ð1¨M/ôðí L°Ø¡ù÷Y—Ú•ƒ„}_õõoô½‚@±d,ÓÅ:ÜáÃ(Ë.,¡–ÂÍÞ_ `‰Š¬à¡þ³¯†z÷Fø•„[ ^Æ83,¶2)ê… ·SrŸZXbâ3½Â›•nÃrX7GgÙÚÆß¯» Ã3ÕÖBNÿ<žéóQ·JŸŽÇ¾Ý~•{kJž §^›9(aª÷ðœ`¬®Ï‰~*8eW2Q-<½ŠãÖX?ÑÖÕâȬšç_éÕ1tÁm\ïËõp ß?Â�”ÙòfãÊ(¥ Ù}ê¸í'3=/½%wÇÝ·T8p*¿,Uù£Ý×Zó œ=C¦X‡Iåï¯Ê½ö¹$_”:´íÛ‘ZDcý뽸Î^?ûáÌß>ŒÑÔ×aI’ë>î€1Æ ûè«ýü—…õ—½ù&J‹™÷ÕÏK_ºñêÏ¿Tuù|ÿ­óï.xÈß™Ï÷âüx\§ö{̲ïhâÀS÷ ûÚ¡Îx=~ÈúŸ¶ÒÑíK†Æëüõ?x{@jšbZíÆþú_ghD²‘2Ç’r¦Ç¿ý?Û?Åõ4FZÄ&ìo’Ëïc1ÅÖù_p6¯ûkx E°~~Äû㤡„¢Â&0ö .k–ö�àf 1dŽ}û÷ø}äÒ{ùÊW\ G6JR„L{À×´Ý6 7Ϙ‹W%˜¥æôlÂu"zëp©™b¸’ûíîØÑµ¯Ž£ ¶‡]Yºc¸‚Û2»Ž_Aí¡³)6·å@É"ÏäÀèØÞ:VÌN{E$Jvöú{ìÕÏn«c–äŠ1bÛ÷ç䣱Ä"àè™ö=Ñ•ÂÊžƒ·%Eèj1… ”!  Òë�ax=2üvšood0­^û w½=$üæù’–3ceï7r½ÚG«Väbúìz.»B ,ÎvâŒ6¼þYô‡·²þækg¨}K®sû¾ÿÌt²ç7gHß °ÊößùsqÀÕç#%ÍôŸ7Ó‰€>»OKØ-ÛûžV’¹ SÒ¦1;c’2Id4ïð_Ò‚ü=½~ß ˆB‰Ýzá Ž¦T搜òôüshû‰}ÏÛr1G®j§Æ;Ð;‹”/lû!8&ž¿ªét¼Ž>á[1Ãx?õå´Žþ#ãÚ)Ixºß}�4q)}~ØlË'T ã¼cdŠ™ˆãmÜg�Ûiäï%íïhÞSу5ïç—Ö{ç4öÆí�0K¬ûäÔzÅ‹RrÏ;Nð$} ´ =üüñ¾yæØšÉ{¦•gF©Z‡y÷g6¾ÜúûDUï�j¼zä"3g:Î3¥ËXy7`)ËG¥Óu¬Oÿ…}y ¹7/1¦]éþqëÝ¿+•ˆÏ3JêazUûF Ãß_µkO Ôê˜WZ:Ñ1"Éýª?¹çåDG Ë«ü¾Ø|pqÛ׌‘UB”H|`lw¥N®÷v‰’ÙwëÁ¢ŽŽF:Z2µÉÅVÜbûê'•í¾I&�VIq~�‹Œ³=F“Ð8³ì»H™V?dz9ð×—6T±êc®Iwò×í¼ hV̾i-&Õ($ ð4Ø}#J!VL¯™~UNºþg·˜ŽÙ:‹€Øß#ÆØ²@ÓÌ~ ×ýÒB€ê&U¸€//™øk#ìã¯ÑŒ!ö¨ú¿ýuÀ›f¥:(]€F'ŽŠöq •ž”CߎrdT;x ð(73æœe\!–å×q[‡ÑÍÞÀQT—³Zéí¥ZðìÚΕ©ù€':,mþ6FÉ#å’�w~¥w?ÆŠ¿0Þ¾ãªÛ{¿ŠQ± �¹ôæÛÏU1/"c¯Úu|ã{gõ?ÎL¨cÚDS�‚eÖX ¬ <¿Œñ�PúÓÖg ÞîèPõõXÀŒg.y‰¾g�nPZ#„�‰½Ï>7ö¾1bl3õ»3` ˇù#pcÓ±åbõ²÷{€lÆÀS%}†ûž›ïÕø{+fØñ½jc¦ù�ƒñ ÷µˆý½š¸z[Ï_?Ïr�H½aj©Fõ>ëÅHÄãG%ãÖïä™Lu:(ÇD\K ±õG «ªGÕ>c()³³{Ÿ1iÌÌAÓ}~ôsÌ ¨ño”˜[9øüÏ0Þ¨™Ç~\¢2ååRfÝ|ü¨çjA¶kf8~ÞµØ|ÿåø\¬2Ñ£Á­›mþ–‘ÖR˜Û¡«Œ×ß”<›1€Îôùëü¾¸í…ìë`³Ý|{°ßóVžKÈÏÞ‡ CãÌœY…ÀL7Öä 5ay;ö^j2ô�dë)=Úuk1Ã÷h´ªý[;øóÓá®kÌËÍbáQûð€ïÓ=¦X—)£ë5™x‹‘ç™b<Ý,fÖ‹»¿Ž½cÅJzpÿ.²ç»úýØþbà|…f¥·L1ÐRÖóí2θz‚ô+˜a¢ƒÞŒJŠ1¦ÛQÔX@íÖâïš-EûqÏ÷‡”F|‡r¹–w±Ãr…ƒœ¡ÉÚY•›§; ˆäï#®qà-y~oŽºß{†” y9ŽJzæY-ý—ÛH/žç1´~´ËëïCû.ß_yº•!–7Z*?LÛ§»�¨ŠnŠíºËüšæ€'CŒVdÉDÆh:JšÑ�Z 0û'¤ã˜a5CÌÚ 8úÅH 0›Œ°?y,¯»ýl¶¿(e¸òùöo†ë]ì°,ßy™iV:q Oeï®à½Ý§¤=¶îßÎAz„»”®b"S›š²]Ô&žnãDµZåè‹d¬U+YÐÁçF™¤Ú4; °�”2t0ÇJ²•Î|àüæSÖ±øéåæWB[)È÷gæðó.åpÕRS*ý¬çbâ{´÷wørɪø<(×µw F¦¿;+‘ßž¡ÿÌ­r„hcw�M`kn_í¾168£,û]Øó”1û÷å™RŠÏánÅxò@ÿ…ÞŸ0!ÀdÛãvþg¿‡Êï·@ƒXY¾Åèz£ŽöÅœ‹=Õtu”­¬>È8 ýâ#.~…ó›ßšöx5ÇŸáz:#0ÛÙ›wxÅ÷Â%u,Wo¤çö™ÄK±¶]ˆžpû .é}g9â@F,¯WdÆÅ…ŒYÅʃßáÌñŽŽyö+w¥›,°dÇl<ë[¥[ û)“¨Cf9kXûöW�¸2T4ˆãçúûÆ\Ä}>²ý*7¥†#T¬¹=ÆX¼/mTÀH$à1?œ?MfN_ò‘õÿ¬ùx4žçæÝ¸NzWù!.@»¥wvûY¹˜ÂC6ÿaådÀ ?\å›Ò÷^$'m“!%÷l9´gì°Ë}«Û…—ë±íú¨O·ü=j¥õvú: -‡l¾gg¥¦ãô»"¾ ÀÐÕ<Ÿ7 �ÖI¦cÅ0rå6È\*ñz}:} ¶^}ÇÑÆ¶Ñ>Ç=ŽÌLW1iªvP1Ý<�öT:xór¿Ëû¹czöËNl«<Óƒi8­€Ùtm¿{7í‹ýÓgã'븽·Ðܺ]�š)÷·'~|D@92Á|n±,]ËÀy:vSeøÜ+@¹£ ¨~ιõß#]@hÿ ܱ®D$šn¯£#ä%ã‡|uËÅû^÷£ùžì3Ç0F—”\ûi> ¸:`i 1“ß´Šë?UÃ4Ãô”Tbšß Ë™W7àëïY“ÆZ�³Ò‰x2Ñf,1sÝÇ_þúo÷Ødî8¦7%6V0Öîç™u%!nÛ9QjMä”tâ·óvÀ"à1úå.ÓÕŸ§sãîìê4†A.Ü^Á6¸£(:¬xL @yÇ+2«z+_mlŽ ä¼u`¡#ÍwXÿ¬µ­Ã þ]–ƒ‘;ºp¥}άÂ\jÆ€ïÙè :KÇñž„b}µrès ªãOßì½%gû5<ƒc-:úôŠæiÕs÷:Œd"–×ÄóùÜmp?>‡j¥7“ÖÊÛKË‘ü"®û,`dc“Ýîò1µ0=drÅ«xŒ*› :¾_L~ž^ 8Æ”Œ±üy tI#b»¡£»3Tïi&é†�Dú]Ÿý‰0]}¾q šµ·ü½ÝО±Òý>Ö°J™öÞǵñØZªd—Çw3k«VÔ̯ œ_fÏê=Ì€sö<a}qJG2‘ÕÐÙÂ<Xø÷Ñ…üÞöùdÒŒÙñµõ±Ä²>ø{øã¾Ü—о½/\=ÍV#Œý/s&™P_3îîJ@c9êvIvT¾ø¨Çe>ÿ  `¸WŸ�éß‘=/컆ÌF;î9A~Œ©Æ²M 5_ÿ#){œ�@Ó¡�xû²üýóºrÆÜËͧpý"Çþr0žé¾jíVêpòtíêõÞ¼\Wxw[gJž½VLy52šn „Dìì)8¥?ü8f2Æ×ãýÂ&v ÀCÎÔ±†õ€ˆO‡'Œ‰V6£âP¯ÜË¡…ßsÕ§c DÀàTܱ¢öl=‡cJïY,‡z3í1É"@¯Ù&ªã#K³ŸÝÊ5Ã Èæýå;ì/FXdŒ% T „åß¹t2¦¦•`ì¯ã8ƒö4ª… (ç<š‘ÕÍÿýÞs{Ìj@®÷üÄX]>}ûk€ûÑþråå^åUÒ‹<½nì3Ì'–«Ç0ÃrÕVn¤)`M-pÌ.” ¬,‘.l1Ï6¤[åkH)*æ-·gˆY`ê'Há'ØÎë†Ø·�ØoÃ3µ< ö+¬Æø#0Å~ƒ˜bhJ:Ñ¿a?ß™bl‚˜'2`Ýpt¨ äÇ¥œvÍ'âGS­_k{)wL*ýlâÅ£”Ð[Hu:b0¦<(¹ƒŒ0í óRI†Œ ŒÁšÝ~:¥š¸ö,&Ø~¢¬ÝJoÂñU;¸¼DS/ÖÎ:ËKtœ'©VÒ÷¤!uëñ|´ù|Žº±c;Ír! ¸zØÆB�'ý‡ŽICbŽYfÎøV·'sla¿a�ñ¬?DÖ¸—Öø±ÀÑí.¨yÆÉ›éGþ=ã%Ÿ!ý™ß³�<,0‡õãﳕs|¼௎¡¦à]G¾—à ¤ÿ¼Þãui:#öçÁ®vnÕÌ¥c_ìø6бòø–—ë¨ifø„¿ÞK˜N]â—ôì2¨ªçañ:Ÿ.«‘}Ÿ"C;¶XÍÔ¾='Ïâ{»öíû´ ǘPþ;€1Ï"£¡·Ë·ÚÛ3͵äÔI �„¹Íý;ã…WrŸ5Ú)õí2RàJZƒ8MOÅK€±ËÝ‘}ã6Åðê:oV9Øsæ_GáÁ¦5ýÜP ÐâåZ±‘_ÍÖJvÇëVZqýžêùäíÊæÁþ¾(¹ÈÆß¬?í�ØŽ×M‡8ZtvKÈϽ«ÛVƘ‡1UãÏ[tÈO §fž¨ZWïñÉ�› ±—1Æ»áŽÚïÊûÇ¥p¨ÇšÞö40Ðïf;™b xP@a?6gø1w»ešvÌ2ÜPºQ›bfù­vÈs@i7ÖWÌÿtè>e+%¹ÈŸWÆ—z÷óq¬XÌ-bÙó¹žÛÈ´Âß;÷L›’‰Ë!L1ý ¼€TâX1Åœñ÷û*·Ê¥ó]ˆ@…£íÙ”k×úÀÆ4%&úDv %+IC h ‘ß×±³ò7Y¼¾² Xã±ÔV=Né}±|Ѝeµ´.+Wm{í£�LŽcvU /4”JÜ0Ê(«k¤|ÿdç“òTÌ0wüˆ!°õÛão#•h¥¿Ç’RœûƒÜ? % £Ý¤ÿ"×ýfÎy¾¶ÉãéÄWù‹Ú3¢>)…b†‹{æÓÈWúéÒcŒ^~U>ëó´~üxì‘(}³·r %ì"W¯ˆÎ0ÈD°Ž¤Ûy½RÕæÃZ¯4ŽK”PfËËÚ+— u=±dÒ_ `ìþnè ë86ãSÅ©»¦%÷zŽÝZ:Ó­D1¦Ñ½z?Ö˜o·µUŽBý+fµÀ¸1�E5¨EØ_^’ó¬6þúºÿÎ÷†’ÎsõR‹cp`fÃ<W¾ß }¼?J¿¡ÄáÜç ¯i˜ÿ›ppÔ1ã°½ñ=ÉÞŸ  ¿H"€b„Y Oü+&rþ>]̰—a¿Ëê~¼z¾ðzÛ|O¡ÕßiŸþepÉÁ£p�2Ûã2¢ ½N¥£—­ï¿Ý“õÜÙwqÏý>½¸ûÏázno>7Ïð~ñ l˜Tc¶€€µ¬M7ûÞª÷ÈÜZàk1ÝcÿeåšÒo(§…S¼tðb¸åãÕ®’/|ÏjqÏÌÔzèþ<Æå£b"'åšÀã屽勀é9ØßuÚ”8�êó›×Û-2ŒÕuÖ,Óc .9ÈËýr§Ìv¾+,¶Ódžùzë~Âã\1^Ÿ�•-iÁê~îèŠN_ï÷q¡Çcý°\*ÿ«¸>Áµï/XÒ¢¯Éy4tÈ¿CL¢ÅD‰–¦¡õÉ“oû“6°ÌÌÆ¹W(çiÔ+öãÅJ&Z`,ÚJ%½Åçw¾Ÿìyú¡k}‰À¼ÇÕÀ@ÅóåÑÆŸ]=CÀò=üŽ{õ±ý«‘ì÷ %‘8™~H‹ÀW Úô„ýw)‰ˆ÷ ùC×çú¨Ø£$¦¨ÇPãÀ›E&–glU¦¤Ÿäó‘/p°íÛ³厗kÏ4ªblu¥Py}×ï¡Òåéëöòï«ïÅ{+{½ß«j—Ås]×§»LÕc—óÍc²Õ1ä”uc‹µ¤+«˜aÉõÒ&QJ�� �IDATÝcêz%Ý8Æ@†˜¬þ¿#LÅS†L1&™h°ƒìWHåׇ„â�‰Äߢ”¢³ßÆcÆ ›@ØÜ¿ogy²×� Ý,;Mt?´#9Ÿ€\a`µo—£Ú”cAK (i»¬¶üŒ@fŸ·Ž#'J'N©í€aÒK«\kÂ;W/ÉýÌñžK=Ã4^Š,›÷(ð{IÍp«bùö^¹Ü«úMÏ­¼o‘×åfuH«ë=C0J ÕR|™ËãçPÚi××Á[Í6Rx`™eûxã£LÕ ™™ pÛqˆ2f)“TDÇ42¸8€ì+¾­”"^7èv•¯#a¿A}ÖûÓW¹#[IZé5¶ é‰X`sû¨Í½_0fâ¬]Ьlö«å9?ŽïJðXë3BÕ•*†”·þsÍ%Ï% Ÿ[¼ºã.éc0aší€’‚yû1ž”Èxñåb¥žÀŒZ€ÌÕü9S±ßè[ΜBàhJó*|^sóå‹Ò“Š©çÛюϽ£^1ôùñ.s3.´ÓÒx[Ò™‘—Yi¢f†…�yË‚Ã8ö´lœ<ÏÈ„Zí[-ØÂJq€®ã¾Ÿ³yc„eé[`ÅŠb+ó†�{ÎŒÅ|mûªòúíxÔÛ–ç«"hF?®%»ý6.°ÌóçËc¼…º<ŒéÚLÑXì,î¨çµÎìÆ´¿õÛvg†=ü¸oŒ?SB3^—•—Õ÷{’mxýrÔBS¿ï%/#ð}Œá‹�ÒÓ8¹j K9š»€4šŽáu+DZØGu̲«ûÝXû8�×´‹n,ð£€3Ö?¹Î2ýl:ïäú…Ÿïpý÷ñÔY€8a“ 6¥ÓØaªým»¿Ëûyû!@ñýñ;F@:«—êßÈ(Ü•À[åÚ5™î2Å~”ϹÿE)½cõ‰L4ÏTRR…ÚüsYÕ«Ê¿³ë8Smïýª˜{à­�½X+�R#•8£-` Ó1ö¿ë1¶˜*‡¹Æk0ÕðúÿeçµdâÜþ=&cìf?ÝcŠÍíºþOslÚ]êðÁ³1½æþÍþxl‘v‹öÇQ*ñãlŘb†ö›Ý¿o¾oOhYÆW˜vW”¥¦bŠ%Ö‹up•÷ñ‰ÎÅ8èŽX|\+("_¹m WxÚ )’ö3`'Îë¾ÊÐý܈0ǹþÔÊѹµô(ݸZͯðF‡óLÍzl¥·P¼’|—õzH%X÷óÅ,@‰$Ûž,¶ ·ÚÙÈ8°¢‡ñøs3ÝREF·=iÅ:–ÏÙ1ê;k†‹ý=CkÝ;φ1f1D¿ž×ß·—.ч2tÈÎtÙ~Å5´Ì--mº˜_¯â¼·úÍ'h (S§Ü©ôb{ªvƒ{±T‚4â7”¢¼±(xßûØŒËò œH–)2\ùbì·A·Úx4ÅœÚ-õ¹X�P¿_0¬röËcðB6Öfïwœ÷qÆm¶&ž)£bŽêò«ý›ù÷ÆùñžÑ1mý UÌYöÖ}~œ†ïI[nDp¦>ð;ß}d1I9_ŸKãè²j×uÔ@Bf àEƶ²ÚÝsç·fé¼ÅTËÑŸçÀÕÜ.7*tDFg„i©x>ÖL¨Yî¼ OÇKñ/`­b‚¢̰¹õVïÆìº’ô¹N)•ìÏ»vZl:ĵv÷:=Ùþºï ܯÊYÛtäÛö°)ùßý$ϳ|C9>`^n¢¢[`lŒ»£ÿΫ™.×CÌ—ò ß ”‚ôéX`ç_O=ƒÇŸïHÇÙçϾ7¾r™C9$û^ìδ(á÷å^å8æ°ÖÒý¥'/ôþêú+½ß¾zï½+ýþ<=€²SÈoë¯?ÄùÅ[±Ä°ü¯�ë´ëw \ý”3à¼!ÀñãÁô‹Ì¿ 0|Ûé5Í|z‡½¼EwŸ§ï©–@ñçl?&2¬ŽYÍ”ê}A„ö¨¾Àc먩v®jÕRÎŒD`­`ˆ¡T¢ˆPôOv|J'’ë»ö¿ÎE8Ã󪊖–“3ÄPŠÐ^Þ~z\ÿËýÈ/X›@Õ_$ýß“Tt̰qÈ>þ2L±ß0æ¶\’ñf3fØÏÀ›–=J ¯ˆ[šð SüßHQ�Ø) ´êzøt|¹«•וu‰«ª™;]Q¹oùE—Ù ×±}&ù¥%”´k”úƒM·p¥©/—r³zÜl9Ân×OÉ'ëJ;¦˜cà¨C4slWÒOÃÕ'2ò:+„°$kZ슟­J‚-ó±Ý¢õ$ÄöŸÊ¾KÜZèIIe€jçwcîô €QfÏŒý4 ”¼›@X‹ì#2?ÔóÇ€{_öÞÑÒ› øòù®-JºÅØc™£?æàª5С¤¨æyËÈ‹�‚(‘0|¹âº1–â3J"‚}&Ÿ’4š€±<ô²–#C_•db,öx¾²J:™bÚÅëc¹p¼’—´–D}k¤r3û¼díç¿§gp„­à‚{ÿ™¼/3&÷ž¶@ƒ½Çp…g8ãEãv™¬šÁÓ{RÕ´øÊß‹í§¿o=ýîtû,¾³Ý'èZl×uj$ÔwÜ"ÃjÚ ¹@{#›Ä ›Ì™X~|nr€I3K/´ÿeÌÞxÔKCvÚw?“ŒÜIW×?&W{Ìý¹ 1TÌ–ÜQ¤°Þ­^ÀY™/ßp>+‘¨¦Ãìwú“ CÆ ë¿jŸI&Z¦ÍÆ#Kê¢èÉ·é"`eÓµ’½y£ÞÐÑû¾ñ÷§þ]sÓý“ØG »‘îGã=à©}¿²ë'ïçå{`Í¥£Ä¨ú}}»ªòg ± Hz�°k[™í§ß%ä¹~±×û¶ÑclDféÊ•ûÞ3Z’Ò·Ë 4¥Rñw`Û!ö•©[ HÉÄ2íûã öYBªW]æUף̿p»ÀXûL}‰4#,ý¥ÚC—£¶òrètÔ~àéþǯ×ùMéC|UÌ/ÂØB£ .%iˆ€œb|™ûi¾ª\ð›ùP`ìì –~z�^+ƘŠáÅ€/´Éc@™ß:)Å €MFJ)ÊzüõñŸ@wg†FÙ¶-Íú¹ç›ë¦pK,g€©íÑ•iG3§ÒÕÅ'¬ÊáÀÜ-½Áqe]Å„ºÙrl¡¤™=Ÿ™Z­V NcjÅK:ï%ã.cH3ðrɇɲÒhÕïƒ@2Ú¼áÊû£be6GæˆæÏí>b:HCâX¬±u<®¤÷íæÓ“ûþø>s ¢¾ÏÉ{q§¿”�cu'Ä/&=d~]�héKŒõc÷©‰‚—xÒÀ—jß<=|ÿåï/d²*†kç—1ÆùãÍ¥“Ùîyûû½aÌ0„Y@í³o™Õ>“ñ‹ÒˆZêÏ;Ž{o Œ·bæÀ”êsc–3î{€_F»�\=ì1Ú•› d€¾ÁsäV‹q±:kcRI â¥+—,eÖ"0·®`�Ö³±]âïp+G„~3¾kW2ðõϱþ¸`:´kMÇbl¼^I”rCtȦ5Äy ]З3¬<séJÚ?ë—Ó1Çó°:Ã>— Tß›¸µ³§ŸH¹ó~XKCÎzÎü3 MżfÒì9Ñtjœ’CÄÍûkwî”#nRBÉÄ.P¹ö-gˆÕ)ò÷•ØË®cõGé6^N[‰—×>Ó,ð5fŒ0}n_ÆM:q–'gCú¦üÈSÀ˜¯·JŸÛè9©æ¹{ÌG íÐû¢ôæU,¤ÝtùýïàfתXg7{Ú|k/‡$4ЇýÏB Z6™P¼¿ôÚÃZo¾üô`нŒ›Tâ,¡g†õ£¿™ü?"q¸vYÌ6”œì1ºt;ásylÉÁûP@lO·  PP[Îɬ�;]ž\ ñ(c«/-˜gÝØfßÛÏ{LéØcÀÇ¥K@âu=®øwq__ÂR¥ƒ†@eˆ)iAÃ,s[u_kì,½êú*Ì6Ä}ü^oˆMó�ÓM ÑJ'ZiÅŽ1IÆÈ[Ò‰˜îï �CfØdŽ}0€Íå±Åîz£7à‰¯ë8ÁÜ])Ë-_¹y44ßp©°‰aÏŽÆ2Û‚“³ ¿]¡ØÖ@8ºP2 cðä€J/]äïçcq¨Z2GuƤ¸<o^ZNÇ:«&((ý¸ÿ{gÏÁyx†[”jãÒ•¶Uóç,Ÿ_à÷8oÖoÝÍ%´"ìXL•b&(8?ÿö)NÌj/ìß(q%Ãjcý[2c&PõŽR;Ìõoˆ)6P2Í0˺Žfëà= �`z«5ké°¬Ðb ¸ŠIRÕŸ9ÆR§†©•NŒ“+�X 8ÏO@4cRû>#ŒŒ%ÏêHgåxGú’ˆ9 ß•”Ku^±g•íîÜ5ì+6ß´WS”ÎÊǾ¯ñ+´í®ÏÒUÒ¬Q9þþÌAnßž±vÆ»—b[¿SͰê8Þ#³í-¯ ´gå˜5¸åï§z ™I,ÿ}Æ.0Ùc†Åý-h°¹mH»ëöRÌ£ŽšI^vZŒ‘ǵê9\=b2²(@0Ôó6¼ÿex�$ûO»–åå ô³nÈzpóÌ>æ†:ò=Řa×ÃÑönöT>—üýP»±ò'8ƼªžøêyôŠ0Õ›‰1]|M43Ì:¶‘ÙÇjq[xtÿ˜7ƒ•N|ú¸<€³É s÷“­-ÇX¯ò¹¦Ï] ”\ÃsÖe€õÆÝ(»€ûŽiÇýžÇGÁ µd"gD=‰ôF™ØŽàÆÏë=ýWØgõ°Ûê»Â�ا$@O‹±ü€”/´¾™l&#ìÆ [-ôêJêl2ÃP:1•RäÌ·›Íçï·Ç™ƒÿu‰Ýåmý>¼ŸÞø“ö$®RûË<�ö£ ˜ìÚw¹¯G+¤ûL}Ž1²~@þ*öضrÉÈp]dv­\jV¶#žùx¨ê뼋ťb{ .*A¨�(Ü'L0Cl7f˜»n7ÖYŒ!ö_rÕŒ!ö;9>íïpüÏpÎá•1¾Ìq¾¾ý<"ÃlšËwaF2'‡íz}ƉÍLgZ#½ozš«�”Jï×¢EÓ10'â»+Q{+ñ”ukᄟ½V;µ5aF‡ cÑØJçåx¾ÈŽ2”¬®ë­Lƒc¬ÔRA|….;ëË·�›¹Ïê•1ݲR­üP2¥!û.bÕbxSÇy 4µŽ[÷ ÅL{¦{oE*YY»0‡ÓÜŸrG,s뿃ìοÜ÷-ƒhN�ÒPjïC� 9`Ž�7[wÝÆ1”jex#@ÆÊëÎxI¶L”•ãaÀHb}±ßc¢Sñ ¤3Y¹ÆØéßlïv„KC~ óT—wÚþ9WÀÙqID4.Åz)Å÷òÓ£ÕŽG[¶^8`¿KÈ„Äç…Ùt€Ù~‚RçqÉŸYËÈÌ{󙃯ÆÃ÷öªÏ¬?_@bÇ ;ŒrdžÆC Ï›—Á|dã°ú{Ûs´£»åxäŠÜqŽí î¯ ç1Å8Ærúíõáàïs G7C="bߥsPjÀyN«üÙw8¦3ëïHžB¿Ü³¾ôÚ9¼^wv�ÆÏ÷ãáRÈ�fŠÙ¡ÎÛv°Ûcð«…—JÜe Fø«ßtLk?–lPãJšÐ¸y´¿a†a¹Ô†Y.¹©b†Åf€Ûbì¬_ 8%½ˆåçã]ÿ|³ß-g^Vv ö…ô”õº•#?Æ㞪.óLŒÁ4E¶_U¬;RŽŠyX-œ¼ijާGÿœí±Ë€·é.¿¿ÿGÒÂ$'•ø²ö]ûññå5ì÷aêø©ÝÌVWR—y?ÿ!¶Óà‰hÆóý~æ°À(fÑÞûB3˪÷íµ¸_µWeǤ”W}ðVmªê¾Ïˆ0ßþïàó·Ï}ž2«ºö?¶ßª†�¤Ã+1u~ÖëPýþ1þ;<`õ¯Á™\?ÁÃþ:?™c¿H�m_-�ëapÆ×½A9¦® 1«u~Ûï5¿]ï´ƒL)œh&RŠj¢y3¥$ïç†@@w¸V+¶æp•O¶Âئǂ¤ûvè¼<¤†4Dà<o[ŸUž5uûüú nò'tàyå�¦sâfi³^v%¹w0Eæ¶GgeÐN,%fì›KûI1Zÿ-Pd>½Ky¼ËÌxK~•tÜ´3y¯øþU·˜}ž«ò1˜2×¾={F’V¦¹ç €š‹¹¯šµ€[¸Í癑ø|‘¨SÀÝ u! <ZïŠfêL?kŒù:ÆxF‰D8~÷Ò”èbFr ãØÒŽîs÷Z X1¶ôÓ—K¾â€sÀíZÐKGµðsqŸN7_à‚@×E<¿ç-Èúþ>·Çì½cºà¾EIº—Rd˜eåñåzƒ|c 1?Nð¿ãbD²ßdœ8Fÿî*TÓéît9¦ÈÄnI& â€äö[R‰Üx@ ložŒ¬u” ôŽlÚñù’䊱€bŠ;Œ‘uýé¨ë²rë~™—ÇJ#~Îü u2Ã*7žv$ú~]]yS¼}víóéÔOZ ZÀ™Yè¨öǯn/ÆÊ³�Õd†M¦µß?-c&^¯²# —1sÇþò¯"]{ßL—µ#\¶~§ðÞÒ_”üyò¿Hì×9¤«�°,õ$Òú’‰È0ûFN*_X€ µª=xýÇ#Ÿ“l>gŠiÈúih®÷~{ õè,¤^R‰kÍ—Ï1Æ�sÇy{\ÅûÄÿÞIKþ»ñ|~ì7}iMÎ|R@Nlç¼GíK}NCàäz/×Þ -Uèµò~^žxËÃcaérVíÐëñ÷ëÆë-ÐÙO§²Ý÷ãçb¹í2ÆRICdzu¥1Ý„¦�²îìç’‰Ó&C,cz-FØ/èʤ¿ºã?‡û¦„â¯,É£@µ{,±iVRÏ®˜cf?pµpoÂz7”"1%•#ž3ÄêÇ(¦ú’1Üpåf5ÞqˆûtâJ`?°^Q&Q-®DÆÉ7‡qtìf1 lÆ·õ볕éÞQ¤£(…é¨åÖQn%À<àx¿S‰–;9SŒ;n»’GQòlÀþç+•ç"ÏBR<–O<¯rñRlÇ„³XýÇ;°TLh;+©%Lpp@ÙÇw €…2ÅHºî~UþÍ|´ù„åp`Ò‡hø^ÁmêȾ—·‡ DÆñEÛ€Å7ó;1«BñºPniþ}\1GÏâø²ÜÁÕ­ÇsÙŠ™uô îmÈë:Î/£‚Ô{7Ïñê'мðö³ FPbtZÀòßÁDW+É#£+¬cRÅöàLPˆ3I9ö¾¶åb¿~ïíïryô½P¤#½x@âZŽ£çÙË㪗òj_ï[¾7;ÎY%é”·‘¨b£Ü¿Œñ)†ØJï6¯ò ÷²y ŽßYù¬"„ Ôü"¶ædªW צc;³r¾’tæþŠuæãޤ], =ï?%ïŽôô°¶%ç¼ùDîçvMFÉÄ£æçSËѨ”Vº¥Ý+ÿx?fö¹Í™TÞP $Û”rHö=»6®³@Ô4-§Í¿Ïm ìùÅcß Täwl/ÏXÒ÷k†›ßdß¡ì=ð.�†§f¬°ŠA„90–R¹ùv}Útlëò¯t=ƒ)w,g±Ä8ÑÌ3¿'³EËÇ+Wú»¿“|ù .1¸¤ß ›«ù7(ÎãßžL¹<ãË9úM®ÞC7¦›g®2@cgaFŒ©¨<¹Ÿç>3{Ò‰}ã#ÊPŸb¤U]]¦W<_tó÷”èt9º1Ã|:ŠAõu¿÷gû“¿þûÈÇï¸Ýyì2²”ô¡ºžf(ûŸ¸¾’Lœ€[ ÈUå˜öñ¯q˜)Æìwºÿçý¾_Æž9†±¼¸âÆX‹Œ¤3°Éûè¦óó㺵Òu—écMKxLKàj¢ùq yL¯»2´gè BG_wB|[€à@‡8c.øã|‚s‚ röZ¨VÜ ãÌHâ feèXaL :>¯»€C%›bùÑáçÔËácU+š¼]\9˜# Ó¯p¾Ðñ@^t˜Y‡šæ©uMI”âùž­TÞ 5„œrt¿ô˜Oe[Ìý¬­~‚±•ü«¼yÌÄNm^`Ÿ0Á× Àj èÇÀ( ±¬�?&ß”åùÈö `p!³ì‚åÃú«˜_* Ä.ÝfÛµÇ3�hoD²òÅÜ™]‹náÊñïҾس·rïýp€j¡K.}x ̰=†X_x©f%ÉWåßÚKz;æV»* ¿w>ý¼$öý‡–98lþÙŠá3yßãø™i¬­4%wÐEF¶Ï+ÙÏZÇ2ÀÙ÷Z'²…;Vš–~«¾@ ×³Õô³;.?ËïãÞç%“ëåžœOH$®|íB©a^åíˆýÐHsk ÞïWjçЯÙsv•õRÏ3ÜR…¾½2 Fhy€nÅ&Š÷ûöäíc¯GöÜ_IýTúìÌ5�`Þq}*8ýØ+_ÅUæŽõj=øî<ü ý‚õ³Î¸†µ‡—ŽÓïOßOu=Ø}!öH&fùÎ|,óf1—ÓaíÁ�,ü}9sh_J{ýÞÎüªŸ?°¤¬p[éö$ÑT;©ýh»ës�DŒ…å?½óHˆÚ÷ä“^dý&RO�Ì^‡±�+‹ÀÁ* Nêžü R‰cÅ3í±–ì¹ÞynøøwIºúz¿) 4XjÆMÅõz‚«Cb¶<ßÀInÛhÐ8ƒ÷{�èöêÓ_B¦F½|«ß³bÀÕí¦bñþ‡¿2ÜÀ§ú+ý}P2û)PdìŸÍë ¥˜]Š)FÊ…×+æXÔ¥õ^ ± ŒÑ“0ü逭óÞÇt†L¯ßÇb†1@Ë3Åôq~6ÅM2qI6¢F<—\±¶'¹ö) EÄúh”­ÜÐ}å>·ëƒíX 9#¤v@ùüN0á¾é3óÌ�”ôÀؼïÇÚi÷>:Zq‚¾�\yí¨l°z­•Ï{+®³vbíÅêÃV«îñ÷~ ¾ûjEwæ©l9¦°Ù³ø»#äÔ‹%ËWµÛ.°6b>ÿg80Ó.Xïpæ€ä%ù˜ã´,Ÿˆ ÆÒ}É®›€–ˆô"2¢Üõž H%õñÒ6ÏáºK(G3³ÍÖw2¿žMºì}3°ghÖ«{ï«Þwm=÷ÞñRwöŽÌúŸþÉzopž_WÅÂÚ…ôJüÙшúb Ó¯bæ®ïâ3ýαÃ\§bìÙt|zþ»— ÔÝåocrÙ-ú»’›b”®ò"CdJ?òزš©†c‚ñòã‚·ôù¶ ŒÉ¦{POJûLþãû7;憳¥R@ñg µXpÛL¼Ùб|qŽm�q‹’cœ‘¡$ u+xÀ6*X&Ö €ï#¤óbÊ}÷_ÉqÖß1Ö‹ÌÚõ íCTßKŒQwl!¦f^M©ÄÞ“S¹ŸJ†%/Ÿé–3®eJ½¢Ý÷²åhWAôBÈ—‘\YRÏ\.Æá•K4&{^”#þ}¨XFøPŒ*æîΘ LÚõfži©,2Zf9ªXH¼üq¿ÇÐRoûný*–XÏöʼ~1½èh÷�Ù•öË8£�±1ûœ< Ï´ê0_—H|5%ù.Óy’‰&} €a»x†XÆ&C¥Fw 2 ¨ØQŒä~¾Ÿ�”gµûëªÝÉ› 8á 7~÷÷çV烌¦Šuìý %•a{©ûº€]ÿ!Îÿ×ñã*="�µcËGPš÷€©bšÍëÿÇÒ%åB�®¼Tì°y_Z¾Cì¿ã?Àú¯¹ŠÇîúSH)®ã `ÃØa™ãÞ~•ÀÜïÀ #Œ1j ˆc+IsÉþ¶V¢E3ƶÌH'ª ëçD/þ1^Ʋ}"|.u²{³¬ZI‰@–TVŒ.ÀT’'U=p‚n3†Ø¼Ú÷ctœ??¤™1ÇîwÊŽâK¨Odr j?tüjÀ‡µ×W9pY=vì\J'¢åÜ 7WqKì9½JñT>yàW3F§qÇØ×¬f{`c[ <I¦‘tF�'<ÿšœSé˜ë@�9`~½Ðfó™ûÀ²Œ¹W“/–ïÄüB¦žÏ'D(Ú{n#ÃÈ|Ž1:-ÖsöŸçÖuxEÅÑï¿ü ¯¤iÚY”øÒxc#ŶÈC}ï=Ó-–S3³‘ñýâî;Óñ$2«t¹T»ÕÆîϘܘòNþZb É·G{p ð9-›Nî2CY?b×Õ)±–9fVºÑ¦ÿùÔ«7ÂÑ4“ž½/wܸ�¿óÈË5±vÑ_=�f¥õY¹†óÆ+I¦ëëÕm‡™n?1i½ `¡ŸŽ†é®ü2iʪÜ+ÿ“Û_Œ Å pEf»Žùn‘hÞ±‡ÀוüÇ­zªy~¿¼Šé2óõLÃôº~ÿþ;àõþÏãÍ2ÉBÎÄôíý[IÿröºÈlY-pLrMËcâñ:_,wÐÖ ®œ¡˜r:=„×�� �IDATe3½=©³X_Õ><¿*ØV(q¸µ0)·Œ2Àµ*ß´@ö~̪¾³ô¾uj¶]ÞL·œqÚµ�Øwe ×’\Šn•Oµc¿‡î–G)»K±àwü éÓÁ|Ty»é)F_hí/ÕáÇ»±-}þßa¿¶Ï‰-ï3)»’‰pB`Œ•>L®GÀ ïGÀ«À™û`6ư’‰ÿÿv�Ö¿D²“f¯Ûö„ý4t 1Sl2Ç µ˜_Djñã/[ ¯3Û ´ý6Æÿ¹í|û÷ã:æˆÈb^q –³ø#0Ö2d†}\ × ¶ûæÑŠ)vÜÝÌcKeïL¶2³ÞŸ@Òs*}h+Ù Oæø¹¥Á¶/éÄkmR<ÿ·‡#ʯ0sºUž·ö€ ÈVoýœé²^4+%µÔ_'Z9̹”Ñþ“‘ÇŠ©q PåŠpð¾dàÞ�Ùd-sÈÚþcKl{Ü‘yÜeÈÊ“õº—ûy*mh�‘vs’†€rÀ2ÐæuSzÑ0©¤ãÊ…��lo�T©ßõY0ëí5ËíPÆ`ü½P`=)6¢ûV}ïV¿Ü^±ýtd¤ü~ Åúrç«ç%± BXz}À�ï›ãŒêÅÇaJØö3ÀJïvÕl¡Êd\Åï«v€gã‘ø;è7ïkrÿªç:ÎêgøŽýž¿‰ëŸÃ¾]Ðsoiº™\ÇT)Äýœƒ¾;½UL¼£Òϧð¤ÖšƈR·«L‡,Ö^Åõ¶ý ã”y{Ù÷·b†©òtÇÃ,Ó.*gt˜ÚÑ Ó¿lWÎ2fšÏ^è<&ËßÖ¤?ÿûœ”Z4D^Ŷ.ÕÕ¥sä ·ùé䟫÷“ˆQ„¥f1Ô)`ú ˜˜ßΞ)ó bí}‹ÏWwÈ,Ï­ß.&ŠŸçòO¶=x>WøÎi ÂÞscZ;߇®Õ1®âz¾ßÏï³6m×O¥‹õ0DîØÖ±ÓF8ïÏÈŒÂúUL]ö\åÐ1Ô_çuD æ»I·“9¦,)fJ‹úrÍß3…ŒA×µïÆ±o%Twmº'ú]Óß Åè™åS¦jü~ÿûTäËËQ3†òXy]Óý©Ë”ãåÔ†@–’œçóØZØŠa¨ë¹k pØnC\§ì¨‡|‹a·!™ˆç•äaË«’2ðêÆCû§Ývbÿyìý&®²ÀÕßp_?ݱeÊô‘)Våï¯_P–—ßaÖêh>¹/ݱöýʼM›ÃÉo¸R'à( ¸¯¬Ê'àXdnt [1È·’²ÊJãM9Ø-c϶Gg@~6H4eå¬ÊmQj%,[qjËk lå7JD!ÓÊKÕ½GU6°‹¥õL‰¥Y®Û6®$ì8°b̳@¶?­ìq+¢»vï¹ˆŽš7HoÚ½®J¯jØ.•k+àÉö­í0{P21N/+FYÝBƒ­`™Qx½½îeh&Ýód\A,³™¾Üèó¯€%”h$@”cˆ%Ò‘ö½Ñåɧ»¤}»†oL ËJqÚï²fÆãŒßîYl‡ ¾Ñã})ÄÜúL°üxÅ ë¿_{P]5ÎQ©2fØíû½~&ÕÇ€E¼Î÷'ÝB·ò pÊc†1`)cf³…þ;û 2¯_†D†×jQ%I7F6Þ@{†ë1æ\Œ½Ø‘‚Ë”p<•Y åL Â<žß·½L,GŒùäÓm1ıĿ¸^§§VÖóãžQ¹˜+ñ}1–�>›ë3G£fŽUýS3ÕÆð1Õ|zµîÇvF€o°F©ÆkèQ)e|¯äþÚ<3쳡ì—CüÖjlDu%O°W©,`ŽKg~ÒÁû8•ïg\0j%M³v¹?/žárß2fšíöù;™–Éž/ëhæÏïtŒÇšMÉG”z«�6o¨T1¥b•Tíž½””›fV}ÖÁ®�»”cïM€1Þ6[´¶³†À)ëOˆS ©÷«}[®!�{KoHs»ý«å’qÕ7èßbÿð1½°6¶]^¿¼¢-)¸ÎÌÏc³,ýn@‚žsNeý#ÃhÜ÷ñ8Šjà‡3«tŒ*Ÿ¼x¹£ays ²›NH즯ƒy{ë÷hOz±n¿®„ã´”©Õ�¬¦ý¯yæ÷ÏÎu$½. ¯ÃXcÿ×1f 1”J¬$-@5a‡ë4fíg’®ßÿ˜f.fØ·ŸÇ E”R÷}wÿdˆ}ü瑟س‹Z‘ˆæ gwߚеº†¦,ç†ì^/ÅQT†üXŽ|M®Ž8í5½Ó—‡I dL'Ü×n˜èxËV|GfJœ¡ÿñ•¶+6˜Æ0—¾lÌ)›Î¼N9±ük®Œ_Ì^¾òÖJ@úöz†ö}õb¦^Ú¡º/:ƥѺ~g`,àµç ß—~Ú•VôÒ€ÀÑXS+¼óãgñ k‰Ë¯‘¸SžŠÑ¤CÏ*™‘$ÄrLÀŒ1¼øz’…ωd£òl~Y{ا0›�v`™‰Ï²s¤ógñ?ì/{ý¢ê×]Fؾ�aþÐŽýc÷—’Ãëñ9÷TŒÀnoÞ3|¿«žc¢1æt§¦œ±r {ÕVŽu2§žÃ¸Âše)‡"wô{f Jï´“W<§×©v˜¶Æëèáãô3eòáÝúŒ ¾Öð»Ö³èæQ=>éS‰çĽÝ[`²èƒã}ZÖÿ®u ýS•çŽf¿{Øfþ\J¯‹½ÙÖÓŠÕóUŒ] ¹ÃNµ“]x¹ãЬ™-G!Õö›ûRÿüþÊì‚PÏÜ;¤(CKÀTº†Ø¯¼_ú›yC SìuŒñ4¥ñº¿?¬4(D†.:@¶Çdü°÷sk«ïŠßŽæ~þ½T±¾" Ô‹Ö=þyèn/fO×êX_ŸË'2ðN¡¿yfÔÍj QõÏà\€ÚõÑŸ3ÿ:ò'`ô=œŸÌ°'Ùßö{8°¼b¢ñv©åe¶«¾'1N­L3@Ùu_gïæï²ý÷¶CÅ`;¥ç•U�L‚Tl°Ý/i°õêù~€Ñ.# ÓUùk©ÆŠÑöY °ZX0ÏS¦×4”B$Œ* $mH&VL/džÑXc¦|*z¼bÄ-ÉÄqgŠM©D+™ÈbáñŸîÿÿ=þ|H(2iD¼ÿ/q~1½þùß$#Æ£öÛc|ûw8îfçûŠ$¾”׊V‡XÉ'™ˆæ¬õzú¿3AAîæsL¢–†âŽŠ¬]v´’•ëråºbdtÒGÕeè•ãØ¬ƒ�lÌA•„–CÑç¥"3›÷Ç)ÓQE®¸$”/·eLyGG_B1;¯aY }ª;v,–ÏC&ç�a¬ C®ª…vœW¢ooÉQÆ€áVG¹Þg­Ëˆc×!@Äo*F˜Êïƒÿc CÃK*¾Áñy=+2Þ.ä'ê—ŸøÄk™§öû”IÌ~ÖÝÂjøºw¥~OT×uï›ïŒ¥õ9¦:öc ·–d[ùþª$d3³ß?ÆÄÊÊÏŸa!È<Û“fÓùóï2–߯äÂts¹rÌ{f~ßY¹gyü•·ðüÛtXì¶ì}1‘bIø‚›ÙÕwñ\¦‹öbÑ.ŸNogäÖáuÄtÙûyYÞÁŸÍ£òßù"®ã@X¶ÏóEf•Ÿfëp3‰Ñ™~œê÷‰b–å þ.nœ=˃€¨u_e’Õ]$ ½³ >Ì¡¯WØWŠ.~«ÎÇã§"cŽ~”4í†>ˆo 8º>Î[‡þ÷¯ú¤ŒB´1‡&CLI$2@ë:byo�Ý5”ë™m±üªÞQjðut$kå Q\¯¤Ü<P2Q1¿å¦ø*»vÔ¿î_{r×vÌÑÜW93©ÄlÒé- 8…ëísÀžöüwØÿ×ub¤Çb†}dŒ·iJZòµ¸žß¿ÚÝ>çßK‡?·È «¸ü¹Õ@J'*ÝWØfð… ©j Èh]ÿ£¸?^·˜}¹íJ2Vå›õ¯�£ þ#Ü_ÝWŦûìû3ÖT{}ßËgR†Q5­+}8Ø}côb#ÆSåÛ2ÃP ±ÿŽ›„àÇ (ú¸¦eÀÖß÷ÿ¿<ŽßîÿEJ%qœåÿ×ÐÖ-ç­Ib ±›)môþ†Y”bĉ:®ÐÙþÅ� WÎÕHG‰ÄS c‹å÷.ñ¾[®zšÀ µ1Ŧõ¤üp»ç؉+­uprU? ]DºU}.àP´À —TªÛÃ;æªØþ>UkË„îþé°Í9IÇCÈç %tÈ«ëú¹y‡t%¥8ÂñŠñåÓ‹½®r„çÀ3\÷\8Ôkwûågm}ƒì"ÒéÇÙµl°'`™ÿZ¬üê×{9pþf¶x|èª�Kñžño¼3|ŸV>ã~ük�lÛNÖ�¬÷»¿ —äÝr|kÞÿ9›ìGkbWw¬|á "ãI=çò;êY¼ÿ"w|Åû’|1Û³az{àiûNÇØ§;Ü{[- ÌŸ×gø>czØNo) aÇqvüÌœy€`qÕ•ÄùÁ>>›þþ•{é´˜˜$vØ¥•J¢ï,г¿ëÕHžçÌ ¼?íW½Aq!ãÒ³@P.å¿G꾗亜_1£õ—• ?:¶2.(ôï먠¢ ¤“Ûî:ô±žïð;uCj7—/×)ìã}ŸsðÛXyʃi Ïb%äÀ’¿¿Ïøó6çŒ QÔØ=c ™(µY`B@¹c”1[xùù{Ô2B ÎÌKÏÍ­>Þ7ùïÅþqh¸kÈhãVu*FØ{ép®Íÿž«}‘Å¥7}L-Ë€âÏgúEÆ›Âì>“€CÙ.y,`Œä•õ²íë•›•zôí0Ïë‡VÕ§{ `«cˆyÛm‡ÚüóQCìï¶ß×ó]íåU°Q�—’ì•O©?Ú¿/V#¶‡¾®{_eX€~¿Ã4„àJ£¡c‡{:ŠQ¶ ÌÅÛ�à*FÛ¬oÉ»™Ý¯¤­ýôøï&•ø7ì* |ý ç~¿æÀ–—NtÛß–„¢‹)æÒûø¤‡ÀÒœ€éÀQY†Ã« ]TàŠÍDJ‘OŒ>‹O×A½®Äã…îJñÚ!È!"+áè¥*ú†Ì¥¹ú¶?¥Ë&Äq¥øê˜ž½þ<”ƒmGÙD~NX²RŒ;ÙZjëÎï�q?®D߱ϻ831J´í– ¾áöWnû¢k¶Þ™ƒ²gœÉ¤€°½HF}Snw%…·˜+¸¿Ž(©Pl±ØNÛu08iÃÍvb’ƒ]fV'ßÌöž;%‘»�.ÎüB†Ñ”@SÌåÏ1š•+ÂW±—íÙÇÍ¿7βfÇ ‡³|ïíCz¾ÜËn /0VXl玔¦þ¾áó­ËÇZcô”LÀk•ÃÇÖŠ Sø÷Ü.dæ>û=âŽJ0¬vïþ^KÊØwù}î1#3%ÆRò–—W•PcѲmeÝvÜ•&×îÒT*�a˜ŽÙˆåÐ Òº¶�ŸŒ¹•Õ#_¡Žó»#kãÖ:1al?UŒ¯núÓ±~›·,ÀзK¼~æ7Fí®QÌʬßôæ{1¶öí¼u¼·^>»’3Åö#/í?j~w¤âI1£˜ô&Jmú!?ÂãKldù|42ð=yùë˸üI¨F4ÎÄì—V1Åx”»;‹÷8Un œKO2ƒ* u¾ªe1.,³q¦Ï2þ>³åï2©ìý °9…çÀoyf ° ”Íó¯÷œ’ïËd„¹-¯VÏÍÞï:ÓG©G•þ®- Çêý‘¿±û1§<¯ž—IWfßhÒ1³ª/Ò±XQʲ©ò( ôxL±Ù>ž¡†�™òúæë³ÉÄ"íÔ‹5ö¶5€Œ’‰[k°ã’„˜^ŸÞ‡×c¾Ì�qXk”sŒqcˆ-`èÆóö¯1¸„ýý8cˆýdöý}:�ka…íã·û¾Ì~…ííMBñG¬±ßVL±Gý¬©úà v¥!ÏL}žO‰#eÃaÚPœùá@û"®ëÙY¸v%]âkóøÊñžäGÞ>GÌ:¼"*®è÷åô¡`áJæ8AÍV˜^È>J+ay¬]ÌÊôéS+͇K7Ö—9–Ã{¦×“°¬ÚW+=§Ïp;¼‘üùçŽà>€Ëí<*¦Ø´Ï1;êv­ÒAôdÄømeû1ǼUîPl¿þûKg±gb¿ÏwL"­,u%Ü–u'l;ýÜ–›gL™Û_~0oyÃòÒl¯ž©˜_ŽÎ¥,ã™c±ÿ> Œ]Bþ9Äwô=µl¾÷r€¯¯Ú¡n§XOö]R€Wö2úœÎîy·Lª*V.hñRˆ(Uü ÷#�èÓWÀaÍô¾¸ól<1ÄýÈpc̰X.Œ .ȤРÿó­þ ôÆ•}ëÝô9Ôãþ¯•tD;˜MË¿/øç Øvš0éKõ½BÀ{*GLæ Úkk;çÁ„‰û 8³íPIgÏËû\QcÕß¿ÇvÝg(%xý$0¶Ü¾·r.‡#–?ïçûn+îèS‚LGù6×0Žrß3P²¬÷K!#Ì2"ÑX±Â¬Äàܯæ«èð¿å{º?' ÈC¦Ž*OÖ.«<=àËØ ¨÷R6Ü͞ľfzy«¥÷˜fXY¶< ÙcæT1ξŽy³Ì¿‡+hS÷ÇμäýÞ¿™„d5~cŒ†ƒt”|‹,à@·$y®?º@VdVîÿ.@Gý¼3[­¢ÞПcŠuKŸ—Ý›K"ö¥«zw™§üyØ–z±¯~´Óã‚+ßnxóïÇóíW3«ïOÜ¢dw!À<ÿÏì"–ŒÄ ž,=üjÅK‘Æ2S×TÜNLëÿ1ÆŠþ#\긷?ÇoãCì¶}o¿8f˜Š!6ígr~^·-d3¦˜c˜}0ÉÅYŽ•y™ÙtØkǯÄjML‘6·ß¬CЛrôƒ+³ûP¢êèŠ{L÷ú ×›šXçûú~œtÓ¡ƒ+±£kZ\ñ¥U)˘ØY!ûš¤—]3d,DÇU&õ¢¤è˜Ufì~›ßZ™¿€<V>—cõô–3]zW÷ë­Ê{~üNÊ…ÿ¹XkµÀR&Âg¯ây̺ÀØç³c¦wÿ”è[÷Yì%8®@ª¤S;R‚cäŽ�›“eùfLÎŽCßKþj^Ÿ*Vß�Åþ[ýsk”úD[½÷9¹Êž©€(o•;oW"ñ\<I—&P§-‡œÏâýß­QÍ®¤ú¢u'ÖÜa½tX†8¸»éÆßßïè¨ñý Çà [Ô›wÌî<UÈ\›¹ÜÒáÌ=´Þ´ðV"” yT"‘3ª:’f=û¨fø|*?2ÏÈó_Û‹ÛZË�ÃËϧ4Ц ¤ðñ陎_¯ð{ÏëOƒoY¾¾Ü¾b90>Ÿ\å=Ã>¿×L•³xÏñûu:Ñ&°Á®?Á%³** /÷¾äá‰î}v]8+oÅ@ÌæMÚíÊ[œ-ø¥óAðDL†Øû}ßJ”!0†õ@‡º÷œîÏŽI”/ÄÄXL^Òmç=ñ¤ë-ÆòæÏMýå´÷½‡ýÈDÚ1ÐŽÆS÷uË£$»ùªôÞ?ùé‹K²rÙ­ŸëX|¼ß#ÓÏK2²çeÐtnöýÎüšL°áº÷°öÁ$A9Snm_Ý>>o±¼Ùxt2ÚÖ>:þ÷HQø^Ž(¹i&R¯ç?…'çkD}#ClÜïÕoÙÞs¤s]`F}9«‘‚ZèÁ%“ªª·b¬yûÞ<^3ØTýTºðëç3M1µ¦bʰJ`x¾b„!ðö?q^í;IÅQÇ(k•ëÿþÛiÿ%wiB·µÌ¯ŸÌ¶bfÙó�C Åußá¾ßàø¸ïÿ&€045౦ݠÐË cè×Àã„4aˆå.´ãwµ‚ðsŽÇS1QQÞã1 06Aœøåšú±t^h9¶,Slå;­vá£Ê:Ú™Uåø³+ã­”SåH´ÀÞyp)¯£€MdÎcz �¬Ì:þ´#0248SÎ;ûÖuÕç̘£ÖeR\¤cü-½¯i$µ (ó¿bè¨Ô>ëÎ# €¿×YüÞ–Ùôûv»˜¥ž c\Å ·/oüe8óÅ;ðÑÎ÷ûÎâ¾ÈìŠ9Ì”&0€ l}€cçgþùJø}†\f±—>çñLW‘ÇRRµŒ×í‰Öo§ÏBÊø»á™cã}W|!cÊnm{¾Ž½ñïðÖp±fhâ•lácè²ë­T£¿n=ßÙŠö1rG “€ÌÚ ûëÙŒ#^ïÏ™#~M[£ÃØ¿/ÒQªêå[Ú›÷ïñ0¬}à óí¦K멤ؓØaùü™C&­·˜Pâ¹K™¯eüžâ‚2d!C ç PâÊ“¦Ÿ76ŸóE;o«›Y?ÏÜPüùñûÇUÇVxW¶Ü‹•¶ÁÑÜø“ û{†€zŒ1ÞÏ"p2ê·}%ÈJLÙëÁñoŒ~ì-´É\Ì0\ÕåŒ0/ÙcA1‡ÿNÌÆ½šç~>¿ 8gíòö}O}ÚìqXÅôZöUŒÎÈy:ðÅäåžéa~j?ow-™øjʯÚ1#y¿_1á^ÜVÇš|IŽÏXa߇ŽŸ$ eÒû¸?/ߘ¤¦/Wl_[. UÒÀÖ¾?€Œá¶Cì·ÏöóÀõ.¶}›Àà ö93«H0ö˜?^1¥ºí_3ÆŽÆ4Ûe´!ó°b¸áu<&Úg°®4¨fÈí2ù¦)ÀhKÒpÔÀÓ?Å}Ýü0ŸTzÑH,VÀZj7@ì+ìßN2qnÿEîÊ�®ŸîÛ¿M,1Å�cÌ/”N´ùùí¯#±o?›ó¿¯˜bÔri•ÏN`£ô‡ß¦–LP]z™§îïKÎÅ6¶W^?ý:Ü[1¾cèàBíôJÂ$_±7•è¢GI$¼Ÿ pì´Ž==)š .厸·p:[î,VŠ2\Q¿³½^ÏîëƒÑU¾¯€Rl;æ%Ÿ@&%_%`´ÚoI^Úôu¬ ÏµÃ>@ê×Ñï¿ÁqÅ·éñovjcUÙ­ª¯•Rõéxà` ¿@B1p‘y†-ó‰Ï×´WrüÒL-›¾v7-GÚí½ ¡˜]`âˆu#cõy\ݞƟáüqiÄ=QQ\Èp|AÉEõýæüÅﵘ{õ¾âç“kYWz ™&È,™90€ÌæÃÆ;Ì[ü~u¾û+Æžª·4 ˧Æ>ÿ¹]ýИ¹Tl”ŒCÇ}ýÅÉ€öþ´6Œ“¸n?rIŸá”Yϯ˜[<?Z¿>`íÓA…‹Ô+cˆyÓ^îéØëNâ;–íÛãì{›×æ< SŠØ“ŽJª¿#óÌJ6®ýØï}½|¹wÖÅ{æ™o÷}w³ZÁýU²½/håþCiǪÆWq¼këI¥M[Žç0V®ÐÏ| œ>‡±*º½îé[-œ)‰L&Ø•�WÞ<@1Ê"x ùûtpò’‹ Ëc'óÜN€ìÀÉë½ÏÈâûOå—ëÔJGɶ8²ûu=ųåªúÇ Üo¥B³öáý%2ú–nïâúuœ<€}àsUÙ»(-C¬Û_"ãiî÷˜;Y;Ýʵ'‘XKß­”{Ç}Ïßíÿ˜òís\¢/?Û{Y÷]lÝrô�/Õ^ºüyÌ­ï8Ät{žôﲫ_Ÿ‰‡Fct}Â*€­H‘ò¨˜`ÿ„í#J;’ú¦’Óþ1”ýë[ì¿#g‚ÙãÖ~zü÷‹�´z¦^ÈûÕ–§Å ›¦$eæ€&³¬[ª§M÷*'°-K‚^¯zÜòÿSÌ:Jü¾ßvë¡_{|Â]•«¶(1bó=™ ç´je :vP"È2”:+¬Y~ë¾ l5€ËVŠgRŒ�K»qÞœt”ºŸµŸo§>dgÅ‘uãðòqGž-_Uª| g†Åö¬¤Åzß1ú‘ßæ~Uï*„y¬_åÈWÆÈrÙÚöb;Õp®ôTu<þþ\ò4w‘_ŠtÇX�šuܯ~Ácq-À—ã"úgÆSõÚe‚±ØÛ¸Dçn¯Œ9ðý (þ Ó9+aëo—g§KÈ÷c?ê-pÙa²yI\l÷(5ˆéqÙzsÙï J!®ßÏ;¦Ï#Ëêç™bñÍ–KB-¦2.±Ü �³õé0¹z^³CÙõã^þ̲ØMÞŽ=9qŒ*9ß?º®øè{¯²<SZ 9;,ÑéÑžI•ÅÚšæ•4rf_æPÆ…b#¹Ží3 )2Þj³ïø{xußü›+²jœà[/|žpÜÍêqó±nÿ‚G¾'}ŽÞ“ù3Í8í•\Ç>«j úÌõ;ë?YL(¦\Ãl>¿)Pûqq€ÑdŒe>¨r¬r+@ëfŒ§Á¼+ÔkI©eRn`«$~ë%.ÀSÅ«znÆ\ò×)Àšiö¬ÝØ8Ü,°òºqŸ*LcÙ]‹ßçÒÙ{¯/ ÏáÒCÆ[|ý×ýx0ÁÞË~«ž+“eŠùö=ÝÅÏ2 ½ÄÝÒ;팿ïûP@r`Œ{9üþû 2~OÏwß—ûê1¥°~œ^Çæª�²<f—’tü!Ë5à¸Ú¯�@,ç(®ÏëëÛcÖ)Àí{™ž2”„Ü6¡þ1·ÐTÌ0z¾q\•GjŠ)–p&ý”¹ö1ḭ̂Cl2Âþ;þ=Æ}O�� �IDAT_1« ›±ÃÆãïñ‹»öï°ýstÍ2ÇÖ¾c€»Dâ´oVrÑ�d(S@N¼e¯•„š<¾H”l ˜b8AòL±£ÊËç²¼=E÷µ²k—ò 2ÃüÄþ$ʯ%&4sÀ¯¸^Ìå%¥õÏ'ÚË1æLŠé…ùÛã·ûä€éöÚ_›ðM:BôÊ}\qïËÛß[t¨ZÉKs> ÞÁÚçLïØTGÛS­Ì×Ö9ÆWþW‘Î2=Uµé(&Ùsã®±) ™Õ°:ÊcjÅþs ûþ}à™7p1 Ì×ð,jÇÀØ>ß(ñÈk{!=$_q¸×Ó»±åVï~†ãG¹†=†Vgˆ©òðã_<*àS;úÆÞ«ó8«'+Œq¥Òa #S œþ9ò�Z”>ä 7P*1¦|=ŸÓq«ßü¯ZáÏî»×Ùô:õ;7ȯãQ:.—îÞŸtV@UÈu\€Ðµ½ ¬¦ç1#ìcÿ)ÍŸïEcý3´$à%uPF‰Põ<p€øZ~—bú Z`1 _ÆZpÇÚ Lî鉇’‹˜[Xg燳ܕä[nø:™½™ƒ¶Ê±ÿTÎ;{ Y¯òŒwXBì0K,‘p*¿—y{£»u9®s‡â¼ìó†’ h®¿ß= O{cŒ eÌŒ¡æ™'*ò{\Çc,VgŠÅ7¦•VÄûêX[þ¹ØÒ3€Õ t ò/Ò“Øjë‰ÿ€„1³öÒA€ÈJH濯g*±vqÀ.ôG›>öÛ¬¬åß•SøžÜÊ{j?ßÇ’JÄüxçy·ÿÀà7ûq†WÉ{þçµ÷ô€±£D¤¥4ä~ûªOÐûÌ0Þß¾K�¦b`Ÿî«ôTûT�Ýû9Ð%{í·k+¯¯*o¼ž3þ7ÓÓŒ:[­b´93̬-iÁcx¹ã£–:ü'ä?ØùÑ—rÅõÿ+Î1¬dâ¸`ÿ½3ìYÀÌÆc’‡ëú›ý4þ¼ÿóSln L±ŒA�×øùÁû€¹?Æïc|üu;ï¤Àã¦'N·­¾žÝ7÷Y0ã1¸$HÔæ«^vÿxL1_uös.¸8Q8îh;bW9á_Ö™@GiÉçÇ~@Ù|2‡ùÜúû*é¾áx™”’·7(Eé/”Pì `¦ƒò ÀÞ’¸RÀqdäÍ­’ˆòåÓŽo/©Ècº ÕŒˆ Jâ œ]%ÝZ»�@¯þUmu9�÷ÜÜçVÕFÁnŸ—ZÔ5í´û¥™´ fdáJö.dRi Ð픯+3Fÿ÷èÂV«÷(á³ØæéEíæ­#+?¯Qÿ·zô|Oåý ¿;.Ì`ï-¿à$gE¦^Å\Â1€M3Œ/¥Ã2¨Yz³žžù¶z.–8î¸ÐO(Ú³ô°½¹Tbl¯[ºý~˜·£ïàùµ°Ä.Ü9�q‡ön*k?_PPY5^/ʉ1ˆ7朙„L±,Û¿&@”ñ:Žcvœ«ã v?Ë7.|,Ü«xãkÉ:ïcé)�¸ZXgçìwaõ± ­ô[¬Gžbøùî“åÛó½aòòîK=rGÓÑXb¸�sŒÉÌÚȵTJöcSj–óýþưŽôéøž�ÃÎ÷#Â;‹©ó W°ïœXj{®û€ —^½Š÷dÖ®X[î÷=ØÚ*Ž1´žù|¾XޝLô€Ëµ8í¡ÞëëùQLùí2Ã^Ü}³>³üûåÉ0SßÚë`ÌœÈP2é}¼óžýñî·æú«øÎ, Úî?ùûÏœ§;Ó­óùäjOž?®˜EýØeþ r\rt¸ò, ¿ÞÒ(-U¸+]ÜýN¡ŒÔåû,¥îÿ>Ô‚]æœ/oì/üw¨zXþ£Ò‰ésd�-‰AP5$?ëkKrq)E’ojÿã€Íí¿ášÿ8ÀÌÆSÒ‡øº¿_�³Ì1LýÙØ"ÃkJ%.Ƙ¹þã¯Û¾cŒÍã3}5bŽ”¸6>v¥ž‚}ˆö¨O}÷1É 4í�ÿÆY§Ð“ƨ$zv™<lëÜV@J¹xI¤çÇþî„:Ègúœq˜§ƒ³8-:ˆýÊð·0p˵®QêiÆ0¹8 ‰zÛvÊ~—N=/pÿY8øêélõ¼+àâ˜-¦cªùú>»ë†8¿lOš-¶W,D ¡ Œ½¥GÕv%{µüJë2Îðü1 õ8Gék&ìF¶ëÁ¶;±éŽÅ¤šV1$•éóÏâzß2•$cßòï¨^àr ç tªÏ)�ëÏ¥o1_k*vŽ/§~çÀ”ª7Æ�{n}7 æ¥ñÊ H:Ë|+ó GrÉÐÊ,ƒ…I%²b~õ9£TõQiÒ£ãeÆPºíý߉¢¨²—1V¬aœ?|Ó¥áÀs'¼Œ¼<`䟻Ʉ² «JZ ¥Bñ¼?Îß4–13÷}ùbºJ2Í:È;1’mz'Ø·ýÝK+ëù"{~ûÂ<Xnpfn•̱| %è­ØÀD5äí³ÏP@×瀕Jd²ùç"9µ#ÕÆñX›¤ckÉækOßnå{ºK'ñüuz·ü®Rj•—X+›p‡}lëÈàð³ìŒù×ù®ÆX_UîöË èE ¿!ö+ã±Ã�@»íú^ïµC&I¨Œ½÷Ÿ’ëø}³Ÿ]ïÀ±îoÙsŒ°æÎ)™8KHü1ß�°úV·ÇIì{`ðÉô“ Ïꥀ„®­ïÆÉm#pšn}FXíö™šÜj†vjI=~Ÿþ*F“Jï˜ö×÷â=÷�¨*Ãk¯žcK§‹1ñŽ\<ÝŠ1ö}/Ýÿ“3©º„€ªDª9•e¢!`§bŒ!Pfcˆý�®É‹Ì±n °É fû“ÙWŒ-»@VØ_å™L±_!½?ÆX�Ø·ŸEùkGùºr`«Npì„qM€âб K&²µ¸›=¾ÿùñé_ G×ôôiW„*Jb¹³ØjbŽˆ™ÚŸŽ/Û:·ýçr¯byxÀÇÇ�É\¥œóõåŠ@_¹„±Ô> %xGÀúQâ†Ò±ŽZÄtbÃy»g«XNŸ³[LIIâñÞï¹Ëpë»Õw¡’n¹}Œ2•[•ÚÿwÀÚ×A1ÿØ3�U±½ßàzoo"vÏA]Ï÷»üϾå师ü;Rt=óï›sxßúœëúÕ×!Sê¶ÕµgŠñ :v¡Ïw§=òïiL—Þà:\ÿ컥°¿“H]éñïÈŒ…6¿cÙhÍ—+öK>n¨¥™­©éõIŽÿ.ô¨j§CК’éšúŽö=Œ ¶6æº9h,¨›óÏ1çN°›L(+ˆý–õáB4ö†àÀS”’.¸ÿb®?5¼Úâïçâˆgë»óråK+ú¼’+}ÿ]G2C`l9÷Fšý\ó•óGUv$/?7_éýl'>ðB{ŸÒ‰#Ц'£-:ª=c,š•8œùhôI�×ò¹¿ÙE\Wûq:¿kd4U=.?© P‹±¬öLI.*ÆÛžY ™ìzÑi _Óû˜c.1E $Ñzml+ÿ<ÄØa¯÷ãæº¨2¾õ%u,÷J©øc¡õŸãiת˜aÇŸ(Û.ýØ_@ÂÁ>#k/–×÷â÷¬wüzï‘›×ë%@«-Îb;î]ëZý¦bv©ó©aÂK¥ @6'ébú€¥ ³ „aþÿp{7 é|!ì_9æÏãöo³ý}øb“9æ«_hz“†Ì°µ?¥…+~Ç=0fçÓ¸#ƒGŸÀÕÕÎæz¿¢òr¶Öœ7$+´™ÕS¨î¤¿'¡X‡T¬ÖÂk‘8~TIxiwtÛW¶?tœÅëøJpݾޡp¦+åÄ*ÑAÌV†Ÿ£/sàe¦�»àcL*©†gs¶.ÜЇ)üó~†PªN9¨÷ù=oô¾Ušg·_sqræ†jŸŽ#Ûß¿Ð)H cK=7Ó]n^Ô¨Tº€ÚŒwüügm7} wÌöß»ϼJ‚“—üRþbóºÜ¾fô厒» ÀþZÓŒïÞ—Z2un#ço2¦ÐæB \袾3ïŽO&Sù o&«(s` ÷ò(72Áž%À„Òˆ¬~L"uŽ_Õ‚Ì™6¹ãîÍý>ö÷³ sÎI¬ÔΊl;Þʤèªú yWwdàÚ»n™£ÒˆhÚ¡žþ¾8?øÖ{zY»Ì~å¿Ô׳+2r²ßòðQŒML×÷7 Pµ[-‡ùùç ™] p¾RJÀö¶ Ýæõ™c„áùÈ|ãíÓsGul>†XõüTŽgm= LçÏK'¸³AhÇ ¢ß“°ž¶¤×<À„vºAöyó¦ß=&Ø0±ÂX¹2F/÷,‡Šmv �Eöœfnè\ºÞÁ’oñ¾3ýžu"Âì,œŒýýs@Ò¤ªžûUÑ2ùs¨b€1{ü½‘3¼Ö›Î_·ž¯’.“`Df˜MÿÉ0¬z’‚¾žÈûnR˜�ØÆó¯3lÿ@f æ¯Þ/êý0äq DFQðD‹@X8@«¢ÈédûO›œÈÈ�ãÚïÒƒš{t÷"4ˆò÷ÊÙþ£8¾ <µL¼;»®ËAï1Õuß‹‘G͘›åš�Ö¸o«X_®âºT±!±HWL5“~7vXÊT»b3FØÍ&#lJ$þÇeÿ‹Á•1»¦ý$$06·‘1†L±ßÇ ûÝì¯ëþx\«˜g,FYÆ ™”¬° 6Dãº3¨œà|Ó¶%—öÿW¹ò¸ôÒyì­ÜÓí¨µÃ‡mëô}û¨•_LƒýfÞѺ$£K€•$ã¬uOr1NÔo{ PyÒ’vbõ°Ž(+µúv1S@ª³çö2øJyí&yåªå,NßÌ¥”¢ÔÀ¦Ãí«˜ìïu³®Ö1ÆJ.xíóõ¼•³‚A4È0ŠÁÔå!)þR¯u ­ÿ[¶Ë³Ò6Û“3¼ž·9zµxâ ð]û¹)~Çѯ§fdúó�â¿îk/,YLÕ–ã}£]¸èå%0ŠTlÇ!w¾›XÂó£žÓÎN²·c+û>[ Çl|€Çñz%¬M3‹+€Š×Ó÷ǘÛ,÷óøÛaƬé{‰ð…K äÕŒíÞ+kŸ!Öc²íÚiá>ô| Å Ãm<éñð2;ï9fæÛ‰†±â2³Rø¨Ôq*￸û‡)÷m{¬¿°óv¼®cíc¸ð²ZŠÔé癣¥»�’r˜¿—_ÞÿUÈù“¼R1ÁŽÆ «c°åõâ1®&�6%ÿ,05d`!“Pí¿Œ1Æ·3Íw¾1¦d"Æ2ëÚI”ë4NốÉ (É˳zÀ,¿­wÀfómÆà´¹u-|{lÆ„ò%ºÂ}>åæßaååèÕÃJñù­nÕ/-sP%§tœU¦‘q毻 àik¼´˜b«Dþyyj?—¯Àó±Á°Ü¼ßÌçH3åÐ& Rs§;ÐwÌêþÿ5Ò·ªåia‡gª!#  Håéàuº}v¾tì~e€ÖÍϧ§% «ã]�ì(Óìs *fZŒ}§êé�¡.à4% ôO{~ˆb‰Ä¢²®T¢+ß´c2ân€ØŒ61»ýïƒöï;S cŽi›Ì0 @ý4VŒ±1Æøû;ì—3ŒÅ›Ì®¿`»êñÇ@3À™‹6·9°p¡3µb³ÿ¸ DH”ñv\”Éß?Ó÷¢¯Z¤€±®U!0› º­iÓKreµâr=×7®´ÖJv_ÇN8?�!_c”Š<KǼZ1Æxìd¡c-J(uÍJl1¢Ÿ0Åú1‹ýc°«cÙtóÅzõ¤É°=¾Z/:æ—Ãó¶ßåôäÇK\azUì%U®·ä(»óyNÓQL²¸¯îÏMñŸ¾šaVÇúBéCt-fÞ›LáH9cKä’šøv#“Ô¶'ÁX ŸÃõŸc„!Às²ßgœsSõ;ŠiZÕƒÇÕñŠQ™¹ùÊò*V—¾˜zûëŸå÷¦’üåùñz3)Ì=€‘Èç�ØÖã—12E…ýLó®Þwû,¶ÞòÐëµUß±ãßëî’ók¡Ü3ŒKé­ö`¯ù. œ[.‘ˆ¦ÜØï�–m§}·X”n¼¥s €J(f@:[Ç=ï÷íï§ œ÷–I%H/³ à|%W¢ôÝ�¦ÝyæQ¡©j¹¼âúzÏp;áÃ>s^Ù[h¢sïDâo–xaø]ÀäìwÈ›¦$ЦMÀŒqܲXƒ¯¢}s†‰Oï¶ÚNiºÈÒõQÒý_Ò×ã³R£¹ã|OWwÿéè¹G&Ú±'cA=…t¢¨2k¿:&œfؼº­gžÔ ±SÚÀ}ÚlŸ¬’UR…/w�¬ë‡±í€@­,m;eÀ!3;ìuä€H·]XŒe†Öƒ¶Ö¯ñDk«ž›ê8Jö¤ u9üþ÷â:<_1–êr)@Ó¯¾ð»#úϧGóÉß‹ v,†YÁ�Z:Q݇ ,'¡Ø` ©ØahUy€K5Rî1—L\�™e†Íã Ã3Ƹýéö ã—ÓK1ÐÆX ±y~1Å~1Ĩ¤ã‡ÒPš-Á3•ŽPä½õš°%ŽœèP¬¤ »Sö<¶J/ÈìŠR–Ïg¢\ZH1Ã4ðYM,nwGFÕ-÷}NG6‰¯!€ÄZWÄ[‡„•®bL¸ hË,›ˆ]ÄÞÆR«¢•C¯«˜{ÞêØ0¹UÒŸª¿-C Û%ÛFHÐ"t¬ö¤ñx|›íÆ8ÛåVåÐSP{×ùôWë©ûz�Ì›8®ê¯rÆ@À/öÞÚ:´ê¾žtçQ�¶~åïïÈ³à’ˆ*¿ÏÞþ‰F)V]Ò^ì£ù½P£3�’£�–µdb?Ö/?ÖûÌ~C`C÷’‰ŠŽ×séÚyÇ¥ö»žK+/¦[WΧóFï³ËÊ¥IÑÖøV1P¢¯›¥ÿœä€�.Hë¯óôã^½0©g1¿ ”’2m0Âxz½Pôz ƒbý*6>ï¯â:”4¬b²Ì…Œ1Æòñåö�Þu\ Ý‹¼ŸÅü:…ã Ïžcæ&S’x;ŒMkùìI8ÒvWGÇáŠYe÷—ñïÕn¿=|y¿ß+¦ÐåÑïðº¬}ßÃùåV±‹ÝÆ£éˆ;ìDÌRÜö/™v À2Tìyd²ÔÒˆ¼]Þdö2‡56¯ðÞÒ1Ï÷íóîIîWR_'z}Ÿá…÷{`í}3=%M¨þe®¬ÅçæÒÉ*E=cÔ®~wéŒ�ùþ¹|þø»¸Ö#!V1*íþ;I?xw¤ïréËJjqOÒ.69T¼Ú£†sS1¬vïGiÃÊòvÓ±±=Ænì°yß5MOå§ë…€Z%ݨ¤)«û{ jFÖÿžßÅuP|W*h,•Üe á}hÀêJ/¦L4d”M³€Xd|ÙØaÿœ¹õ/rüwº“Nœ ±¿ÃþÀ˜2Œ1v̰۟(8 ìÛÏ÷¬#GIâÄݯd]@VO²Ç3Ìp¥VPEÕ‹À+BùD"¾~»:ïÞuñ¡#`ŸK²WÞþýv©jó€ÏþŠy\!í¥ž–t wD[ÁÊ$›Ðùå\ÈÈ`­¹g¯"%©ÄW{ˤ¤¼t2È¢C÷öoé÷Q—pÄßQD—Öu]‹|tÜ¢„2YºŒ™çÖuU½ôÛ’µf–/æ¯¶Š‘T=·<_®ÞÄ}ud,•þ3½îMü^UyžÅï¨k_¤ÝvÌÛ·+‘[/£øª(m>öËšAuÌê1U û¾©˜6vo7Þÿ.¤}ºÀGÇá»à‰ø¬ÌßD¹b¿¶RÂ6?%ýƾGZÊx•Àëû \òú.idÎP÷ ` W›Í«ë¥ï~ ©ÕðÓ5ÜÁ˯ïÕ§’>Þµ¾”øcŒ*vïݾéqÏÿ*9õ{qFÖZø×—†WÒÞ·ã  Âñ.cr(�,|~Ã�&Ŕ˘¥:ÆX¹0‡&Îc?™�ÌÒùšy J#^…#íDîÈ,::oå‡ýXÕߺ¹ÇØVúlf~DjŸŸfnå€/€ŽSòæ@ ”2G¡³ú rßê÷×{ÿ½Êù(„'ÅÚçÕ¤Ë?ʪzåRޏP6öOþûq{’=ö( <MI&â}»b¯^Ú0YÇ¢p"#‰-,ÝšÆï³Ç_Ì6Ò±¾¨çrÖcÿéöž‚ì9øþ�À2èðaSñÛ=ß{½¾uU\²tý.ÕÂ1èH$FÀ¥zOÚÚîÿÞÌTÌœžEIN¼o £\5s2·jéÈ®$â”v<¶0FI=vcoEË6g´Õ�Ooz» ÚÝîÇRÛªÔýŠÑ5,{¬2 TÀ.•h<Zÿ|ümön�Ò¿õßpÏdì°<¦Ø”Hœ@ØŸî<î¯òÜlJ%ÆØa7ûküzß"@F:'ˆ è(‡»ÝG 鬛sÉ‘³œˆmL`6bx«ÖÉô­ë’ØÍ‰…Z;Ÿ¯d¯a3¥©ïÓ=ý׺6c07M•MGZ¡ïRZ¢æV.Ô4à fÙ�&†Ð¨Vè£ãÍÙú<�¤ÍeÊüïZIxÖ1ÆPTKbfù|6ŽéðØ2:ŸÝ(Y<ÕJª=™D&7ÍØà÷+€¬þºÀa Õƒ ЫZ#.*¦X pU€c¯*X§úÊôßG% 9Çî,®ë2•¡4ÞZ ‚zõÞ8&E¬—§<Ãû’?Ùû±rÄñq¦|©áøëÄ,¿‡½Áwc„꘡^XµçEÔ××g¦‡ ”âx šýþ" y õó `âqoQ*‹—w­PßUo÷òCû,Ü Æá*V ˜RŽPÊIÔB4íð}¥÷Ç/4ï‡za¡’ÝGæNuŸ]9çiö¾®£týÙÿ•?{#Øü‘áÖ©k[»­ ®%•èÏ_;Â+ëIŸjã2UÞ]†Ø�ØÎ{¥# 6†fÈTÇYÿ³ù¾ŽáÞ VJpZç÷±é®Vö�•~_Ót£´áU>‡óü‹Ùb}v$Þ,�ÝÒ—â>o:f^Å´T÷åû1½YŽ Ðàñêþ+½^—c¯üuþ¾ÝXMqV"PÕËÞ‡ÏG b�Ÿú^X`ìûx0Ç^dÉn%Y5øvï÷põÜÿXåÎ%ùÃ’KlÖ=Ž»Ê êùµûš!É6}摊!öDËS¿/= ¸€š= '2®ø÷-2“ò÷K_*qWâQíãñ\šñ³1Ì~ý#þ.½t«ôºå«ÛÉß'ú 2°*‰Âðšé¥�nÖ¶&àö¿"ŠQæcˆ}ûiDf——J\Û)¥èkûnÿ„«þ¼ÿ%ÜgËó—ÙŽqÆüö‡„b·\cø•¹Š)VÅpÃNL¼Fxöxz¦˜_ÁgW°6&z‡b¬#2¡f¹v ¥b0·c.ùzE¯ª—¯Úï:¯c¥Ü4Æ šÃs�P¢c¾3áW¥¿´¯ˆí›­Ô‹öœ:ÏÅÊÿŽÙçô⳸žÕ#«g_’kÕÓokF¶;_›b”i‰É,•*í�T€EÖ•ôë¶êÕ])FíþËÎà:Æ|Šö wRº‘êü1F“ê]†£@+ ´ÿ|uc]EÉX¿n¿{í¯óïƒøØsüWÂÑ5ðìß*]”°=ÃÖ–,“Ì]õ_ B^Ýv™ú¾!04ëáÞz! 2É,°¤¾ €Ò1N™bÖÛ‘1¢ÀåÇÃ>öÙÆ/»Ö‘œÎlÿ¹æý˜» À`yû;·z\’YtO,%Š^‰œá¼`C:Ñçß™°þt‚rÙÊÊØóçûqª¤1†$ìó’IÒ«zØúÏØa‘y¥ËoÓL¦Š©ë}d¶Õ¿K-9Ê¥ßz’W×�„ùØ[§æ“¥éµTbÎ ÓíÓs<í/ÅXaŸƒÎ™Ã™3dò˜J«¾S:qeláH(­çÍK!Zà±#uj ÔÙÙ{ˆÅ:²ý»ïØç±.ÄbçRÇRÞ¡„Ì*ΫîW�Þ.P¢Ê_Kãùëê�(5zëW8¯cÆb~€µ@Ó-Ý“w)©Ï›M�l9Ôßåý({×}ÓÏ >§±ß)�°z~£Ï3:ûã@{b¾onLÔ±°b”>~¾k¨ú�´\2¯¦~ÈëfzŠIÕc E)AhÕÌ7Uþ¯ñõ}Óã­¥«tºâͽ÷ý,w$«rLÉÃÿ±ãã(ÀËG„±åŒ�i©„áèK!:k�m“1Ä>þÈäš@׿ÝÑA6ÿ5L2µýl�wÀlþ(™Xí±�2–ïÍ&Sì×Çþïæ8Ô@ñî@iEO?+àj<#”PZC¬[ŒÇB»~Òa€ùhÝ^;éX =ë·.wµbû°•šù„ûÍ9šÐqz~�eËvVvk`HGyÁþí¯¾4joé€ñr_Q±eÖï¡%t@Úÿ�:H£j?´­»_aë;wð£#ÑZÅhÒÖ…´Îôèq¦ZÏ¢d—ZÔ1„øý]Àè³€Y œq†Ïe(¦Ú.ÐÔØvÛ«+]YݯÒÙË¿ÀLþ�� �IDAT"¹}ŽOÒ±gº½ Æó&à·oqt:࿦%*àa½ó…�ËžÝ{˜aì=ïãe¼Çè÷ëElÌá¡Êe¿W[퀻PŠ¥gLìøýçŒîøÝ‹í•`Ë8°çìóüg@¢²þt–K÷¿Sù—öøxv¦>Û°|AÖ¾u¡ÿËq¼ÿŸÞNlgA2D^ÉÖ¦¯˜aø\ ¢‡_¥çkÃå{3 ,y©Ñ(a¨ÊwKG3æX»¬DÓV»+ÀŸçëíîâ/îúù{øú±XdLòê0$]ÉQmObûžˆ_w¬ÿœ_?y?ÚœO×Üßi3ÂïW0ÎØ³€0}_‹ÏÓc¼‹¥·ïC9ò}ùÖ<™ÇhŠ÷s& 2Äj&‘wØ3àõud@ ––?gÙw-_X}¬‡½‹íQ;Êô©$wÓÕõBéK{+|òïÖJßwÕ÷.ËÏÆR«Ðxœ}¾?Î?‰ë[=aJ%~Ó€#·%õèë™åÊÛÏKêiæRÏVÿã1ñ„ 4ͳ-2Æ;ßžÐðP’»ÖcDévÈó¿§b\¡$d³ëëì³í7îåÜc¶©qRÅ8SçU¿­�Ï»àêlcx‘XdjÀý•¥RˆI¾Uzª¾Îþáö¼d¢ÆT ±18ðÅÌßwc†ýô`†MÉÄ?1Åìu˜®eŠa¾·ë½ïÿ$sÇ/t‚5†š é\~²’ÂÀôÆã~»ùo­‰­�2b øŠšû;¦™bGWÎú•²Ÿ}möcUâ\q¥fwžOeI0¡íhÏ#pžõŸ—RñŽ„‹IA1§PZ±¢¾¿ ë¨óŒ¸sެmÖQ¸Êcþù|¹£ð"LâÑî£Ã”ý>Ì”£W2»7”T‹Àâ1‹Og†\$P†éuO=�H=µµ´"¿OG†.¯Ê·C< @)ëIöá•ü>-ÅÏï~·Ûþ.—�à£Th%¸Ÿ³?êÕ^õ÷éˆu~>‘¯Å<³ZwøXR°©cÛÑ~·T½Pbp}Gç‚•(}Øm§¬ž+ß8îSß1Û.øýg Y”M€sÖsµî#ì÷ÒE%„ÚýçßÊ}Ü•ü«Îßžá Yß×ÏÒÍñ­ß«Ø`ø½G³ÀBó|W9ÃaÑ_3–ÔxKå´‡ÊQm¹z¿7®úp�ïîÓ�Ÿoomja¤W^Éõó½ãz[oÌ¿£hÂlÝ’ƒ±|;«½‘Äñ|? óTìBW_ÞÆö¸@jåýr(2 Ê¿XÎà¾3ÂŽæ;Sl xðýÿä�ð8?^±šàj/ —Ϊ¡40–ÅjcÏËY¨Œ= W.UØ4€¬¬¯+=¥ýý³¿vºŽ´ëßÖÔó“×göÏcíT}÷X¿´’‘ó9®–°÷ÂrŒ?‰ëŸäý¤üN*±cG�WÖ^?BûÎã«:é®~ïûö¿*=ª–JœGßïGýÐo/Å`›€!Æûšï•¶.ƒ©„z†1ܪ˜nhßàY1ξ7߇ª}°ÔL=-gÚU A¿²É�CSˆŠ9–Æ3÷S3÷QÆ–kCz‘¦k$i=o’‰Ó~Ã1Æ›RŠ¿Åû¯Ù*À̤ÿ�ºV>ºûVŒ±i¿H€m 3Ìç3Æ Ìf¿Â>_ñ¨¥êúÜ)ÍÆ>Tëõ'žÜh0ê éÄ=—0¾nöƒŒcnŸ[3«‚tk-~~´+Ñ…vŽª1ÔŠ²eU»í?ðò&PÕÊo/Ž9sl¸ë™C WÜór¾A~oÞ’¢;²9Jå Ho9Ö¼Ã$2=1}›:kg+ÅÊçM%x«˜ý§ÇOÀÑ!†1…ŽJš¢iàã Îs æÜ–ZTŒ¬Cé(s®/YÇ÷»ïŸ£�[4ÎlêþÚ-^B£^£¸¿{\§w”éÆŸ `R¿{íkˆLjõDÅ… ·ý½¨ w÷bEi{KÇ5(ñÇLKü~Î|¶édMº+f˜ýžeõF¦±-¯Zpq±–ávüûœÕ—µŸ}ÿbýX=Xúìûm‰™$+‘µ~,XLG-øò@@=®½g?ÇdÁûbì!—¿Š†Fæ| ÂLà¹Àù|a‘µ $)… ŸgB±_3‚×ûawaYÕ±dÙ¸õ:TyÑð}5¥}9ÀÓñ¥2&½$⑬)†KíPôó¾FÈ`Ç%ðæ{äûÓ4ƒ¨Çd™ôÜw…óz!.*˜L D,cŒ'ãYxc¼ß1+ cói L;TÙ÷˜õ“ÛqŒp€ïgí®Þc¾>ñ žº?ï2 b=ì~ d}µCÝ?AŸgÆìµƒ2Ö>Ù‚…øûD µRšÁrûëOTªÓš½þœÿ!¯×P(`¯.V˜ã{f2®à¤�q4Ö^ßG|¿©öc*öÝÓ¬ªží°§ö“ �~]%ØFvcUUíÉ™Wª<ýrbú @ëÅDhì¶ ¶Ï×0Í*IÏ*†›èຠ@U�–1djQ %àJI/¢ýOìÿSœß5zÿ?ð€‹)æí?’öÛ¸d\))Eo¿¸-�tizÖ&0²_öGH‡9¢çñiÙ4ØK€p@¤Öþ¯s‰ù0Vb3qÞƒ„νë@¨…y;é×W¥Ù~R¨8!k?Ÿ@ë•tÊá6·SÂÈ®¼¿ =âR…¾ÖÖÂV’s¼ð:Å|;‡};¥³’W^ÆXcèpî;vl» šZ,_d�äÀ ë½ìý´/åk€’’ÖÛKçXîzŸ·Ë%ÄìòŒÂ!£P»´cDñò~Öí©~Ï ˜ÃrT@kìyëØQÀë(/ZÎ`ÛÍÆ.»ÑW‚bÇaäŠÑÂ%Ø4¤²W›ÊËÐýû"¤_í÷iîãyeŒ¡•}Wx½'°¯�ÿ uüÆtóØ ê½|y|—QR“›¾VN¸`#³Õ~‘Á­}¬Þ–ÆúA§W)îWRyÊ:ßc5ÒÁgÓêÈ;ƒ¦‡Lí£ãÙ¾¥oÐ*FXC)b9z«~Çû8¾]Žã¸PIÔ³•t(^ÿ’^Y?÷Õ,>¾Ü)ãÙ¶OUí~Úa à%oóÖ.cË‚ýÏYt^îÇ{ÏOÁ&Ÿ¹ž6íº]ΰõï£vòŒ0¢ðÅl;íñ2Fô L»·�ÔÂÆ¨cU¡éõ^®)•xrWÞJÈú?‹%õ2X¾‹áÃgSªÎÆî|4öž8ÁqI@^Êûy{©\øûæ=GÉ{O&jul3UŸcVK_öcvûö: ¤0�–Iƒúôx=ÝûkŒÍV1¸¦4"óO,Gù{¸Oµ¤9߈!¶Ê‹À“ÈX=*éÇaîï˜z/¨÷À,׎2Vyl¾kÿÝí÷ËS1‹òkŸ¹ÔeTùû¡V[]©ÅhåÒ‹ª|ýëv c¡í1w™](é©ÓÙZP@ajá>aŸbl©c3]R.U¾/µ[ 1oÿyüw¤þö‹¶€0¼o4÷§D"J%®ó*߯M2ÍK+ú˜aÊ2!†L*)3ØòÚÖŒžC Çà¹ÛÞâpwƒAæ[F­ èsæ8Ë!ŸA 1?¯åýyûé ¸ž¸#„Ž»ÏúAæ Š×ù•Ù™D¦Ÿ1 :éøúF¦™2¿bý-8RfëY ¬bˆudþ¹äÒœÓíL*Ñ– ËçóUý¸©¤¢Ž2Pb ?Ť¬9LÇÊ©qfÍ9�†ÊÁ®€Æ (Ë÷» ¦êís”)V•£J?Ël;ú»öcí1ÜôïÌc¨]$àÅÕ pþ:à‹ŸÝeöïˆgí¸¦þ}*&gŽeýÞ2œ¬å¹gù]®>{ê"¿³“W¿ÏWC•?Î\¶ŸõÊ@º„úô�4]î,žeu(çcoü®Öﯜñ‚±žºÓJ\(—×t¿]ÛýÂ8kŒï9 ¾Ã±ã°(µx¾.€Ì$í{!—Ö ¸°ÝóŒm‡Ø·Òб}blZuÿv~°�,w¶Ðk‡±ô*îßc8øvYùGI¾#†ç'è—˱™÷è>„ Ôìd*öÞIŽÀx}jG®š‰O&Êu뮇}óLd MƘ}ÞßÍuß[Û;¬äô�Æþ_öþf9–[Y„±4!«È—º3Ù–ŽÝ­ëñ4n騕dš}/ÅUÅ5bªPˆðp$×>mmöÅ€ÉüC($‡{`¾µåÀAìáY=L@"sLçï›ø>ÚßWŽé¼ek`ò{a˜¯y]O± Ädx?ÆøÒï)2ºx;º Ëõdqà¥W?k+c†UöêjhcÏã“)6÷_£¢‹V1½myžÇ’ª|»ï«r)?×QQQ'z?¦[¶õÈtŒ¦Ò»8ú|¯ßRê÷IåÛ3˜4 „ç¹ÕÀO¿Š]÷w¼^Œ­“¬*‡²êº.3Œ×C”ÞüÜB$V&€8#¨˜Z?Ší€ëÿ)®Kc| íŸìºÌ6´V,±Cì×»Tâ4<yf˜e‚Y`ì¯Gì±ÈàÊ™aþºÅûC¦c%m,1e,Û·1tÜŒQ­Xž†³D†H‡q¢ƒ-czÄÔÊÐdÅ(w±_¨(¥Ø[‹\+¨ïº¦{¹gŽ?ö@è}é?o¤Þ¯8?'*Ë [ûèF�ƒ;ri› q0°zÂ÷Içïó:+)¨¤®x~�ôæò}¿ËENp˜ã$c–æiÑ¡ÿfö3åhŒ%[ÃÜ<`†æûúmû>+ã+�hŸ©€²=&Ø÷Êo÷y]_=ï(À¦ö2ÞêzÀú¨îùïv DZ¿ä€Js­Ç£Vÿ>ŸýEë«^[×­÷Ç_ä¼®8ì˜eFñ|+‡ùÇý“ʸŠí­Ç\ÂïƒÈ8c ¥ãÎâ»´|TßY4ýb ãB–›€G¦ˆ°ãú,¬§ËÇRÌJëo<޶+5.”mÅëØU|êW±†¸Ã¥ÿøø²/™º<½¹í2¯Üq}´ØÏún±|jœ˜-t[ÀÀª7•¯ À¯%ùˆñT޵Ù|#ptýÄ qŒ„EÇáçz€“<R1Äz@_t³®z¶í®cü:%¦c')…×ÎP*ñ+l�lJ$f1¶ØqÛN,�¦ÛIí�g~˜åˆžÆÔQùeÇ;å<>Bœ±¤°ü=-žw±eõ™ÙûðPéôì¹È7]<½ À4º|µ4!@¯¦^týÖfãU½~ÒÆ°zÖ1þ åˆÜ@Sž/�~ÜóCc†ù÷(þžÙø¾ÃÈÃ2^&Àquõ³¬ÇˆÌbúr(©=¾ÕõËsðüJô’‰ýv“3ª˜Zû ·“ê8 S1:óXh �ÔL©î’>rz:œžª¯.£UIª|óûëôæuU¬.Å£×ù_ò¼º~šÚæu°S±¿Œ)€î–>çˆ`èãÏ�Ù/.YË ›Û_Íþ²ß!Vײ@uc~Íçü®[RŠóz%¡8Æ ³@ÝÜÿ¯1Ñþ¯Næ¸Æ ê ë Œæ(2šr¦Øõ1óS#+q0Tä»c;ÈŽ­¨ÕéäÀW\Ù›~þ÷7«îâ®äkQocTnt0¾„vÇï_ŽJÕ®€U1Øø \¿Çˆ¸â· §ÕÖq×ù�Ìçï<Î!ÿ^ ç,®Óf%¿㢷,Øôçѡܟ‹z!ßÚ ˜ù÷õéü§�…eXùþq`ì³�Zü(æÛQÇt¼ÿf»�[÷¹û¿3gtÅôòz;7cÇi~Êÿ0Š�òt¤W¿ÈçÄ&÷—êýÈæ¬Wé9˜ê’xFïÅõ»ŒñÜýîÌTQšø–ndöút^Â÷@-¤âÌ®³O¾¹ëâÂ(`U@çW1ŽŒ8/™[œ–¡DÆt:*K”ïW×w¯Ffõ±qå¾ÔøV^ÅcDiKÐøã†ØëèͪäJâÛ+(ØÊ‡etÙ}¹2G%=«¦—P./©ëÝ›^âT˜ß÷äøúeÂŽ¥´˜gØß}¯±>ª3(ùÈc¢õÜYLñȪ…´Ó,ð™W×ô¸Í/NgúÕ¯ô>¥ï=Èc;|»Ê�2ÿ]YÌ5”2¬úì;¶Ί)´J>™>op?“NŒùñ3ÛÕ_Öí3לÄós±Kå`ïÇ S€Çîû›t»‡Ø¾¨ËÒ{€xƒôqßJŒ®ë'“ðšŽ+³1¶nû{ žFàaK -À_¯ÀËÍ· ”ôìH>ŽôübˆeÌVeš©ÞŸxÁmö$±çÖݵM ¦«ë?ÇRýCµßcäu‚>=žÎ~y+ ­W}ý^¿×Íw-ÁxÍ®#L+ÅœR€Ùã4MÃXcÊ6b‹9C€N1ÁLì3—Þ_~&Wÿv%föݤÿº^=ö�` Hã 1üÏpÝÞÆãËÿ¯ácŠýŸÇUÿw¸5â-ócšuñVCܯœ:Ë)›X©•W؆®t¢Î*‰>1ÝƸe¾¬nk7ÚÎ%½º„áÄ;»“M•Dâ-•¯‡•w¸}}l1=e˜:Ã>Ƽã,®,µù¶O”vŒµÌͮзùÅÚ´ùïØ”˜ƒ¹="�V­ ΢9Ì”ñwôR’ôpƒ²ºþyL±uÿ¬¿ ¹šÕ«¿þ{cÕû©ö³c‰áïrÌ#õûÅrv¸ÊñÜ~º1д¤än¾öž¯¯¹L.~¦×í·ÿó�­z.êïî±gïG¹:í¥åPî¡ãëû}}\H}XÆpÆèÏ¥Ñ0¦Þ‹Ûêû¿Ò}û]ÅÒ( Èy…¾Fó»T;½­ïÆ”FÌ?{€1)Q¢íL˯Ú^°Ókq;l—ÇÒgî~h\1ÂV>‘Éûop<s|­q·ŸØX¾Œñˆé¨ýõ~#£ %Ë–D½/G|:w”zÃúéØœ¿Ùíz.øð¶3ߌÆÛÑÑ÷ÁÖÏ­>vß7Ó+ç»±21y>u9¸ãm×µbXû|"SªoÐa¦€R ³õê¯c,‰Dð<O†ØÜ x7ëï|—NÄQíË…±—øwM·›˜®Ê<ãǺ³sÀR`°~sÀÝÛ’ì2cr‡¬–Ž;Ñë é6>ßÈ {>ØŒ�€!�ŒL%#ŽIG¾Bú¸éZ©Ðx´l¡Õ|_Þõ ¶@ J&*3í%?²»³ïü3ü,Y5^c`O¡g:…tvìÞï]�G3ĦU¢¢’=ʸü&šÏõû1¸ö{ ˆyÇkæYWºQ1²º€¿zÎnùUûBæ_~Ÿëm´ÒûƦմOÅäRé$€VÅðBÆY €SÏE)H„Ñû’‰»ÙŠ Æ$ ‘öÙÿmpc†š˜aÖþ$±Äl~&LI'Úã·û0¦V Ï-:8vW4ã„°@æ+ c, ­€±#H¹ð}ÐàiGWƧìq^b·Ut=Wi»Éš_IVKáŠÚÈx4tÜEÇ W¹D€ÙŠï ¤�Ù¼­dç[¿bý2¾Êj5aŒ8+UeWô_ÌŠvï8ÖQš:ÒcP×±«æÊ|ž®—êŠõÉ™šÔi+¥Å»Ðû`ö½‡ÝuÄ—‘KíE è%½?ƪ�·‘^·LU»±¶FqÿQ ë(ð׋§bFU«ýŸÀâ[‚ïï?úïݱ|°TÈñÛêznT•ÆKKqŽíO ×‘¢f£ ßÿóö­¿ûü¸î÷•¤ò9|w0Œ‰¢ë5 7‹ ,¼½¤ÏAæ¶ø ²Ý—ŒM%:¤w-ŽGñ|þ^ÞÔ·Ëc|®íØÀWù†ÎóKú½cQŠr.ù‚¯¼´va_�ÅçQ“‰Ã˜`3Ÿ•ë±]_îŽïs{ÜÎÞsSÉ—üÊ7¯gRtÍyßX¿Þ·sðûÄ ›¦¥Ñ”å_’Ýb+fJ'.`JÏG-Àù{ ¶í¶Wì1Œ‡ÀÎÇ´Äš/O<?dèÄšf�«^ÞS‘.!f>&…ºÞ¿ØOª…™iàªçpÖ1ÃÐx{y@V7=¬7Ÿo²Ž3c|>W»Y¿/—ȼ™–Ϋê)¦ã%9£! k#03gÏ�äÙtlûû6ø{¼$W 'cŒŒ'�ö¡™sª>N®Èx«Óñ¶ba]é~&͘ÙÑ÷é›�B4ãè9Ý?ÎÜôù~z�Ÿ_ªb·û’Šh=¦ZŒ-¦ž_ÅË­–8ìÕŸŽI¶»0¡»NÇZã¦~·È°Sí^ߊùÕ`Ž¡)†Vta~ZÏ#Œ´Y:F*‘¦ûÔFt1Äpÿ ýB¬€Eà ³\Bcˆy[Çcì±KŒÅ0C€ÌJ+Þ¶{Òhûææµt7-½€¥DFV˜v]Ÿ[iˆRgp¸wƒ)ï[Î-é¯xÏW±ÞL¢f]ciÝžŠ1LT¬—˜>cráùõ+£C 'ügy?“ŽÊ˜]Õ uÖþ-SîØûɹ(EunöÝçÕ�Áç� ÍHãûÕñx™_ó½õí,ÿOI)öÊ­™cÊz ¨K ÕL­zŸÎO¤©ö£u[tœŸÅó.!Ý^yjà„3ùŽÆ^Ûµ ù/7î¨ï35?küw¹ím!±ý¾%é~Æüw ëëì¾óºs#½iŒ±¬&TÌm•o™ØØÿUŒõËÐÏïIÒLÃïç×íë¼]\°5¿Œ‘ÀZH¶¹Ï,ÌãË} ×ü¬#/$z9 û(H¤yúµâD?&ýÇ�¯pŒ¨˜[X5çO‹ù›ÀgtXÛçuÖq½1—@·åàéúzEæZè¨Þ—è^QõÉ¡Åy=2ÿún¨)‘è¥wc‡õ"²Äüç¹ZVçætÿË”>°ÆRN¦½0€Óšu0GGóbdt™Áªü¶ß~0?À?ðqywL¬/<6ŸJžÏÚÇk’ŽÀ2G¼—dDiÄÈ´SÏáæû- ܳghaÏ£b TéíÙ®tŸ6•ï½òÄXhØîs�Ìš• ¬™„¸›U:8ÃxWǬZåU1³<ö4"0††Àظï›ë¿Ü½/‚9÷å905ñýÄ÷)æ»ã—¬™,Ú9Ê,~?zíOÅ«¥ø|N€¿C ™A<ÖÖÎ4ó« «.§²= ¿ŸÞl¾|hóõ Ò©�.dRíÆòÒŒ²Š¹6Šã¹éa•¥@SÂìcD€KI#6Òû§H§+8ŸóOv¾›¯›d¢¨&SŒ0Æ~çI<€²_ |ý58`e¯»1Änç—„¢g†ýIî³R‰SñÿëÐ|>¢ãÿvTK¢©‰>.åă (cú~BsÁXg]ir—‚ÀüM«»A ÎÉÙï±âÿûJæ¨rǬ}@¯«É|k‡JÂm94ùÊ·˜næ`C (:ê.¥ãÐÖBtxÔO\ªêëÝáè:—¬˜cl¢e%ΘcÖÞ—k~¯çðzŽåîI›íÆLÊŸßoïuÌ 52f.ôºÿiI;Íüšö’ÞW ÎWL«‘.J{�WÌï × ñÜ%%7Ó{¡Û\©çö,9ò‘ß÷½ìLþËós´Eï]¯Ÿ¢b´!ð5ç=SjÀ8(JÍ=2(n{ �àâþ÷çfË;Ü}ñ=ðßÑœ™È¾k<ÈQ9ô lý#s;s˜\ ¶æ¯ƒ¿­TœwàÏóç‚ grfKlg|!–rHÞúÐ\ÇÖôx7]Wî’¶,W¤è¬Í¥/ázvŸeŠÙó¸Ë.”BF#V9Àc'5VõÂÎÛrö&ÆtU~2Ž9JFzIR>C†ZÇå¥1ómeÚÑ|¹?öå>ÎXó%ë¯/÷J)Q2Ô—‹k?“‰aϼ½Òù†-ØS2qŒá´cX{|ÿ¸¤í“•ƒ×QC—Ð°Û Ðñ|¬g‰ HcL´u<~×ìó¢Ûy¯½¾—-lHÒÆßXùh'½^¹ºÀ[ü½W:ãR¢ë½ÑùgR‹¶~&ƒË¦7F_tæ×¸9cÑÚÂÆðÀÌÛàŽzž÷Ë~ÜE%•øQõ3“!·˜”Wùþ+ÅŸY¯Ã~cd€/§n¯Zb“í+ ¨Žmås¢"¹í3$'sNBÈÄZ1ؼ)‰¾ âùÑûÈuc“}n@Ì3kô§¼|Z²Q•sWbñ³ òö½öP”T(µh¤+«˜`Ýtèõ Ãô¶$!H™aÓ~KÓøý±Œ0&ihÓQç­M@îÏ{ì°?ÇÿÀZ–cÿîÃà98Ê­1éDtä’‡*å˜.—ªéÆÙˆß ¥GtL-I”1ìÊø"ò3†’5gØV¦‚N3©’Nýõ#º¨•ßÞª‰SÖ=NGÝÍ‘0¡è˜gŽÍ˜Nt|¢£r¦cWæG §‹1)ž$årHZǤuÜZ‡fÆøÙYYoÓ·çÏàp`Ò˜ÞŽ¤â:þžß—Ì{Ûºžçc¿÷®Žæ¿°¦Rúþ@Ú±[(I¦�6 ø+à'g‚©ûÑÎ0SåáÀÚYäç<8ƒ«ŽpÒ“B잯ïË!刿Ûš vì}Qïç9´³~Œ:ßß½„~”õ[õײ.Ÿg¯ïºýIÿŠÆ�![?ž¡ìˆÄïWÞ«…êû¿O¹!³™bøR ³l~æ¸`Žlý°ß±§T0 - kÄ>§û«5éÂI�� �IDAT£ã2ÿíGÿ3Q»R„÷ç|�P¬´5€2Ϙ;‰XG %Å|:—ÇøLWÈ1×ö~-Õn'ÆË€¨uý$#/!½la•JŒ8?ÄsLòÕÎ*iRTn°À%ÖW×ýrº;’Oà`ZL±½ô²/™ßâõùsºÌ°!ÊÑOSE ÌÏ­u XÇ3Þ‡m¬½ÄXu÷mÕs�3Œ „åL•+}ï:1æz󲄸ú¼Ò-%¬eRŒ>õ³{_™[·§Èãcm½‹|+ÛImIøí¥‡±È<𵟞*J.V± \¯Ú¾±Þíqh䀬Ï_ƤRþ»o™ŽAÔè(ÇŒ¨ž¿žwr€´¨ÇF:ßýÆÈêKÁZ‹ÀÓç€Í”Ê9iÏ�Œá¶Æ¡„�V”ÄCÀ‹ßW{= DÍ,ëåo„ó|_w5jORÿγùó¿I óÝeÌíf]ãõqßG ‹Hþ8FŒ½…ÖœTú•uï#1Ã~Ì®¯ì‡1>+‰%F²›Ý˜aûË�d¿Ý·ó¼ÀsÌ`¿ &¥øÇc‹ÀX%Íè´50Ϥ/¦Ã†­ÎЍE='l<8pmjå_¢þºs Ž08s÷Î]~Ö!æŸßƒ¦4¸†`²³õÓ«•îê÷ó@l'æÁ›K52H,pfË“9¾¬ïæH[1æþþõ»ø•©Zb&3+ÆÞï'‚ 0›ŽËa¶˜®ªG»Uçoéz)¯ñè¢#hˆ´õïk•(ѾÂïÍøåç³zéž÷éŸÝöÞ{¬̸äâ÷æÔ嘆’‚Uz]É¿—Öu*_Ø/Dæ™Ê¯Õ•ó2VºJ±ëð<Ê «L÷Fg8ïKh™¡¾äÕþçZ¢ú½uêªßG‹@*cˆ)&Tþ®€Íøb̆ËF}úïÔx�AöûÀê%_ÙºJeÇ;¿²ïïÏð@‰ÅK„¬û³c,� Íö¨)c »”äÞ©Ýsr�“§jÿû,Õ3vc¿ð}¬˜îN LÅ #׫’pé¶Ço_xr)? Œñ…ƒj\µ�«Y¯{ÄšëZIß±za”8~ÝašE€¯ZPÉ•Iêß]­¬þ>+ºßïõø\ÎçüùndŒ¾yGìépJø^éþеÇØL†I½âž½—e¬°þýµ ±éðöRiÚ¬´Ýzÿ8P`™ÆÝ÷Á2wØy_¿žñ‚�Àó#=U޳øîá‚`ó¥c ùvó‘ÿîx½v¼+ ·sí¸çýÁq& ÖJ VRgWšŽm¯¾õ{À·Á¥îò…!ÈÔô�áŠmþzã¹xþíž³¹í]í5eÄf¾};}ßøx€ïä�¶C,¿šžTLª<¿}FÚs²ó[?ß¿g𙄀 gŠÕ@ØÑ¥%�…Œ­êýÃô<0U•¿Ï]WŒº!Îçýηf»Âüõ%*sñl›†Ò‚„™õؘðyIzÝ| ¸¾-FÚc|q1¹(ð5²_ãñ1¯Kl_¿Üÿ2~½ŸŸ1ǘ°Ï$§ýù8?óýïÀc�›eŠù}tèOó‹É”± —=*õÍæ€ñ4üŠèf÷e@ž°Ko¢]¦Û]PJnÚAÙË·þäЗr 2¾#G ”r‰ÍøÈW®FôÙâJúUþèzŸ ¿õégÀ2ÕnÇ£ô—/‡Š¤cní2¹øñcŒ1Ë”kt´ø|E@ˆÿN PŽÎ\Š ¥ð|Ì Ê!^3 P1½ü<2E9#çû3ƾOúXÂë¾¶îÓåV’yÝüs)ÅØÿõ˜tÿS¿‡^wÎkªZ5�[•(ÿ>©ß­ËḊ …ý5y‘ŒÀ>@ÉÔ5“Ó»y| éEË%°k™ÒðZ9¦=cL92b¬M,9JSâUÕ‚+d¼ÍrÎm¶ò¸[q¥ÿræÊ+G]ébkº_ä°]Pd÷wÝ÷»ïcVo+®›@º¯»’çÃŽÃðøgò‹’„1–Õ¥|¦áx'wŒ×±¤ËTñ_øDæƒØŸ±•þÄ!@| íw-¨ÊeZš^/¥±õ°ópÖŠ åï¾iÊ¡_ÇVäOÓOÏJ³<§Çþ^9têÈ„UååõÁ®Ci@ÌÁëðõ€ÒœÎ`¦�€/Þòl®ïH.IÎUÏ6ÿñûqï;2¹®¢_ñŽÏ£‰×³Ží÷È�T!#øó| ùY<{ol”;æèÖŽû X8¹û+ ¥ŠõÄ$ñ²ï‰æriÏ´_d¼õòoóÀ0˨Ârð|ÅtóñÚócÛÍ9yÞÇbJæïk_½qÝU÷¶DùvÛQq©ž»Ž«zõ¿ìÚ{¦W5ŒiíèB•cÀ¡Š…¥€/ ,ñô"3®ËüÂtøïÿ´]No ˜ëK)îsϹÍúñÛJsYÅSÇ[€Ô†ÑôT~’ç( ­Æhz?¸=,¡eR‡‘XbÖ¬¤">7{Οw�,sH€­gqâ46P³Ãô×Á8z…ã^rf\hÒÏüÍû«˜^ðÁ`ÜÉ:2>Q¹Êô¹éîˆOôj`¬g'9±òZðÑ¾Ï å¾EÇS.íÄ|gã0›ŽÀ逸í¿È‰¸gˆé|¢•¿_»ì;Œ#+uÅίí×Ô±W9³_UIJÚ­>>³s1P÷Ç+ #Ö JÖ 8Án?“…ý·á˜DJ(. l=»í®¤éåì}þL­|æ¾ÿ ãê³ùÿOçC`þ^ã}y‹ê~™YGð¥He^™`úýöç#“ˆ}?º1°6}¿Â:‰¾ÜøuÓç¹M ëÁKïb:ɰë>w1À¸T¶·s(gÇabLÿÆØ}/á{Ñ‘~‹î…³h¸ín=yë¶;5ŸwîJÂE`\I¸õ "œpqÛfI?„ñ7;ÏÏ~·ë¸äw2ÞÉÚ›R$°ï=ÏÆÅ6½ì÷÷ïÙ9´c·VÒˆöüü°•µ0ê,Ó³Û@®öȵãqý¶»Ös„wíjÏ8öø.ÑÈ[éƒíïªò“ÍK0f™PÏ!ÅéÐçŽæ2÷wID»cŒç{Œ°g³?Ÿÿ:n1ÄÔ÷©’jœÀ2i|p éÏúáÒlè÷¿ßóˆýM1ª$`gíÖ0W¿Åóê}S@jÂúqÏ*€Á?÷¸¤#Æ[é"ó='Â1Ÿ…¯—a~ÿyì¶¿›! ó4fÌ­ªÄïò»ývg„½êXb&üwƘ~µñØišùÓk§Ï¡ TgO °f†=§Çc{ó�YmG)~?–W7ê:d\íÅD\Ì·J±÷=®ÓÉ×õ1ïç�`°ó××Ì®îïâóW2¨ŒÄà€ãÊæõÈ S×)àL=·¾ðù•)�Þï1,},&Ý/ÍJ'bú¸¯�8ÿ¼?†2òT>7f˜½î*X±·3ÙrÇ÷™N„––@ÞFhÇt½é‰B—“0ÆhMÄsà'Þ»AŠ«çÔOnzÚÓå¤Ó³µ›¡’ÔB€qÙ€¡c®h�,£ì3@IÕŽ_!ËÙN Æ2Såõ³(IuKÿkšîeŒò¼Ý¹ï¥×:ÜB´Îï¾Rí´¯Á!ʀƮdÝ./sÇÁÎîÓÇ=S¬¸âyÅúÿÛÒºL¾ãŒ?ÿž­ö—·öûñh™ª5 <ůžb|uNÏäcR–Y??†r`ÇÔl¼ƒ P+=ÉN,©YmÈTVõ;%s‘Ù:N`}r‡·fÈæòX?Љâ×꾎ÛçEiá+l~ç Ȥ0u9ÔB+õ;íÇêxïÊ5žü>Œ0ŒÙ¦bT¦Ý0l¦àŸ”*7%½”äV?~nó[­Hæü)´cŒµ…æÛ;¾Gª6úíb–ÏÇÚŠ€„Ž|þ±>Xl ¬¾ p†ü(E�„YCé6œbÿlËy Û]ó̰%y·9/‡agé‡Ýϱ*ß‹ †åÙÉ}ö”z<ÏÚ‹’š³Ò‰ZõÍ€¨ÅÈ*l2¿D‚ÒsZ‚.WÄ™1ç®ãÚšïáý}¦&š‘gËcëåO1¡ñ=RLéÊbì­aR´[oÚ=ßY³êÃn«ô#•S•Åv¯é�æ’cìK{òãu}p¿Éd„aì°“lÙøymŸÝõ߯³xÿÞ³t&�F°j+ïûÈÅh‹Éò:nŽûìº*]͇«zöÏöø>ŒÉ¸g  «F´œÁ]1²jÀ¬[o] ŠóíI¦SÙ÷]� ŸWÕó^½ªß¹zþþïçò7® 2öãÎõä:œ)€ ÿXÜ7ŠýJŠÑ™‰!öñ‡Œ¹5„d"· €ùØb3¦Ø”LüËÜ‘<×Äû÷ýø)ög¸ï�Œ$ÝÿºïG‰ƒ8›ÇíV3”4Ç4/e2ƒµÆa^”—_</Ñq8˜t’X]×dOZ‘åƒí££íÒø¤Å•Ï\«¾›[,u͘ÊkcÄ€v¢å+ˆ<S,2¬TŒ™øœ¸RïÑYN`Pš±îü~”Nôé}uŽ{¿—‚ÔUµ"Ú3 üï·~J|)¶ ijìy¬2êi<ÿ9@Xg•„ß÷‰¬Ä -^¿Uï ó¡éÄó•õòñÿUûÞåŠn&Þ²Öu¼ðØt5ó£rÌårì¯vÛݺÏÇdÓ@X<+†¤*­íÿl¿ç·±$ ªb-1‰é �ÉñXߺžðû€�‘•@´’ؘ\pÂ/þ¾OF“®¾7~ÿkHŸ—ï«"2IMV¿Lr®»@…ÕŠ¶êJ-"jí¨£;2Ž{ù>î^Ùê1?±@M¯Ç¹ö­Ÿ|¯X;‰ã/¾ÐÎ#æ¼ÉnGت·~ÞÅ;*CÀjæOI=*å–Ž-ÒÎEúÞú@RuÇQz7æ&òê÷îD÷Ôö¸é÷¡b†dý곑ÌÒ“ËÎ u¸¤ml­×Á%è*ãR¢>–Ru¿ŽM…̸å1éHS²ã\úß'dXÖ_4dYC‰·*Ÿ•Ã½Ž¹•ç£ïØŸ@Ôô޽Añ9꼺vn[€S4ÑQî¿k5³uКõsûý#“³R<ãæ¿`ã á{õ^ø#œ}‰À!22 ÂX}=�1_�ØLŸïŸ§ÛÊëØyÞTŒ­§¢2þÄçMH¬ëËçO1«öm@¯› ðAS¿ÿB+îï3˪üðçõº¼^×ï§vøzP¶Çƒû&`UC�%ÃÜJ%̲4v9î�0ÜP—H/¦v‹!öë+–؇cbaL1clŒ •øûøšÇ×ùŒÁ…öç#ý™¯µýÕœÿsü[¦“y  B†Ø´ÕÚZþ¡ŠŽ:&Uƒ–MÔp%/K·{s飄âFyz¦»î’8‹èîŠÒª'é@ÝI…/Ù×0aå©V¾Ñ»xì KÜâŽÂÌòôgĉR4J‚cÖXèHáR`(yõõá0¼åçŽóúcåçõქ##Ì2çn/a€|;~.¸Š©Ç¤Î,ÃÞÜ­/b?:fñ÷Âóß׎­8F@ë"î‹À^¯_¸éà™Kûøçjçÿít¦¡|Šñ>¨–Åcl°�izª_ﺋ±?Ž×íÆîÂ~ýúÎtÊܼ_Èëõ/<f"«íW±}KÎ×_a$.€hžŸL2,%.ȘÇqá„ üøÑKÇßC¿à}ß2 c>Æ|ÕL°Ì!»¤ð³D·øì}нçÞ¦£îx4dëX‚½ñŸrÜÇúÛO&ãoþ‹Óe<ž/¸±¿ÿdPݶ¸pN÷Ç||¯fíÐG)V›¿¦F¶`‹)iÌô«ñŸÏg×bºUþü<N7Ø® cl-†Õžã}¹ oùÖŒ±i|!åÑ÷¾Qæ¸1 ¤rX3ƃuôc 8Ð{uïÁ<žI6¾ñLd 0d¨uò弚XM‰S•ÎDâ/¯Ž«tǨcû “Ö¶;8æLùÈDã±Ãª]VZ"pï ©ÝùÈ0óoäófÐ1˼bél}Ì=LOç#§­ßI·ÇŒf™3jžîó“¶èýþ"àu}l_ÝÖ»@¨,cø­râ{îM30Ë¢F�#J&~¯è_¹ásã>|¾‰ûú £ª>zÌ£¾D ²°z*¿ÔŸÅµwÿ7‘N_‚q¶÷®ô,>ï@&ÚA"IXUŠÁåîO€¨JbóA󃀛ÙÿŽ#`V=oŒ1b@úâ€¥É ›@Ø—ŸÍ¥xú} ý6ÆøéŒ¡ý4&Sì÷‘ÙÏÃh û÷ýømËlL‚ñ¿Bþ/0¡AÊüÌ<pÆ™JÚÇšuœœ=?QÝÅ5þÍMÛˆ]€Ö“ê¨1Üã+Ð×ïqLÔ­Öõj¢zzæà})°¤¾7{=Ø*_Û";€BÀc¤\’ö¨�¯ 0‹ŽÖ€yó’R/¸¢¾#¢ï?»}ë8fdë뼟™�S¶B•õO(æËßwÔ£$šµÿ0¶Ë,À«T’K¸^ ÿ×%îùó8Jmúë«íΓøÙèúëý`QùçðU[ùï†ßõ;ÔL¾|eºº¿óµÐ/26U¿ô"Š7z}þÆøBë9ªxÍN�?þšgÙYq‹¹°ý—ïŸð9Èg ,ph×¹v¬œyÀL1ê"Pˆ��ÖòæyÍwÔý4_ÏÍJÉ©ò`~m>ú–/l¸Š.Ë_žþ<б'«Þ´PË…žß4Ë·äÇ…q{Í‹q2ÓCFՙΗ²úÂ÷ÉæjÎ3ìŽvßÞ)ï—tü8í(]Âõ¼ο«§ð~ì/D€Ãל·%!G„G¤Ý–äàGK90ŸÇ™žWï{ß–;˜3ì3 ÏÛ{PÿެÞß×M@à•n»þHfò3v˜ŽÕU-ÐP É«(O7&Ó¬§{Ì燺ÝU¦úk¾À‡™gøÅrÌšñ[¬¹ÜÐÌ.@(@­6Àf~fº{@œÊw”²¼¶ÞŒi¥¤wc³­|Tæìg¨§˜xümäÒpü;ö^ŒÛ—d¢Z€ÆíïkŒ‰Ö± x=À¦K °×é÷¸úR(Ó÷±¾ô¨·(‘x¥ûÊ”tŸŽ¡…ÏÙcba¾õñ]ÉGÌçgc õžïß•$ìÖOõû¨ï„{õ±ß¾)à ¥„‘uè¢ùh¤×Ê?a¬¥ÀŸ‰!ö1ºnû4–Ø4ŒÙÅ€¯¿Èõö¾Ÿî̱¿È½“†÷ßì·¿òùGKìÿÀ¾]qˆŒ*%q¡¤oм#…› Â<ó3O8ûÚÿ>½•>wxµ&jd¢Žæ'd§b¢³/¼¡Vöây,_¯žú¦³$^Ë~ey”²í S_œ!…QŒ*¿ß“RÄØ&#ål2êòz‰Äåh^ÛY.¬kèí8xY±Þ†HŸéeí–9D3FÌg<X`¹Ïü�<gŠi鶘.Ë×hžÏ¡=‡Õ™^µÊï()-Ëð Wœ‹þA—Û>( Ø­_%å†ÀÛE¤Xçå:CþÙì¼–äÍ™50ÚstW¿Ï¾è|¿¾º­rÆã<ßýÂ….ó"–¯ªgŬ\×1 è,ßGý´ SÀ׬_þœø]SŒæŠ©ÆaøÝÆ…º*†\Çr6 Ô÷©Sÿ؉㥜ÐyNÅïŒWúýS㸲²üýG`lÒ‹î Ìo¯ß# Ǿ¤,±jg^©hMÆXìÇ™$T®cnq{Ï&CI"ÎãüýAé³Ë#=[^ƨٙW­NœÁÆò3o·ö¾S¸_pñ{Û™§^¡'¨ç9³eZ”~ËÛÿ>pÕs¼í–O3c=`ÜuWi†OŒ…Åsà%ØÚÒžwàËö$vÿYÌä™c7kG'óßÖ³…yv¿äüó¹Ã¾ªg~ÕŸú…Gcñ=öS“¼\Jjqª†*öرØB1?Ÿ«d.if/—­Š‰6eÜ) ™½–ù3² „5Á7½ý² d)Fæ,çQÀg–ç[Rhži‰¦–$}V÷]l݆öæ]‰=Uî½úÑ€ÍUœ÷VIF` óÓžºÌ·Q¤£ž—?¿üU–ÿ^O¢žÖûÃëáép{¯˜S?Ž¡¤„‘õ£ÝNKbŠÑtLz£s>gC’ÚŽæ�§)¥è²„!¦¤},±ŸH.~…ãJòp2ÂÆãç3ìû>^÷G¸ßnÿψ�žýpœÈį`äº,v†· Lìàá%KbþÔ�Óæ#RüýÄiSʇÍm)—-v*†Vd̳µ$dÇ0¿×Ò¡‘3@t®ø„]¥pj”£ZÏhzå=Z-¥øé¼ëçÒe9q¿„ýÊa’Mž1†�àËý}åÌŒ3ae@ª^Vý®öë£àµ×{ø!Æç#Ÿ«ž¸¤¦Ý÷õ†ýÈxÉ�»pr7wÇÛúÊËuÜ´ãßnk†–˜0P1‡KI>b>8p†ÌYLW1%4ƒ"gfi~‚ê?»PS½ä@]ÿ–œ­ø±ô^’PånÙK±Ç=€¿òåY®tW¦ÙJb2î©úÌ�9»ã%ŸŸq.ÐÀ…¸éà‚ËT9›ãX¾ž!³ž9ƒ6³È‡ªkõåξ×ùÂ+¾¢íó~‰1²ï æoŸãSB)«u|'•U®‹è?vPeOòvt)È£µð,ö\vÁ^SˆÏ#Ðñ?dú«#P«Ú­gjù;3,öl}Íy»¾«¸Y”†‹ß³ŒQYç»2Þ¾bì1m³ÜÊ7¥+Ë%®–û˜I›ó³ãLK.Qt\:¿—q~’ٳطŽsÏ ÃrœÂÞséŒÁóÞ¿xißqß·ŽÝޤœeú÷Aä§´%å†Ç•M‡½gìÔ帙ﱘDâž!CËoµƒ¶ËÀìÖKd,ùtÐ|þÞ÷Ÿ ÏGáóõÒã„f€ž—þ‹Òš¨ÎzÈúê9Ã¥™oº~X;œ@Æû6žïǟἎ¢5î@Xo¼©�ÇÍ—¯6Ë|û–H`²z®mµ„ý³â¸¼§~ÐÜûf ±ißÀU`Z€¢b$í1¡"³ŒK>Áùñzî3“ö´Ã¢tá.PˆõxMÓSL®ª|»Ì¬ok ƪà5ÍV溲ë†�¼€Ö!V1É«žçb¢%ñH$§ý6ÆÀ°2€Ù1Ä*ûm,iÄ¿ÆïwÀjJ%þ~?¯c}yÆ»åïÏñ\÷ï2½1üëÀ?„+¶w àÄ-ÆR&œhù•…éJ%°çé×f 0: ¡ˆÀÒ÷š�¡ãØ;6ö¥{xú«û<–¢rÿ^Úmß¾ìï§�ÓÜpåü‹k÷�™çѰf%¨üuç8±1´,`6ÂýÚ!;Óaï»k:X™ôØ%0à4“ƒM(°bõä÷Ï´Ÿ±ÒtÖ±r†r²•ìʡřsƒ^ÍÜàè°æŽöý˜G–xõóW1yéù¾v€øæéê˜bpRŽMdèøýÈPãÏQŽÞŒaxÛG ¯rdõ�³:ºPm;íÁk¿U)ÔuË&�Œý…f‚aÿ«î³éÚ_ß¾—J‘1=±dê>;αLBËtˆ :x}£1@Ç^o™pêwöýùŒæq²…Iö»¥™jèøïuæàf�bþ^ý! 9SûkùýÏÏ«@þ|wPý<L™A7;êvÓ¥ÀþsÏ´ÒUGG¦±gfŒ§ ]¤c:N}zZ2sY¶àjîÛñúüÚñѬ_ïxÍrἋcÖØyÖŽâFd0- =U.4U¯¾œÕީ޾/+fØLgÏ¡¨Ü³Œ-÷a;ð¸¤!Æ:›å9AùrcBF¶Ý-Á±y᪗ €]‹ùýú}TûŸæÞÃ/о¿þ3ÃÏ-1¿ °óÀJú|Úvã¸õKùçæéa>3f ßü—a— 8í]\=àgŸiÒ{ówÓEiÄL}.èâï«i9ày*Ç£(Å§Ú ÷ú˜WÏaÿÚ¡2ÄÅšð�˜³w²ÿºbˆÍó_b¬9n Ы�B^NÎõ}u½°ZбòºÒ‚~_3Žø—ì9 ˜|øó›ðàj >ŸŽŠ9†é=…ts > È) m÷Ë›×[]>oßÚý1¦¿÷¨m]†Z¹×N‹¡5ú‡[Öˆé¥òQI4vc ¹ýklš‘LœÀ×—?€1V ;CŒc €òç—Dâ-†Ø/†ØoE:Èúó¾ob7û·;?†b®Eã¿9‘•Â:ñ»Œsá`©Ž#�ò9Gí’‰1<�§]£ÄÀXoíý~÷¤2\ìøú.Ôä¯8_ŠÙ±WK¬¼o.«žv¤]˜1 h íØðùü*ŽëZ±ÕtÄ•è¸2%Q‚W¢[ 2ÖìÖçKÈИéG ¬5A5L‚Û2WÍ1FØ¥÷~¶ò“2(@ÆMÅHÂ}ŒYö"¯ç ‰¯°]ùÆr°ÚêEûŒõz€ ¯ ‘‰†¹ØeTás8 w¼‡í:úôYï`ÍSQ_¡ øòýš¶ãKm#³É2%Ù¯”½o5 YÙ%ô¿h·çû~(Jlî3p2Fmÿz±-£´$2±2‡c.©•þ ÃüôVëzÃ.ÌðÌÀËð±,Ï„1Øa†EƈÿÝ㩞”Ô‘vÇö¯)tÌ0Y>/ŸT-$Ãü2&•1Œ¶±°,¦gñVÂ:ÊûÓ÷P‰¿K22I4ÛŸúq›Ïy ó¡¥ý8òú7{[”^ül{ÃyBLB¡±ú;‘ëÙÂ84”¶ûÔ�� �IDATrÄtµM@ãØ ldHÄØa{#®}‰ºÈ ò÷ï1Īu×»ý2QÉÄê›}?:LF÷{À{Š=Ï}ßJ«uV\ƒã_·È,=S*2TÔ‚ÃL±gn3&Ðà¾~÷ìYz6>k«Ó"Ùù¾;™m;*•ˆÌ2Èâ{pu¿§­×‘×O§¿cB„o£â{yºß‡ùŽõ’1ú§” ÝÎúç-ÆØã˳Ïñ¾¾ÀïüñþÈ—f úþ‰3Ä´õêý[Xf†íƒ¨ÌCï÷M·¸ª^Øþ YyžÊ/}ïø·ðþrÀò›L÷$ÒÍ¥±žŸFðt¿ø|*êSïç@Û7y?®NŸO]¯ù¾~þnÿŒŒ)<Ž@O0SÀWWÊÐ�^(ñ¨¤ÿ},‡z0Äþ¾ÿ7·†˜g†1(På€1&•¸˜`¿�3ìTY†X(yhó3Ÿÿ§ÙW÷1 Í®´ÊVBœ0Â%t†Ûë8 ÞÒí>Â&Š X³RE –¹®LI%~\¶]”³^Ýïv‹•ã#J‡õ&0KÂ2®4eåP¥ÍKßY©\=oMw“èh›Œ)Õ„+н#úE�Kü9‹Éà‘Y†+/bbï%ªðndT`~P† îp­™#þºa®Ï³Qz%JO²çe@Håàí´t,[€l¸ml'·ã‘‰ÈMaxþ~g™m¬>y­¨ZÔõò½¯<f=ÓþÂuþ\\÷9ë�ê¬Ô]«ûÅÀ„j§°ñ×iåí½òíß;VûÕŠMU“è¶ù¶À'.èñÀMü/—œYªœÙöõ±?Ès.ö8~OX9²ï “8óÏŒIÌgŒñX9Àm?¼ŸZõ…±èt;` Ûh ëøõÀJÝcúzè¿—U¬0³ew…~\¾¤”pÓãRVýðeŒTb|×x¬-””¬~‘ À»1˜ô ¦€=нRÁ…†¸ÏêçgZ"ÑÏÇ¢ý9¤çï×[d¨a½øy”zïõ8Ìÿž«ÜXrùühãý’FœÇ?ëø¾ÙûÈœY?rН™“�Êj‹¿Çí~Œ}Ü{³—„Ù�®ô÷°[ˈbnÌÎ{8´³/ ô×3‰Äìûµ˜jðBI´+ý>³ô­Ôá´˜ÝþÞÈýðƒï]@ݤ{íu-Óq¯�fþÄ byº±“f;ó�Bð±÷¯û|~wy2ZêMIU9<#1Bã¶}Îö² s°˜aØ>‘©Ì¶×'ØÆ#SìŽ;û`ùDÉBd|Þž¶�Ë®?É¿ÿÓ³èh¬9o @õûÜj`[Ä;<o}¦ùІ@ ŒT ®*¿s¨žŽs±y9µ†‚/ï÷‘\År`}öëe7fYPS¦�³ãL°|ADm“1•ÚdTUL/’ޏZ÷oH7vmkÀû×=VØ¿ÌQ”N4Ç?&ð4FÊûøÓ�_7ûÝ1Ä06ÓáÒ‰a¾ÂÖw?”V¼]g;;L­¨[¨¸’•KŸ-`† XÙ4“OÄÎ0ÑŠ æàÀü³rrK'Òs]û6û{Çk¨OozÂw{Ü5£%»ªüñüèó^Œ¯À4«»R˜1þºç‹t¦#s¸íËèsX¨÷áB�0•ŽgfN&¦ŽaaŽÌí€Í+Ý_@¡­Ûåõƒ±c˜„ÔÞ@Óç™¶^¦c[Õ£Êæ:dÑq;ËgÓ=ƒÃ{˜ëX´õ¤MŸ÷L1Ï(É+Y}+†N¬¯U®#+ÜÖóªóZì«—Rßõº ¨ìo¿<Õ,v»_½Ï PÈ€¥›)fšb’~m½×±×Bƒ·­ûr` ™·jÁ “ºUÏÝ)Ÿe~"PÅúÅ<fõ]‚¬¿cÌ1\Ðä(¬–’1¦³çæï—’>äõr!ýç3­– ‹ÌÌ*†ân ×°ÿ™ÔX¹ª;¹ÅúúTL°iÛ�–¬~²ï»N×§¿f§,aÓÏ€ØØ¯òqŠ# :ÿvkŸÇ ÔÂ#UÙs®Ð?\ÇY¤%-@}•Ðro! [Ø™_ï%wí½8^K#¢4]•ßî™+ìëI–¢Šâ”Çr±~3Ö.b©Ø‹¥T’‡®�ìuŒñ>a„£ªVóyÓ¡þæêõô�ÈÐö\(¥·×2å õ­óå ™žýPÖPÚ-A¹ä›rü×€ —\|ù8j;–Þ‚Öïê£ø{+€T]Ç$<´S•ž¹õ–¤™n±Þ»Ê,ž!v‹ 6·úþg{~J"~¼‡ëÐNá</çUJŒæÆÛ·e8í.ض†íY—/ïï5ðˆæ¡h`â=öw߃§âx—¹¶®ï1žÄ¶_?àX1Wøù>@œþs&×7Ùw»�¥¤ŸÄuß> ÌUÌãFcvM&\ðr 4˜’f$ÏQùi1Çn1ĬDâ߆¦$»K'V„èš@2Ä<#ì”ýéâ~LßK;ÎXbKBqI*b:¸Ï&4lBŒŒ0ë€^ë|ÂÅ&Ä\"kú/)ľ٠îšmMÍû„õV°]ÑW=…­tÏòûýüå&¼ªûkØ|q‰ŽÅјÌé+~à¤b–䌈Y6VÍÛˆp,GÜ_Ž\™Œ�‰gÂ!PµbÏ Ùã(]…×1†ÀÜÇ™sa•›;vbÌ1ö RÝÞ9Àß—~Åz÷ùXõÍM ½ëy ¸Ëƒ¢~¿é°ÀXõ{ q>;ž½ß¹#ýÒ¼¾ß3Û)ohaßÓu|  ñò|ûJʳdÌ}\ðrf°f.y)&²^‚ö|ï-Õ§† w.Eû«bŠøò©Øf—$½AÓý*ûEÅÃṵ́\: ™X(q‹å^×÷ÚÓÙ,°¢^x¨Ö{*F{”PTíd¤ûõx%Oá³±Âb>xþ3F53UŸ‘‰Õ-·³ñ³g:!³Ëæ³×ùy J‚y拉Æç=¾´‘±¿Þ <s%Œ™/\ È~ÿ ýó`›×3†g˜E‰E_ÒŒt¿Û6}õû(ËÚeæÈÅô£hÏA¥Wì×åß;_™/IŒæmW*q¥ƒ C (eõñ,Ÿàs|©AT3{cŒ[{|7’ˆcŒñüåü�޲…¸]íu>Wú½ÏÌX¾¤>ÆüQ@‘6¼i§Úã£ó^FàëX,Lï(ë¨ÀÛJGIûR¿“‘É`<s‰Çˆc1¥vôáó(¬¢!3ßÏœé†×?�&O Åçñ‰¯‹ö%¶›ˆE r‡1êÓõfžÎ‚àw±U%jÍŸ€“•¤Ìl}n\Ý1ÏdÚÂTì° ùÏU±Çj†U¬€˜oÈÙpúùì-HÐû]jbúóÝØou»¨bèáó]l°J‘œw×M`Ë�dnßXÅ@£�UƒIö£8Nó9bl4Lw†Ø´ !5ècŠM©ÄSÌgŽEƺ"Cì÷.“NœL±Ÿ1Äü–™bŠYi\)È&jEòQj Ÿ§§|À%CŽ1³"-¦GEj" &wŒìv?•ÕRŽ=Ë•räKÛîJœèξ˜ÿ½tQ"qæÍ$Ë ]@E¼Þ¦”b.a£�¬•þW™Æ$;ƒ¥%c,˜ÚÁëáìêimy‹:›ó¾¿ÁØP±¾P‰Ž¯.ÃGŸGÆ×ÚN†ž?>ÂuÞ8Óçb€èX®€<ÖÏ×ë…y=±ôm>˜ä[Çq‘15Øï7ÄuÞÒö ª¼ƒ϶ª^£ÊÿZLŒ±ýp‰O»ïÛ­¼=V@'cÔ0S&µ7-› ž `ãûïŨͤ‹Tºú|¢ýB�”’Õ &n¦c†áûgë ©Ø~Óë"žçÅaÒaõv™°¾=­0ûíøÙ8¾eõ›Ù¾D¢ª·=†È®)€LY=ÍG&[jßaÁXÌŸý}Oiß/ço{Å‹kúeϘöË8cLå‹3³XXó=EFÚÞ<#‹KqÆôÐ.î96¶W¶p©³~¸ ]àw?ÓôjÆ`ΜÚ¦Y »­-ô6u~ø;½£BŠÖ U0ëã-©‡÷‡]爵wÛ¿§ïÓðšÛ Eh�2›‹!ÆèN?Ⱦ±\ LžþÁ2Z4З†„±éõ[ïâúç²%÷Z¤vÀóþ¼ý&sC&TŒ!¶›¾¿þ9´“=Šª÷ª<óýÃXd™q ëô¸ßnõ}Ñ<Clc˜Î»ð¼qÀÈ{ûÁÚMö^=ß¾Œi–•c.§û¾²½bØíj7Ýì©Ø¯[Àd‚…Âò¥UY=1ûÖ|?+2–ª˜XÝ÷ü³@Ž’ˆìæo·?ê1 ×þ1ûŠiÆÂÈôSvìw€þcs¡dà€X\F"ctá}xš@VhQ@ ­’p4ùRVI,‚dâß“öÈÂ\špgDJ‘H+:™éõ;\ÿûcËÓý…¥/·&Œ0¼š¢ôóè\yˆ(CLKu¨ÌÞÖÄô¶’iYž!³+53¯?‹ߥ5Ð�«¥£ ;,ªËÙeŒsAÕ+±s‡3%)¥®cåP·Ls^Ùíú<ÆÓ*í‹l/]‡›epi‹“º²Ì(¼ÿ¸N߬ú`ßå€ârÄW¢Þï“·ŸÈ`ðŽ`»bûmX‡ot¨ 8sÜW­9Ð2&ߺ?—Z¼Dzfü¡}¥÷_0çט½Ï�¤©Ô×äº xÄû«ç©|e½kÿð¡Ê¡¤9×uØT¿Sõ˜^Ç!„€滪_k{ß‚Ãy^<ù iVÞ¼bN¦å’Ž}ì»ð"ÚÇË£?ECà/Ôðµ¤ëU-�ˆRËoôºh¼ÞT?¡�—ЪçØt‘1Ãå¾—¶£CÕ'«ÍýŽ‹-ò»€yÛË8|Ñê˜a”ïöQI·¥i@ê8€h%,vÛ_åâï‹.­Ç £rmãËæ]8NÍb&±t­Ä#cò0iA–_TИó¤k`ÒF@޽‡öùžé¥òy½GF ­Ÿ}ã’|»íŠG\ù~Vççš^×”âû£Xz¾oÛ%:Æ™»µ»à¥ê§»û¯cŒ÷{4/C¬z/ìõVÒñ¶ÃÕ –ž³Àa¬'ŒIÆóg˃@¤ò§(F¸}o»óåg¸{ääËÁöÀ¯ÿ>1˜öíXLÁøüCï³Æß|iË3HZ@IÍwmûf ¦7ò–Ž}ηþ<þé=‡ëL:_4#2æËÖ'¸oņë…6?QjïØrÍldQëôÐ"3LqÒø—lŸy9/Ÿï¨ÃzSûêyy:O¢?y õZ½ütG*°ã#š>»ð�í[±ëkZÎTD©Æ.3°^²7:ç £ª’(ìÆæBF}ŽÈ~줓œ§ÒÊ ×Š=öÃø×¸DÿšR‰÷íßcx�le_þm¥?ÇŠ-6ÖÖ™—F¬€ªKì”ýÇmz(ûR›ÀØ:>%·˜b3½ŽÔ„}=ý„‡a¿˜ mttVZÎ+ísâÄ®§i޶V†ú‰$J³ˆœ«XÊ@b厑j}@×¢cðû¬á­º{Œé¥D}&‰Ð×â\;+Á×]Êq‰OóÒVºvu¬ËÔb+üçßWØ·÷Û­bª ƒ€3Ì!϶/rà;Ï’ž}n6AÞo¥Ó1ˆõÂcëÅ÷¢ OKŒùëb½0‡¶’XÃØm#܇Œ”å Çû¼#^I4FÀ…?¿bº pR1Üòë+ÀM=_ÝÇȪÚÝú*¨÷Ù×clo‘éÅ?dl©rVLÁ!û­yÝ«ÙjÇn´®ƒkÇâ¸àýTÎÔè,ó¨$b˜*J¢­ÜLÀxîÛìwRŒMŸï×ñ;ëí"ÇuŒ™gëÓöÿGF ¾#ÀÎý³é¿ªöbËÓQìÏÐ`ÍuGgu}ä5w\êq·ßî1Åšã_UNŒµ»3 %¼vÆ»½q,Ÿ¿¯—ãøýˆgð=E@ÈæÇ¶ ;ÉÚ3[ˆå9…ë7%èÂóÏò<³L¡¡b b¹Ðòþ¿i×�Æb]{¾ç£/íÖkOývί¼¶Sø,cµ^(Áìy£¦qáCwbb½!™ccÔã|Ÿ<3 Ó¹Òï.ÆXŠ€D|ã‘Ù‚å³ãƒ:–Rl‡¬ŸéþJ1†Ôç€#[.~ÏÁü.�·úyøÜïƒ Âçæ{ú^ì[cŒØw�Vg{c@X–8o�¬O7û½» ª l S,™—|Ñ�üú=ñ}î|dÐe~ÑyÜJíYàÍ,Y?YŤD@5Z/–Ö²=N3aõ]4Í|ä€I¼ÿ(âmGQѼ¾=€&¼Ÿ—먱�»ˆuŒ/~ß“¸þh¬­‹ %=¾ÿ]èÆ2SççöØ¢¥„„‘…Œ³ûR}�™jiþ‰Tbj?8f˜ÝþË�_óUä�¨)øåç1Ư�ý@“TüéCì—Ç1œý2”eŒµ?Û?û·tÿé(G:®`T�”Ÿøù Ú¹‘¾úÐe;ÛÜqebOªdn/4èp¦V¼pĘX>v|ßúŒ­ï‘þ©éH9ÂØÈŠx2™DMO:«bŠ}}8½Ct™šxeŽ…Å ð ¨ H\é¢C™3�˜#\çõá¥/Pþó@©5.ù–1e: ,z/g¬Æv¶çðÉ~7rUwa€NÕ3~"@óÒÉÒ,¿Þ‘ÿRÖ¡|_7¼|ËMÃÛž½KŒ‘÷Fî¯óãíן ¡¤Uñ9P¨ò£bÂ}•[øE�2Ö‹}ÿ?/WcU1Ð1ûžW–1@±^õr‹¯´¿Ì tÆ7()kû1üîñtT¬#Ï„± $2&&«7Uœ1‡ï ¶Cd×f…%e¥Ú—ˆ”²Áh¯í{3[fªÈCÛƒ2óim]>0kw»Šñj&Ýž¿wÈ«• €Œã/V/< µïQ6¾W+úç},?1šªoe(Åc¢Uéøù™¾ú–•wǘZßKºm1ްžTýevTâ°NIÙYܽ@[«$î0V={ëϯn^cFK^÷žhJ&¾'÷3¦ä´åÿÐî|þÈû©wpÈÇë=Ãź³Õ8Âûcâm*ý(àËcM3À¶Vì?ì¹¼¾ZúÂcdíK™Îòñçv,]>°Å–Œ?n¼úöóLê¥Ã€´çÕóf9æs+¥)ÛNŸîÛoáüóÎw`J#6$1FØõQ¾:öÏ×Õ½—Ø-�”•ëYìÇØaë¹ÞzŒ±|ô Þã±øT~w™AC¤“ƒÈØë?mêþP÷T�”Oeÿ6Äùyÿ^¿»�¿JjÝ<ÝÝߥkúù»€hצD"šŠÅE¯S65L¿Š6𠝡c‘µ�Àÿý [iУðúMÄËl2ÂþºïÿôJ¼I)þe®E†ÙoIº??¶à»I?Þ»1†Ž)a-ƻȉ ÿF ³®d‘ŸpyÇ›X1ÇÙ®1©ot} «,Ÿ0UÃÎõ”Þ éÊâ°T¥Ð’Ú‘Æ{øÊÒîÊÅ)½­¼,ÇärøyIAÌMŨÉókc‚x€'JüðzA€ëåpEÖ‹—ÐÓç16Ý•ÿZJ±ª§j�=¥Ôxþ¸ÔÔùñ>Df “*Ò+Íó7н CãÀ†ºþîÓ±£r錗pŸ?¥ùý1¶ÕÜ÷@€–<“R¥™RŒÁ2Ócåâû±¾3r¥«%ñ½O_Åw²Ôß\=yËA êÔ=`û‡ù]D Ç|°·l@g×Ùz’h_C{™í»Ã¤»ˆöhË—õ£0T±„.п¯~ U,8uÜ2â,SŽå¸çä’ÄÓ”ûËŽoãR”>‹~_IpbþæU[ )r]^u_5ëóšsëNk›åÃqï¶d¢Mß;Â},¸1´ƒÏ`ü»o%5“ K9Ç}L"‘å[×÷™ž¯%Ëb{³Žû“gçß ˆ^ļê\”ϧŸÓk±™Û @fùˆéîIN)Ç`˜Ê¡ócëÉë;? °ïæSJè1Çÿd’LGzVëwh)|žÆI 6fâö}®Ør Cí[@Â_%™½ÇbIùôµˆ»}²·ÕwšºÀXO2N[o鯻ØvŸûü�L*·ØOì/…éJ2�Êzª½Ìrç ,Ÿïç{z¦šÆÆˆ�ÃS`„=—ó|s~J'~D†$—pdí û+dÒ1ûí¾$p‹í¶[©Ç¼ZûêMóo¶Š‘Ùí×µï pôT˜Þî8ïA+éÆorF³+Y1Ñx¾9‡ùúöÉþ\1Æ*@N×>·›Ž:TBq šf˜b«Œæë³‹ó~%­ˆ@ÙM2‘ÙŒ-ö`†á>$üóí|*èM1¾&�6¥¿1~zÄûýqe&½øçwiÄ[~çþ<€±›áë,žÙD*N,kÍ{»âYK¨E‰<tè±bŠ}îØ%§ÑZÜf¶UxvÎ;î¸à鮘KŸu©øüéçÖ+ry>ót3‡è¼n®ˆ»åÓ;,®a?—è°@»@`®Œ_í; ] ª[úø^`ÐsíQ×y—u*¦VÆPóé+†NŒE¦€µL²ÀîwÍÿžjÅ}tåÏ‹÷W’ØÉí÷Ùߥóv5Û¥’HT1Ë1†@–ºÿ+\Çc—¡Ûç¤ËÛWõ~UÒƒ»öU´×ÈÌò€ gŒ]£k“Ðb^ïÏG�P1”ð~´j%´ÏÇEöG¶ß:›€¿/ôŠAÑÎc:«%ûC,¶s$ŸÐË•k  ÷÷q†ØÜÏ„ðrØzñø€ú°éc;ÄúD‹Ì¯›ééÏ’îæ ¼`õùª%"»üÈ<·¶Ë¼:ÃþÊ·ô¾OLØXCÔªa�0,.\ÒÌ"Ö_Å÷÷ú™ü½Ù‰ÙçïWã/¾00“Hd 1GW“þŽáü‡Åæã &㸹c}wS@íý,^ÿÙXD—û~kÁäXóÔîÓ+À÷áš®þŠç»KÊJ±M»IŽ)ÆÆpóŽûÅÄZVÞÆpKO)ƒôãR¦ck×îO€àöžFG{w>ÂêI„˜£,fX>nˆã*_Nß>ûÆ£iÌçèã»lÏÞá½Z€DQZÅ@{~�Jñ½î¾_Ó8`åÒ î`éòïhì±&ÐäßÏëm2ÂÆð žÛñgH?þ’&Ý{ûŸ‰¸âãþëý½á¿gÄfó›Ëi1Ÿ*¦3<Åü}.†X’òXbª½TŒNŒõ­ô\ö€Íø:;ËBýXf½|?IÏ­ŽÚ›×“¿¾Êw%Á銱–×kÌÇ,¦Zńۓ„ìÛ”þaǬÁä¢÷%Ç+©ÄŠûS3À›:ïìÇcR†##Œï£$¢“PÀ›1ÁÐ0ÖØ·b·ã¿ÜÿBóÉÌJ#þLbŒ! V9ØøŠL5Âʹ‰fþŒàó¶„“QR jEä§$”¢ˆ”DŒw´ìKÛ ñ‰Üga±ØŸa‹ÏÏ'Ý ölÅ|'ŸîËV"&+”Ft¼¿8†‹u„s†Jw•“Mõºõ:ÖšZŒÀ´bˆdù­Êu p1좃2Å´ÉWºå¦�^Ë!îëó"Þ#d¾ô™ŒÝúDiH¾]æ)%7à8“fäÏÑÒˆ ®¾O_gÖq9¦coUí®Š]¦Ú·bÔ¼Ðtº ©jÙÆdéåŽ)Î4Š9­Éoî8J ªçG«€ó›q)Û¼ýˆ<ñùðUý(c*u˜ÎÈpYïã9,¤@fKåxäï€KÑnkaH”–dßS6¾aŽÊ+éqºÌîyŸÏ'ž_×ñí™n16ÕQ©ë‹ÜVùèJ$òñdVcIúÛRˆuþüó¬tbwáË H»Ðtpþ0¯×ßù8±ßÿ³»ÃYÏÍ�0<¾ò£%Ü2Æ»=þš^?ëûòxÿÞÄyoº)†Mçþ+¹nwÁ“¿nJðùíqIÀ)¹wvÛÚºïÖ\ëÌJ Ú»ºå;=ú->¯æÕÓi²L¼ÝËÑoÑöð�ó—3½cx±ôg=ØûN¡ž¯ðždzȨñ�J%raî¶ÎM1Xíùj!Ç2”üã-®ûû÷™\#ÌKàíZŒ‘¤�¬ÃMÇ„Rí$ïs¹)‹ÁfXk‹:(ùøœ8²Ù8Ì:Þ_‹åT1½!#ì †g~=PXÇ„ë~7mý£4bdÂô%Шcóå±› Ð�Ésº¿Ûï,ÀÓYx~YµäÍk1½œ2 �££±³º]ß¶0\çO1ÑzƒZÊë-ÆÂˬ–¦Œ�rçz4”Äì3è¦9 È0¥ZL° K$ •9¦ÚL¿sÌ]_å»*Çnï·1Œ1»u�Ô—‡}³ýòóèÅ cö›»þÆ û‹�gdý*¶Ùó'slM€Îb@ª^xž¼âJÌA®¯¥¿pbä²S˜€·Í¤ñÔѧW|©£`C2‘;:¢ƒ ;€EãŽ8¡Ÿ{ÇÖøª½»äJ¨È¶îèóå·.LB"3ÿ¾ l9H-p€ŒªôÔá|%âú=3&–úñL”N´oY‡ù¤ó‰õÆ ¼X¦]G­Ãd‰õï÷õ{¡õ´غ'ë2_TN•ã�2y9{õ¡̦ãÛ§£$ñü€ëTì¯ñ8Ï·Õï­îC†V¬Wu]UÏþøKz]tÐMÏ[Ã~åuÔý¥m÷XêNÖÏ.iQ^òµÐÅ·_û¾0@(ëgƒï%ÖÏmûá*ßA�� �IDATÏû íw¹‹�QP´õ˜ î1¦“¿"¦3û§È Öõ¥Ì3ç°|3V2G£´é‘~Ë™ûuϤƙŒ™«™a9´ÌùÇL-Tª8I½@*&®Î?Mw*¨XaÊÉÏ/G}½€„ã#㟟O,SÞß—±~ÆÖëÛ`Šüúåˆó*dÊùëb;Ý_, ÇK»ßãÌ;Ít‹5ëËÁÎï3-=ð¥Fô׃Øsxæç÷>T 4.5ØOHüûžÕN˜ÔŽg~|»öùÏòñ:F¦ÝOF‹µU1Èù÷ñtÏ_íE&O÷òƒ%Ÿå8fsÁ0úEÔBŽÊöƒ5t,–o/Ý£±½°\ Њ1ïvò¯™5ŠcM½`åïïžá ÚR9s-”•Ù÷ìi¼‹rD¨îö“òØ|M@êƒn>GTþºiš¡S·c\Hàû àÀ˜e]Ãúöt”Ö<Ö1à“í?µ¿\È8ÛËÇ2ÈTŒ*m] kàÙ-§�@Ë™YÈÄûÖ‰=…ã*ÝŠñ›§ó­ ¨U6aJ:ñG¸nˆëºÖ’ZDIÅäyÿ°|%€K'2ĦYéÄ_‡%¶³‹J%z KÙ/-2ÈnÒ‰7³±ÄQ¦€²)‘hÏ/ÆØY:&rÉ>]¦'Xè8ËVb0©6ÌŸð ˜@#³Š•æßé¾¼äÀYÖÓÐ’2IL…Z¼çV®| »+cW”Ûýó8¶öwßAt,l½nJC­L]íäˆ Æ>Š[.QwÒt™í2Ÿ˜ãcfÙ€qåÈDF…dêV£€ %}·l:`}=x¦ÆN+Ê0oË‘z™‚6Ða½Þ¯Ê±Ç�z/¬lnÆ RíQÜÏJªW;?&Ó°xqí+¾O¤æ±‰˜t©gØqÉBl«úÄrŸÀ$c|žÉ>cr1†µ2lWЂDZý*éN è¼’û&ƒ©Óç o¢Ù÷S¿oˆ¾@½~•ÏE€–-˜×!PÉÊ“—âóדl¿bëU1ΆH_™üΆ ÆÒ¹þ·r(dÌBëÀ{uû8®Ó_t3¡¶¾8uê±ÿÈD.µí «¥-ÆÄ»ØýõÖAU/üòí"/Ï5©/Öo1†Ø4Dá|& Õ÷Þ+_œé¸bÅTÒÌ=ìGò…˜ÊA®7ÆðdùCó g¾.ô<Ë··Óýï.<#ì³nóZ2ªgu~rÇ9–«3OÁïýÍ<ð”ÑX;ŠöXÂé Ví1´cñ‘Þ—óc;Æ=Òt”3É9¬ÿ¾xFØÊŸ®|ÎȸÞÏ_áùë ŒÙòþzËë?ÚÞgãØ2g§ß£“.2±*©@ΠéDË%ÖÞá 8*™¨m˜«€§ÀÆ€›DåjËC€gZ6þ²¿«=n%;±žª7æÔ-'Ëq¾Z›¨1\`¾T=Äò!“‘·–>ž–FÜY}rSt¹E€$‡pŸ!GïBBQÿnEÀd@þ»QAýHcÝŸ3Âú±÷ìiTžcd|!©~Gl´Žëòã}y}êçøúŽ�žŠ]ÖËŸ¦¶|V”ÞI&î2Ĉa 4u*b*_[�YRw~b›­eŠý ·ËXbó¸ÙÆÖÇŸCV7û¶¿PÆ×OCkàöçpù¸;‘‰T×eÏÛ‰œ¨¦á ç耫Vjùvà¡ölB¼ãhC¦–Žm@]¿È#ÃxåàŒ15ÁïO”òÇ—°ýœÕŽ‹ž$¥ÌïªóWL瀯6ßN9ã…¹·¸~Àý=�G9ê‘ Oí¨bŽN-qÚu´N{ý<Ö“<.ÇíÜ1Êzù©û!Î@ñÏ\`k ûž)@ŸÏË* %fCE­Œ·÷u·,×·zÒÀÓ0çÏ�¤ží\0¸0U1âXûWõ÷V¤Ç™Rë:þÞæ’ws³ÃŒðÀmŒ™ç¬ÕΑ9>KÆ‘ø½S�¡Ý¯ú~Ý×b<óÚßdöúý^Œ9öžØvÂb3VŒ_>^ò-êlÆA¯c1ŠPJXµS4 âÖ2Ÿ-cìã•9BoÇÑ1_-pÉ¿ð°<Zwªž|•ã?az\xÌvc˜A¹Õø5ÉùÞ¸nšbPUåŠãÞsy6Þ‰û9oáå\@n¶°HçnJ {å§[oÄùù_þ»]ß‘Ü"ÐÉ™rü¼6?Ã8sY9¶—ƒZ-ñÉ¥]fØ®PfP<C½ëqgfÚáž; ­›Ë¾‹YóáòKK‘a‘1=X¹®ÃÇòŠípzWØ_ÏËü Ïv¢é°aY¾£Å÷ÖÎÇÒÒ‚s»Ç¨ªMI¨)`l׸Ãþ³€Zà«ëIOü~_ÆP«ÆÕØŽ‘™¨ƒÜé>`kŒ1¾=öcùvøl÷DâëÚ&õÌé³>ôýê»V1±3íÈÂÄ+¬j/ÀíbøhO»U¦u»ö¶¤ y쯧ïð…då_ÏïÚÑ‘»’,ô¦¥1mër©¥6¹GXI>Ià’ç ÓéÇ6ÛB•uûWÇÀ"Ò„[ 0"‘XIÒfJjñËÿ’ÀV‹A6b,4úü†² „=˜cw�ìo8bŒ ÅßæbˆMK˜fæüdŽÝ€²¿�8û«¼²SÌæGM°Ð±Ê>8 ½šW¾ÂËO$§cžÅ4éÆà.“�>˜á È5ð—Æ<h�c•¡¤ÌÑúºÀÑèH³×6VDÌg寗÷Ô´½ŸOµÒ› €ÌÚQîÈõ€Ù¥ˆµ´Ë|BÇyt"ã£Ë8šŽðÅüÈ$G”ßÖ?ÿ"'˜VÊH×ËËÃ;Fð2&C,¼Šãêh.)§]µø»ì<WKáÆû2Ç\HÌ{ZÊ®´ qý€…ûs$cбüe…Ýr°ó; F›¢r°Úïc|/yÿoßsëf€©ï|?±Sžª~Ðx»}¹çc7®m‡9fÓÏ&ºÈ» ZÆ Ö¿gœ C?¶(ìÇØ>c¤qSÒœ1V°óßÁgæëïªÏÑÞȰîª7VIV/Ãñ2ô•õF8ýiwõDÊ3Œ±˜¿7š^ŒíSY·¿›å³ýÎ)ù.²ô‘kíMÜ—Y\R¾#I‡�Á,ŸbJuÇ/�ÃtóöeÆ0‰ãa>¾ù^îó<§XSlß›Z?Ôa^¯÷çúÔÐU:¼*óý–eâ)†eì0Ç)_x’çÓþ:Ly‡ü|¹/¸˜aŒÉÒù~Ÿ‚#û*ökwtGé:µÆ¬½!PÁÎG`;ú3ø}¹!àUÇþªÒSÖ“(Sïi-ÁÈÛåg™ŸýrìIéeé#ó’1 ûÀ°7ï÷ô;õÃÒÿf€­@ÖíQ6c…M`ìƒõ;½.§{ùN๷�ãtÏÿÚ#@»L—î¨q@FIö¿`üÞÍgPi¦ÿ¾=•€¸¯ ©ã<ßuÌ3•€»3….0ä ]Ši¦Se]‰G^^®ú]óþ:£óy·*Ö–9ßbŠMS±¾Œ£² 8›Çÿ±×ás’˜eøRÏÑ€Ø4¾XŒ±Ä(6¢´¢ÙŸÌ0dŒ­Øb(û‰ÄCó’Š8†˜•àð´s:@¶×j¥Ÿ7Ϥ`Žt¸ó‰*w�ª 癚Îò_Û:'}’H%Ž10¦V rGMÔ÷ ¶®„¡vD÷VbW¦¦¥uÐî|‚^åêÜ8Âó‡xƒLÌ”£–ç3Æ^aç2Øû”K­…ãÇ™Ö!ŽïsåWÌ-˨‹†Ò\/4Ý‹lEsà±é²rÇúEGù%8À9ЇŒ²Š™ª$Øú+É«zIá¹yý·Ü²ƒ;º;€žŠÇzÙ xëXw…{¾âåÀ_W1ð½]íÆ/Dñé!`cJøËüÊ�½Î‚u~•&%‡R}"my»ïò™©oî8MwíªOŸÿ³t +€ÿ{2�Ÿä}Ž¿Æö[±óì÷bõû}é_ €-ikß_[Ž[<U¼"_R×ër`¬?ýÅ>|œw){ÂÞsêa[€£ÆœáwæX=Eã •f X¿p„Ijfã#%MkŸÇÛãYäëfŒãëI1»qÁÖ1&æ4­pQ—Óßìù]Û™ŸaɆ)YŒ%vÌ´C/•éºåºW pv\]+>”@g>¸ÓÏZ0J»y‡=|±Ôø~ìŒÓ@س\ù/°ó8gÖĘOªþ°>|‰gýÔéYS@¯ÙyEtgÏ­%Ýz+øûÒŠÇÞW ÐqÇëºþsÏC; ¬i JÄ¢©®²vÓ|ûޱëlû|7@䎿ãiø÷À:Êy?Cc‡ÍXa_úí'J¶ÞRí`§ŸQ€Ã·Í÷¸Ž5çÓå»™(ê'úç~?ëIÚU±Ä¾P¢ÈD{×a~°CIÇ'ò²ça¹£ánôÌ ØÏ™…Qš1ï÷*FXŽ×tg�•#�ãï6ÆÐ@Ј±ÄÜñOX3¬’8¬òW•+òÐr@ìׯ 1éÄ_íñÛv]¸@ÙÇŸ#JNÀË`ã[ìWzÝŠ5V1Ï\~ïf^7[ÚÒèÀ™Æ$?–ÅîR�[.ÑT¯„ôZ?з¯g%!;z€Â•œ[ʾœ¥câÜ<>ÀŸ•Ú‰ŽP_Šcé¯ß¡Ã¥àOÞ1•ïK³>íïÊV2âuµ¡ÔßÜbŒ±uÜ·Ãîzý>a¹ùÊB´x@Û>b ØF@®b”ùòp©Å ¹îvü«Èo-‰Ö`³‰“¼cåA™ê5I€±ÿÐ.¤?zu[]N,—¿N¿¿Ç¤”xy;×q†R?Ý.ˆ›Ù“üwN×1¼^áºá¶ü©VêöV ¸FÀZ•Ë>ÿ\ö˺~U½æíc/_ÝûËïó×!ì+í/X?’µ#V. ^ ŸŒ@˜W]ÀqÒªULÕ¬þ3‡ ÆÎ[ß”*åœý)¯w´8SÐk‘ 9óë½kù•ùôù3Æûë‹p°5kª:ÞZÀÕ.'+ÏQ�™L~Þª±qˆê·/É‘jaß-?¼g ¯Ì‘xöip`Ý.8Tã[Þ¸.¿ÿ*FØe{¼»óûHý›y•¡cOXŽÂÏ-ث˙ÇJš¶+©9>S-2q´C $Udî0,Þñ¾ø~³ïe¼-�ú”æ9+_È0;m•‹Yï½ÊûÙï/ñ»÷…ül,¾wQ‚ýfL; ]Ýv7f“(D Šÿþ XíÌc˜Í÷Ô3Íýv¯'Û¾•Y‡ùë°’}ïãmÜ$yÉ#”W}/±Árøú×R§; 1Öánc,FV‡a‹µðzè㞦ü‰þ¹Ýã•-àe/Ÿ}IÀê¼Í™S½÷²|²ô«X`øü§âú§vT©|¿ƒlÀõ•$dÐäé#ÀXKSVõÔ•<j-FØÆõ._† öêr@ì·cˆ=b‹M ì€ým¤IEãëËÏÃX>�¯ß�ØÍ~yloÀ×b†U�Üð¾Kp¼Ý&@pØ]R—Ö¦>‹Ù9ý€3žT¾"KGëC¿žŸwtø‰åi´V+GqDìU?…ûx¹³òøôQ2Ñ?ê0QÃÆØmï‰5*‡iü5ºÜ2ÿX ˜•cÇеÊá™è¸]Ç1Ö˲.00%¾ðJïhŒ(‰Ä¬üýfÌ1[Ó;xQâì+\§$ÁV~<P°€3_þ¯r`ÞeLåÇã†Mè/ÐÏ὜gÏp½/¹È€\5b· hR1Zâý páçÇöy4^ž ©êÕgLWIƒi¦õŽ4ØzŽß×’:¦]Åü¬êMY¯~}»Š@Ý ì{[¹}yôÃm»*8Ëx—ä{¦ÖEü¾q\Âú?&«˜·]›ý_ÅXžL/Æh­¤|+ÓÓùÈŒÅï{Þep`‡Uý€¿R3rØsŽï¹D¢Î_Ï”R€®Ö„çOÅ‚/{£/›¯ ìG ç3åcÎ;<ãð:*©à¸€bÖ›;®˜eþø–X{°÷E Ž×.³J8‹Ïáõß/ žÊv”õé­f<£UÌòÌ&,ºgz3žãÒo½¹?ïòÀÞUœßÍß5´£õž|Æ“%/ùUîå€.<÷>3~6[õ~g†ïãš×)&W4Ëȉù?=�ÿýÅô½¤bß­GD·§`Ȉcß— ÕùêI‘îJ"ÀÄ$({ùQ’˜^ïU1ÕŽHµZ�l4×r>‰åb×!`«žÓÑLªlþcZ­_þõ¾}ƒÜ’÷ù “ÂÄ|ûúôõ¿¯ýýv¾o‘A¤G¸,Ø_eÌäùŠOÌßàgx£ú1üiÉÁÏBñ @Éß· ðy#zp²óZúQÕ=Õïz\zÕ×JÏ"Óç«b.>@d7ÖX”ŒTùú¶cŒ4mH*ª}KL¥7bŒ¯JšQ]×ÈÒëjÉÄi 쑵ÅûuŒñ¯ Œ �  @6c‰ý ̰_AZ±Çðº1ÃV ±@ö¹²J¯Z©èW2×’5v»&¾k¢®VH³ãÌ1”›wôÆrz鑎4Cï8J‹TRfΔãáK zöù`<ÿá€ßð¡óçW0F‰¢ÏMàúÅȨQR=6ÖªöÚ•Ž»½_[žËè®òƒŽV5ÐUŒ2¿’™cªDú¨bNÍëxþ¢”ÚtŒ[/æ;2G<vÒj“yë7û•cÛnñ娳õl„É,ó@Ìd”`ûå+ØYl5ÖÞm>8s8ö ¯âº.mã×#°]1ûô{Ï� ÝîÑ8PhÅ ™[ÏüŠ€&öÓ¼¾‘‰É$»ŒÍÑ<΀Øj�ƒýßb~âyP¿´Úû¾azØoªvÇ‚Š¡â™`¶ž”c¤*‘aÇ?_v!.(x£û¹u² ˆÎ›wu<¯Œ‘WLÿ}Þ oé:vÙgm76Ód‚¹|à‚¬CŒ—¥0‘ÉÕ5ÆÔ{3[[þZ¦¾38p|ÊÒµõp éòöm¥ìg¹ìñ:ßø¼éxà92Åp\Ç lzÀ ¥û˜›úmð÷)ï_N¡~í~÷=XîÂ[~ßïÛå>ü\{Ý5Í ØMÑ·ŸØoí/LÂë˜ãÏw¤Ñh;ÿX¿Ëëc|ñïûû½À–3FPéãtï–ä¦úÞ²òî�Zlõ,öŸÍ¾G³~祻 94`„¶÷ÆÕõäÛïƒtZ*ÏŸhºê>•~õ¼úø2ûû¾Ëû4ÀÖO±ã+VØ*×|o=@W§«Î¿ÝS~‹Y5÷!V˜+yŸ?êúáÒ‘€Mf©-_6n@ ?-é×c‚>@\I�âs‡ÛÆ|Þ¬‚Þ¿SÔ¼xu´cïOUÞŠ±õmóxŒ!§Òßcží×Keœ©·Ë;j°õMÖS·¼Çb®MÉÁDzpžÿ‘ݧöG¼þSÌ4eî¹I¬±1†Äþ[^E˜]KJñã“ì·qÆ(�å%ÇŽ©å¤ñy~c†ùc“96²¿FÏPª`­äD†X4ö!ËÖÅd+-WzÞQb‡õG$½f9Ndb‰R ˜ß<ýqO_­U+q)ÇqDTL±®£…”µùç^D:çÂA¥ 'hÑñ¤§¬\½Òt®Ì_¡]1 _ÎÜ‘a¥ÿìŠ}ÖŠ¦´˜’ÌR9ÅÈD`Ä×Ód&]б’|óÏ .=ÆRç�ÚrìzÇm²Ygæ— ­æc ]Ìó2G9JA²zàùÊ¥ØV:QÚίpçõó1–J’ W˜#Cƒ;/ä:t Îçç�KOº¯:iß§¤è<@¸yk!Gæp½ˆ%«˜PÀ:‡}ÜT?1ïª&ÐoÍã¾<¾>Wæ%LÏÉäßÃ3a€Út-°Íó÷µ5ޱï/Ö—zfç¾_ØãÐñ½Ôõ.Ó…Ùeð~w-Àzò +²öÕßÜ1œ"#êÍm{åBKyN²f8ƒÉ¦ô½k°¿Ù]@¤L�›’ÝÉB¬ªDÒŽn‘5>B ©cìw˜íË:´­¤u§=©ïãY.�ôß×9¯°ÀÓ«;õ°êã ÒÏ[§ï‰]hÇ¥óùÐ[C íJÒe×Y³ãˆX?¿Û}ŸÔüògö)ß“¼‹ú©bªíK"`t=˜ÿi ÈÄØˆš¹œÙ’(ŒŽ`¥”Àó³JOÛÑ0®¿x?Äû¼ïÝ…I'�`Qjna§­÷íà ¤ç"põtu€š­gÜâ›l|Ðâ̬Ë(w„+ MÇ&ã=g Håù_L·XSåP�‹fŠåéí0Rý﬘n1Ý΂µçG{¼R†ÚÑSß̼?x–ßëcv‚÷Ïh–™mµë×±b¡=ÁýËÁrï3ZÍD®¢OæÌ#4Íüy‡zy.òuÌ0–Ób q ééðÇ’ŠVÕ_ÈÅØTU~}¾4ã,­†Ö—äù«i±~¾ŸX¼Ï×^ ´îJ2îJ¢u+Å S’‡°ª¬ŠI†ÏwÇ'`÷åñrZ@ìù1éD»ÿëã_J2qš—Xüò3Èìó¢E ÌÆ[À×mß2Åæù_·l‰ ±ŽÄÁÙë£&˜qE¢8ï¸;ÕŠËÛ¥p¸eÒ&ùÊRèÄ•xiI”#âC8p‰¤"ßÇ éþg'gøÄ•Úßgåsì« 󽕜ýÜuG︰Ÿ«ÊÛNÇfd„ù8g³Â¿ËäP¥ë8Vþ+�EżῄußuÄŠaæ«QßÚÑÎ&ø6¶cîFýWŽ»n¿ãk[­¬C_.u:‚«=œåón[dTqiÆ•>æSÅÄâ’ªX?„À2ÀT½Ï«!ùvOÇÀŠŒ¾ÈÔ묰TÌ1ýû!3X=ªÇœY´ŒŸõ`cTÍ-XH#3LÃl!ÊwV>Ë„³@˜Zh“3ÖïãÛCÌG·Ÿ=b+W\J÷l�0\P€ùìØr¼ó˜Eº¾b½T #X{»È;øqÆ`b×wÇKj“F<Æx¯™j-Én´±Â@ 1*&ôÆ=þýRë¥õx¶vŒ3fô°ûe•Oõ=Çü’÷æÌf\€Åák¶p†a€)f§²Ù?¨ôöLI%î™r>Ë7—Ï#u;ÍóÛ0ߎ»£.Žš'qæ:ÖcÄðïR�&cëÍñôd¦Œ «ÁÒƒç-fâªoX-` ÓËû1Ý"=@™P€¨æ!7‹¿#[8v¼¾”EÀgO²KÅFåq_oŠ Ôçµä 1•ߪ^pµwéÐíÕ‹5T»XØÛéWS cþä÷¥šŸ¾Þs4aÃìÛšÛXpõb†çõtÕÂzûÞ{Ôɾ‡Oò÷ñVK†V@@.ØgþL�Ì÷ìÏÐ"»ïÙ·°=¹íǯi:O¢üû�M¨ô¥ùB€.Ë¿¯5ù>ü'2ùºRŠß«Ý©ßÕoc¹= ‰ùë?ŸJ#šý]Àë(ã‹c°ì<Z ýS\'cˆ)fØÿΙa`O Å?ü}æø4d„™-ȼýòøÏÇûŦï�°ßFÈ´¡ä€_¥W*úë®°µÒ‰|eäzþpÇ•£Ôo­Ã©ãÀaÒ%ó¸O9Zg%t½²˜-èÀar>Ÿ¸«•Ÿ‰}eË‹¿Ó¶ßk%t\ù¥—òÜÆœ(&߯J€Ž¡xTŒ¡ÞÀMKXMÇ2›P]FßÁ™9>´#~þîzöJ®Çß“1J,“,c¨|N‡oWú¡Ã @ Í–Šÿ¾žN^«6Ši–¯ÐEf—ÌŒn“å(´¿ßYä˜Åø±�¨Ú°œòŒÈèPõùšþspx`ãòh?¬ÿg€z<C Û'²ìqÛn™CÑàÓýQµ¢y‡é†ïß ®–y1LMdzy¦Jª|F ŒMȃÔÖ{ïÔŠëyw$c}]d½áŠI:†ÿšf buÅU^£2cÎeüÈxöï}ê«vÏWÅè®ÆIù~4ß_œÃqdn~.fXœFã8¨Ó…Cè~&ngþÝ>A¿tM~g?P†1®üóµR€ŽyÅJ1ög¸à‚Škþàc‡i)Gµ@…/Š€¶�óó.ÿý]éF©ës/câá‚Ûb?qT §·nØîç)/ÇÿÅí¯óØÞ·�æ’ø-2ÄötgØz‰Ïº¿ðß 4iŽÜ=ÓWÏ¥ã×{Ïôn¤-Ãã=I‡å¥?Yì¹ì»È�_o*&Óú½ßÈ}Ó2©º3S…pè9îßEû¬LI2é:o*Vص¸oÏvïWŒ°UÞŠéÐK?Ë×h<)Jbþ: ឥc]K†f 1¾Ý? 5~UóØg{~`1ß4|O{R—³ýÛtÔ[àÇ–ïÛÁßççNð¨$U {–×uë -a¹S?`†¦²Ï±é.�fXÓ1Ôö�­*ª¼0Ú«Ÿo²ýU ÆÞïÿ-\ßËç&30‘>¤Ì-²Oc‘5îo™ÉÏ?Y:D¢‘>ÿãÿ'™bÎX 1Ï S€™)ö›Ù_þÍ^Ȼś�˜Â°ò€×ïèÂë~ L²›ý5º±É¦´àšˆÞŽ\"nŒ¸ÂŸ hãÀ'‚Jû›¯X‹+ö»+b0&š·¸"³ç°ˆA°ýóôŠÏÔA¡�°1ÐQµçê?çLöØõ½úÄû*…áÊ!Äø¬ÝìO{W‰'³ò–¯5ñd+÷¬¡ôδjtK%®x, Ôô¤ü²u¥ÞácFqfÎÞÿ3xWÌCd`tZ2Èðøœ·L³‹‘¨d@ÛåÁtñý“uLÛ߃ “ñÇÏ>°îShh�� �IDATQ¯˜*ØO† ˆ9'¿×zÂÚF à õw-JÛEÀ!/÷ùQžÛžÿ®Å¯À¶Îâ»s÷!S­'uW1±X½ãñ®cX·€Öº¦ùvŽ1ÇcÿÞÏle ¦l%*cB²|`ùqÜ êç2.¢Ÿ¼„ý¹ÅqÌ|g¢èß¡úÝg}ÚßaõG/®œë÷{yl=� ŸÃ¬^0cúú©M1 ³­Îÿ ºÝ5S„t¥¤÷9ïøÔå¦õRÅK$»ã>[Àv×uFµÐéZÜ—ÅLd½ñô–p3Ëe·•E™_(ØYPeíô�è8àÁ$»«üþ«Í/”ôó»Óc\óѳɜò)XfÖÄΓÞá‹…ü}ªæQº¹ãóú(çQCFšîAy½Ìm|)GnÌÁ[sŸµï÷û øùË”´ÔÌ0LÏί0Æùšw]C»~MëçñzC áúÈ¿Ø2¦X‡aº€ècKQ—#üse%!X§Ï{Š}`ã*îÛ+WÅp{<ç{9àW>;ã}V¿;Ì~æ€V@ø4•/~üÞ•²û¥¾<›m^ë}òû3–ØžOt^Õ‹¼,À·—ޝ7Å$¬™…]iÀž½Ä»ÿ~q�äéÀH–*UŒ°Å4Âü•ìÆ�Û«§J*Ëy\º¥)w—"E1vn<ß@Ì%AŸŠçD‰Í*ßøüi]éAÊ(#æ€(%Ihη ™k$S¦j?4bly)Å¿a‹ÇL°JBqŒñÛ’NcŒñ«fŠ}üi€.d„ÝìwNœÌ±Û}?%ˆ 2.µ‘OÐN½ ·K?_‘µ�îHŸWÅü·«ô –<_:˜:sp)SÓ€«™@Ûó¶|>_é�vCÒ¦’ÌËÑS×éŸCy>·Zå':èªØù°Êußq2ó·&žvÅ®]AmˆÇ'Â`A ¬ù¬0�YM¼ÐA™|#SÿSÀÖ‡b2f:`˜ãó¯¶Xþ‘÷)ÿ äÇ3\ÎÆÑmÜ6–_ý>Ùï²cjÞÖ,4èñ xÛ™8Ülº�ÚYáϾo°o¯c�oÿ(ñ¨WôWª¾6¶ø(fÖY0ŠÎDZo@:*ߘ #,ëOag0{Ö ë¿òúS1:4cñö÷BŽòçæùà±Ð˜[“ƒQQKOªßaŒ\*ûv™;Õ’«¦bö±mµ€)Jfevø§Ä¯Wö}®z •ÿîþ²V97ZåvÝqXe¸`¦.—ZH§žŽó Î`,[ß‘þ{%ן Ý%%˜KùªrÛû_ïéßžsã.ž÷ÛyŒ®÷j>u³ýuÜ'¸®ç é›¯—åìõµÒFuÅiëjý”³øý<PÚeŽá¥Ãì“^Ýv™/<ƒÃÆ3U7úðïãd‚=€è¡,cH«ìñõ¼k1î¯kÞ–SÇlŠéØóï†!6Üñz¡·Å dþ®-¸b'¸„f:i†Uï}ˆŒ¬Ê®ôú¾Ôbn(öŒ¿ÏÛU¦Ã¾5³l’|yæûôÞH3ÃÞïûë—ï¶g“Þd†}hæ'Ö;J›ÎØ|xŽÀvnþúo÷ý§{úýXR¾¼«V>›©/ÇÅŸƒdâ±çÛúºßQU¥¥ûêz•¯êwÒ@ÊžŠûW¾xì« àÃçíŽw"“­7²x å;Æì‹±â¸‡¹f8vëI•JNÀ¨ŽˆMÀJmŠ‘–Þ7™l3?ÈlÃô©ÅÉK퇱�¯ì¯û~”e’ƒŒÙ}"¥øñ§Ì>þüøÃ2¹PZÑØbŠÝ¶¿�Pæ¥ÿºdS:ñ§cl€xç9Ẏ38Ž.tˆ¦ÄL‚WPx“RÏeA¬q…£¿®ž0T$¶ïsìr¾ä|ŒáVüVùÎSÜŸal›žÔåû˜þJi”ÊWBvÝ4&Å|ÎÎDS1 +$3îHDõ œ×Œ›®:Τ½fºÌ‘½ž‡LÍËB­8öùBIª‹,ê|¾²ró ô’|óhŒô5œ3ס¤ÙrpGIº`„×ñßaŒõûv˧öUú=Ó’-“ñåusÿBË—µWÎàYûŒ©¥k ±ª_ÌÏÎJ|f|EþdÝ~ž)ôú°x`öb€]ÿüàÞ,ÆØC�GYxyfZÌÿíú ôWú ”×ë¹xN”Мõ=Ïç€<Jªb¿²4ܶ‹fû…h/~*3öݱۥ€Ç½DW¬W¹c¾v׫t{ãšIÞ3%{90wÜpÁL·Üî<2‰iz‰°OŸX™œêjÈÈæÌåy^/Hóó¾PG¯;¾´¿§³þpB‡vçûq‚ë×ï³ÆU|á!¦ã·ðÓ bæõó~ËÄ™×u݇Wš¢ZÆFzZš¬»Ž¿!õºëZÛâ3ÆêÛ—•KŽ?éÆQÌ0Sìd€L|_fûtãš/¾ý>F˜u$#Pf­ÇÜXÒsžY²ÊÓñc<ò Œ+Açó3ô+FÙÇš ã‚­¸Ð2{o-£Š.¹gà¹Ø®ôz’pÀ¦m2nø›yˆ°õ ˜‘ˆ¾µÒÃúšíS- >µÆý̲yàó£~b}VéÛþýÛàãÇÍü|aÒ“SÕïÙÏò1Ë=ÆÍÁnï.àƒ†ïQlß=€X1q²'ú½É; W1¥¾ÓJNý˜Q{žÌóLå‡3õ4‹_×€4uJkÀTÅìòÏ‹�2¼T¾ùóWº{1Êú@ªúPòÐFDB±’>œ÷#ðTeø¼êüV:Il4Zž%™8°ŸîÀØOC[&=ˆ1Æþ5±)¥x“JÔÌ1œ�a1– ¦¯ûdÑ* É^g%­£ˆM”#ÏZ”¹È‰>Ï:Ìëu©¹dºÜ¢Täq¦Åv"à]?…¡’´1ó}«Œ;l®dà<ËÛ3î ŠÓÊ)1ô}FW1áÓ°þó‘™’•«‚ú”„^VNšûó÷˜x>ÛfxÌ”t™-¥u¼OæÏ”TÌW¾žÎÅDn½Ol"kWî÷˜E9s$æ7Æ6ôþÅŒñõ6®Èœ¹åÓÇbº„Lƒ^@‚-wö»±}UOÓNYÅÐé|7²|íNÕõ;ÀôÎu‡ žÏ~X€î$8×ýv;$ãëÅ¥k¯{…û3F«GÖ¯¢±öûš\·Î_d½Ì'r =Ž_ì}‘Y§/Üï½_¾°€¥ÝžMáûU_Qz•åòv¼ãë×÷³WáˆË˜<9ÓNY—æ¿»§ñ½Âþy1& .ÐØ35~9í•WSÀë-eˆñz?%ãÆî÷ƒ×Ã¥è7.i1…£41³\1ÂÆòÂvæË{ù´ûZ)�ß >/@‚©·[¾sëùwG£¹4¦fÔù~ÄÆXãùS9¨Ž÷,ºÿº€2–´’F•Oèíοâ}(•©ßøŒa2Jà9Ý™#«Äè¨Îê!Æ”,ú}3Ì]7²¡Ç£Õ÷–rسéz†Ç¬¯Y/ó<ÆzBÆ“~/Çb:{�”è¶¾y}Mý‰Þ´…¾‹í2{ p×]ÿ^ôŸ•6œ~‘éËÃ~_Û~ÞÈñ@^Ãï‘+Är¿¹ôb}M&Õ|>ÿýù{ô-\ÿì˜Tc¼‡mc^÷Q3ÔV¹<c3g2³ù@G~FŽrx‡¸ï¸@Ï<#ì]¼™}ÉÄ]é½Ðé2¥"´}”›z°T̪¹ÝåU•çsŒøŒURŠóúJjÒ|4À×ûðÛÄ90·Œ2ÂF-¡øÏæuÎ 3š¿±�µ £R‰Ésil²Cì¯Çö¿éqkS mcÃ3Àœý0”N¤Ï ±›ýî¶?ݰ{ú /ÆzÔæ¤72ÄÆXRcÔöÆóæ0`tYÇcÎèòñ‰¶hâDºë°î”ãÁ¹cùÒàç¸%̰=é”ÄÜ ¥Ëž§žÏcl|ÞÀTR„}‡û]û±Ñ* Ì;XpEîÚ™uШ‰_9¥%øìþÝÂìØaEàèW¶>.#{ŸÇm=¬çð îì:ÿ+Dé»×¡Ü¸óù® d€`}ÚëCi•Ç;Äcǧ{#ýÀÐeÙ뙳Œ±· t¡©‰`×QR]_í«÷QýžŠÕÍï›Hß[ÏŽ Ä›­ý›ãxµ'ÀnöÒ¬¿ó.»¾Ã°»]W;t9“äú!f+°_õs *øû쬬#ÿ}#s‘3Âv€~tœ1³1‰öñ…1̰ó…Yù÷6J+‰D<²rÃc‰íšr“ äca] Äû=äõÍNa½²ØTʺ øx8/ö³JÒ’)(°þù:p¡ŸW”¨Ëãz§œ[ïÖGŒ}äÇ“1Æ3o⿎Û;ûÞiI|ŸN]o§£}Ûg†ÅüÚ|èúªHÜÁµëö<ïCu~“¤³¿+2š,Ø,Ê}wûÐïãÌ^?©S“Y¸�¢ÅÄys[, d`Ùó2ÀËpYÌ'û÷.†šàé( ™Aú\-u˜ÇÐY ¯c¦`‘‰ÓëQ"`ŒùSõr-ÒQ¥?³ÀĶóÛsclµ×Á˜Ÿ=eм?öoL±È|½oßÜñtüO™b¾ßÁóWÑÎ}nà9¦<ŠùŠ’€Gªƒª2íøW-ëÙ•ÿ¹¸ºkßĶ ”õcCùtŸ’ ßòç|k÷o9ªÊŸ£êgwáA\†ç/>¿ D©|ãq.¹¸Û.ºç¿ æTL6Ê3–J&F¬ ûÑÞG$»é}*vÙÄ–”àÿ¦WFÆØS`ëoزÿë+ÖØp�—’HœÇ?þcü@gˆýâb†Ùó¿ŽSlZÍ|òÀÂP^ÂÄÐ>h)8ëø?%€ ˯Z™1¦8ÃM]Ë1Ëߘ#CŒl±a«‚¡ã à$hºŽ’s+_/ø|ì¶zL¬.p·“ñœßË4,‹ç Û ®è¬3êxæ8_æ­3Hr-ðb s>Zd–p n¸ô#Œ½}·÷7JQ²zŒ’ª>6á’ÔLVÀ³X=,Ÿ¬þóó(eöòÏ[2Ï!F¿=´iƒ¿Û¹pÀ3àÇ×2Ö‡Ž9…L:5!Ûe¤u?ü±ü3 'X¯ö9°²Ì?ü½âûûµ`FÇv…ç'Pnóݱªß±ûÝt#Ó ËûUÕ/(‡zŽ=/Jù½ ö{Ätv˜–—1—¢/íŠÝfë'`óƒ3Kâuþ<ö——´\¬^˜e‡ùB(ŸŸKÔ[×1¬l.ØaÒªö¿¸àbÏb,Ún:®%ˆ–ó÷GI>–¿]fî®e ÔBµ@DÅóíë?úýáùS £ú—bß-v¿b‚ 8ÎÆg}‹éÚùUd@&Øž]ïåóå½–Ž˜Ü¢#´Z½ÔªÏÞgò;>;O©�»£fî€^�’h-#På“¶;3cuïÑ—30r´©ïžÏ?g–Ø"à6ŸŸ;õŒYcÇàL·àB†)ú´ás­!sê}TÐ/7-uX1·üóöc‡u¯ßöVz˜¯co˜ÍïQÑ·Ëi Îf®ü{¨Êžåº^(‘ø|gŒÅàóù>0ÀÌ{ø�ñ¼Žcþ)þ9ê÷W×g=éìïXËÒÕ€“2έ|Ð×>Ó¿?ZÊð{3Ý|:`©–”y;îsåè,úL~* •:V˜bºåýø�U>ü÷¤/©Ò˯[ùPÀ“;NŒUx~ÔÀÙ`×IÅîýi>H>�¨˜q?Œ;lÜ·(™øß°3 0MéÄ¿‡6Ëܣ̰±€²TJñf¿?Òµùú‹œ÷™eJªÏç@RÏaɤ4nÏ‹+)séY:àx>–ÃÜ;Ðñ¾9QÆXQû?«5‘ŽàXß©†}]î[LGO˜­© ûÑÏAtlæ‡Ï®¸ŽÝ{æ‚ËêÅŸ¯ù`ËV1M|þ* ù’¦Ã¤Šø{Â%Òð¾å°]±®ü}‹qö éw� ÈÌãÐ Ø–Q††@——¸‰#Ïpš©aói-ê×ù%fá#¤¥Î|úÛis[/uÇ�x-ü«Ùb̳ØZ‹€,ÏÿåôçY½g +2�[7#Io]÷Õ}gÐ{(AŠÒ… Èò�ñŒõêí–%HSåQíÊ·¿¯´ÞÙïƒçíï’-ïÀßÚÈÌšW¢ÃW}ÏŒ‘ÈðYÀ9QÚÙÏïÃ÷ ö¸@Á3ø°ÎÚ+«ŸÈ@Æóø}A.HÊ¿—•Ôå¾eâšyy;¦˜`«Ô>ÿ~‚SŠçâüãS�™ÍjÇ!8Êm¼¨>pdLªïõE¤ºËÌ‘oË×c¾y&‡¿Ûôgy2 ílJ¤]Ædµ5Âê‘—s˜}ÆðRJ6&¦“›–Ô³ÛZ iï _nÁž¢Åq73b=…Äâ|ô¶ýìÌI;Ø3Æ0k‡¸Ç³š'Žáab†)ÆŠ·+Í?J JÆšHÝü8@fOx}1 óÃ1/½z4ÔAtÔs¦X•²–D¬ Z~Ö§’Z¬˜,ïòþÏ-‘EfÛQ¦ÖW´\jqϤó´[ ™`'™>>çmèXVOZ1@Ø´/Ïû°ï÷�`¯@CàÔ3=; NŸ/ŸnͤÑõb÷õóÕ{ðÿ0÷>Ëñ=²hÉ©Ûz©»û®=ž»ÿÏûs1öxw^J¿ni¥³hUÈPlyâb!Šl²þ‘,V!+9“Iï÷8^/ Ãýž-`n¶WïýÒÒ„<ýÊ4�÷(àÒµÞû%þͯkªÿÞ”°ÜÕý‰ÏC>ó‰ Á“ÛÖõÂòªß�Db}¥6c„hU€Z•îxäú¤œU½YÉÄÀ™`·ã Húc(C`‹dö¼ßÇXL1ãû·ôP–Ø’Nœõûý«>ÿ¼ûPÅHñ+E‘¡±LíÛ‰”rÔDI�-5èWÐûz(fʪOœUwžNuü\¦3·+¿l¹ˆmEÇ1†Úw™b€ùv@æØîŠën÷Éy;]Šóu­½#V­èUïw<*æÞš ÕRo¼–?‹ãÓ4PÁ cEë2ÐñuÛ׎^ÍHäÀˆ–Fµûh(�‚G¬tõSŽ’u*&ØV:óú ÐL‡»bô©V�ú|9*få:ß3áb½x:C‰½­l‚X› Ø; rmÐúÙ=ÇØÎ#²|þøºéS|z€ôgù|X œµ?.8Á÷³bn3�‘ÕÛ§›Eçºíûúpi¡søÞĘ–ªÿì0ÀÙuo4Å̳µˆí®"ôôú»·êþ>ÔÌ~{}罞©æÌ±.dÙ6«œÜA|ÔP ñR–szÒåÃú¥ŠÝü1Âò/QŒ%ùu›}¯-`nß/ÍDFÉd.AXIýYËû Û‡]¯€«î{]9һƧjan g­'Xdó»Šó¹cå¨Ã¿–HÌuµ_Û©øu·§Â~P×cïyˆ~|ÞïŸõ<úXGìþ+ íuŒÐC…XFOg9Ÿ˜¥·Žý™îé«\×/&[œ'E Â2L0f˜:™<'Wßw³µ×g–Ík4/ ÷R ±÷M G3K*I°ïÒpñé*@¯Ã|ÊLßï]¦™JGI�Æëw2Þ2"¯áý~u¿÷Oìñå0o}Ç`ÿ ž#ÈŒi)Ï DyÜž=‡ûZal< ŽØÃzyÃP‘1VÕð{ÄW9Д3”>Äùša–IJºRµÇ­C«û{-¨�¡£ýWžŽj|öcŽ+ïÇ=¿.Pœ3™�I¤ ÑþçÑXa(i¨ZÆþÎ~ïÆ›ù˜-æ OÆ›L±\2ñÏ;@¦±i ³L±1þzúϯ¢þgžÈçÿ–L².@f°¹ÀØI¬„Θb ó×)ɸK: Å|tPq%5ˆgEÇÆ&ð`™fCLôl³Þ¸47s WàZéƒWWÿ ”ËÕ_9<éÄiÊá¸�UžJñ å@f[åÚUf¾†‰e/æÙŽYGfÎÄ í«8ÎÏËÌZª4g~L[¹D £·Ò1:t³|0Æ;Ï:è™äšï¯¢c1¼u ¸ŒQĘm<ßNÖÁ—3ÆÐ¸#=c걕õŒ!4ÓcÌBË„bÀ¦ežÙzù†ÒqŠ‘¸îJ¬ïZPÉD%9ù#œç-þCú¾]Ñ‹å·å;*m¥î³zŽðÇb9!#.ÞU—ó—@?«¿íì‚„7زò €—µkÇ.âyXæß;ö¯ß»Ïƒe€ Hë")à±úùqdêd-…ùÙ}%)xçíÚò¯øô» uâ´·âš·Æy`º¦eŒŸ.c}„ëýxY[L×?†ì÷$¤püt³Sy]ÜçÀ½·“Êvû5Ûn§¡çQßÃÄÔ ø’ù-¯Ý2³Ìšxþ<þ=KóÞSÈ^ï÷s¿¶Žžd}æÒ_ ÉOkÿT¤³ê·¿×ûw†}—ÓÐg˜_cŒñþä•^ ½ ¥ÚÕ¿ÿ6fØ<cök·rd¿1ëöø»9¾r´çazWwþ‹ØVŒœ«ùãÂ_ÿzëAõ(p¤-w”FÀ‰ï«tU{¾˜ûôö^´OxÆßu»¼ÂuùüûålL5ˤ² :’‡ÈǾS*q2”¬tâp[Z”Bü¬™iW÷ž)ÉH|²}¾Ýoé/æS Øfó­š ØžÅ~×ôóxì@@î9´Wã‹×+.„L0Ïð{.ڷߎ=)B ì©ô2޾„Ðz1¼V=÷ˆÓ4ÈÓûh>×Úöau,?Î@1Ä  4íovž² <‘óS�lô™a83Û*Ÿ´\?‘<0¶˜a“A6%9p6í¯¡%cü‚ ° ŒÍã0cÒ‡ã–ÎÓãÊf,1ŸÞ™~èìcY}pё¤tf¯Ï<a~l Í&¬lº£€½9ÐÄ ¡Ï×;ŒÔ ÓîÀ§¡VŸa‚qH"‡ü¾ëRé­¤¬¯óõ\�æ¹8¿gûŸ“£+À+`v·ô 饫ð=¨4äOw(ñÀØ%ìcëÔÌ1~]î^úõüd€TL7:|‘©wĘã?[P1m*¦ :Øo¦˜|?hþúúô;p1L©7zž—X!VÕÏîø*2è0Þ<°†éX�Î3ÑT}´!0È¥Ÿi»2æå+¤ÇóSÔXß×âüÈ‹Àr ²ßSûþŸ °ÏÓ­úÕ(å‡ mní_¿§æaV*μ[Ï2$mûD ÛñGøý•äÓ1‡øñF”ÀÓ5ö–9$3!ä0èBkÞ® `Çâ÷¡çð¯Lýœ(I©Úá<FT˜û °ª\ÞáÚißWšŽïí,Œ³[d�Wýë'lý“Ó¾/Õ|e:¬}:()ºÚÓWíðæÒÇüÔ{xNßÏŽ½‰tü¼È?'§ò¹Ræ¯Ó}»Ÿ’µ÷b?š^�àËÓ-U.Ut…zîòdðQõS±ÿôŽrß>,FÀðz5ßeÒí.Ý l}õ\/_û/Ÿ·çëý³î²…º«µ'Ck:ú£#2ç( æåËqn>€¾ÃPaãìÓÝOãÄ¢dâµýýžL0î˜]ïË1æÓ(¯÷Oü{ØWé)ãïÛz¾¿§‰åáo®~n´Ù…™”^õ^ä ¸¦¤àUŒƒ‘á8äþÖ‘þòõ;2ÃÞ¿Ò}‡ó¢$âøÚ¯¾‡öùU’£Y–Û­}ž“ß»ýc¨õ¥;9«+Y‡Oî—4å]2ñ(0<•n¬°ZZo�©�':€æw˜öö®_vT„|8꿼|9# c“í×óÑóÝu*vÖX�å•0¾ºÌ®.�Ö°þUl[ù �øÓÐÆc‰ý9ú† ±/˜‘P4éMfØç ƒ¬´?¿®‹šùqb³CͶ×Ùë-ÓÉ:—~С¦ÿ‰¤ã÷Ï_Ž(ïPcg¼~:±+çDW,÷Û9¬b{Æô±¼ÆX9\Ièä+(¯ÅqQÞ2Þ9ß3ÕwË_9ô¾V¼ýò–žÁWî_ @ƤæyG9¢pV�4ÖF9x³i¸¯ŸÎ e‚.=J¯œ¡ªŸÿ|…ö%”ß'»Ð×O1s˜£œ1[,㫳‚P¥—,äx i=¬|6}¿ö³x>~@ûh�Î?'1&Ö<_9&°ãíñ3”#–W1Óòççgù~(«Þ ƘS .´È òï—Ðj¦82,|>ê=‹ n¾e•B=‡Õ÷™÷?^Ó2»ü{îŸG&š¿º<Þ±¯Çmy=£d"ÞçŽuà­|A••b»%åùÄØrYgt(8žKËŸHfó6Qê¼®oo<‹Œ"¬O-®ò{Àg Züqΰ°ó;^b ùû”3¯&õÎVü_M>“fçS×Pïø|`zƒîwég:~¨òß‘1õ¨•Êêà{Žþ«¸.¤”åšuûýêtÜ. Äîáé*ç`ïuŒ%}ø„Ý™WOg1Žé$-u{?V ßÞ›ÓW9#Àg£äVÞɰYŒ›Ï0@Üé«zðyŸWòAÃî{3¨ÈÄÚƒhkโ’ó7 /-É`»Žÿ#N•#ŽDóR2ì8Ösf¿‹tYzpübž×‘œ—7‰ÄY³ €ñ÷ç}¼~1ÁS,mÙΞá¦cóÁ¥_Yº,¦›Ðyíp%;»#U.i×Zü“[ÇÞë–‡¹t¹r`¯¿dÝÇ*SÒ‹µõ¤ñ‹¦�qÍ�� �IDATž•Înl®™ž¯Ï³¨·Þ÷Çu»r@êYô¿Ïò;PyLýyؾýç÷h¾iý»L¯1Å’˜\³«Š-ö/qÞ¿Äy*ÿ¿³ë n/bh(øý½”ý>–tâ]BcˆUŠ_gý‡ß~þ׈L±»íÿ ǧùˆ~ÅmÅ4ÁtìövýšÚ(Æ °×å ´¸br¦ƒåp¶ét‚¾s}”*˜€¶ß�Q¯Áч ¡dEñÞJí]…ð>ƒì G}Ì—£XK¬&úÖ†Ym.Åq¬o´¸Â:›¸1G {úÀ2¦Ã×3!PâN;„= ÐqT³zÆp©&œ0¿ÇÚÌÁ3S*ÀLåMg×emXOÛ®Ø.Øîìm©æ]Çg¦©ë5slZÊÑïÿ ùi` +ŸþöÞèïóö³hGdFþ,ÇòÚë2OÆ|bnïùœT�ô ÇÏÄ1ÊÑs/É%|Wíû‰@ûú £8‚ê=Èû…Øþ¬º† ?ÿ2¼¤è×)€67=}Œß/tøc{Ûóbû{û+À™þ½÷½^Ó3þ=Þs§±òá”H¬ûõNþÊ}Ðg‚UãŒ1F”Ân0Äò}\pÆl‡¹a™C{Ì%>n¿ÈóV¿ )F*.ÂýÜAWIXqéuÖžì{©˜WW4²|*…Š8‹Ì[_ÎÎñexÏ?æNªmŸi’J9j‹ÀËc5ôßÍ+y_ýyÚ2æÈÜ/˜S*±iì“Çø|ùÔóšj!×ÌßTZ‘=‡†œ·“ø=¶ˆb²ä~¾Ðe1Ã[°¡ø½;Ù—6ôéE  º¾2õž‹…¦™nz›1/`]÷ý*Þ³% ˆæ™‰¹âÈJÿê€4+ý‰Ì0–ß´èо¥ø<¦tâ²·¯– ÏýÓ³kc(™ø¤˜_Øî/¢X»eóYØpÆž6¼/Ã\¿bóUï×w- ñ@Øb†M¦X×v¿Ì¬p�+J#vs´£Lªª_ؽ9cJ™Ž©Æ¢ÏÅs£˜^Ï›�Õ‡È_3½ÔõØ>X®hÅú}³%Œ±1ÆžþŸ6ð¥�.e©Ä!‘pÙù*]+–«Äþ”Ç=Pö+9'“2´Šsûï13,¹þó¿nç¹bÈ û=7ûÿß×Þ%8B”TÇ0Ç™©ëǰÒTEÀŒåÇ^'5Áå+Çý~#å ö+›+µp%çü5Î&Œ]†TZäé8!À˜J'w ¨zìÿŽ1Ä‹)Ö7¾òRId®zhG¯ÝöÖ¥ëò°ãÈhb̦ît<{¿ò÷ŸKÐ-JŒÅä·‹I1Øj‚8’ã—ÑsX)©%¶>¾zÿàe™©ë</q‰÷Ë:øYyWy"�€@˜bÈ`;1ZÖΙ㎯�‡ª]y:‘qå‰ây@•ž Æìb®ãåþqîý}äL1Ëtë<oLš° dzà7Nb/ò}ÃçY1)üwùR”S¯”î•{„«óç1_Ajû§[~‹Æ�ÔU-YzÄâ´ÑKÓEfz pf¡Ýâ•Öò;´¦EÓÑÇ©}w²/Gìç93j·¾ó<Ž'ÔÚnÉxÍ/ëŸ-�²Ï ÷ç@‡b*-¾Z”Uß1ž J·GßüÂÿ’ð@Ú«ïz¯932.ˆâ1d'`ÅèáBCÖ^Wsÿ|}ÔŸÛÀаå½À¾ªç÷ä«ê‰U>±•òXÖ;åfï‹ÅÓ¹.;ß=/²wïÇ“vSäéLǹ2¹=…ë«úúò £JIÎåú>ðãÛEKÛö¾Tñù̶ï0–³qÝQ�[K<>öfkFØ^;X€Ì?úMž ® ´t“Ý…'öý¨¥àe÷?à‰þÜ:êG ±ÃrF×22 ¯–Jì='Ëñ¿KŒ[o©8»1ây ìÑXzw€&oŸ¸`ý÷ÞÏZª±º.Ï÷¹¨‡®Ï€“Irò|z” 0ëÆ"Óåê2ëªö9=˜Î®¥×5cÝbŠ©…F¥ àæ¶¸êÆ£ùt™q†ØÍûõ~|2ÆIöG*eø˜±Â¾b/àêó{¦—g’9¦˜ÐæþdŽ9àìfÿËnJÒã4öƒÜ³'[éh?xW2ÁªºÞ´4 ÞØôyeÊqÞ™(X¦]æð˺K–ÏúŒ`;v,jjE1‘æÙZ¹\æß”|¼;pÏw�Œ—j³Þ¥éu¾½OศIÎ CÇmænàÓžƒBO¬xùƈŽ>¡\þì}¹àŒ·Rdùôl÷K,_tøF)¹(ái¯ q¤Nà—G3ИdY<;l¹³þ Û1c*2FRœáïo⸪‡ªïh^—µÆüÒŒ¹È,Ë,c&Ùzd@«½Qr/¶‹fâ}b퀰څ ñú3|Ï.Ûo\Âí¾»™‹}íò•²±Õ¾NWy|Œ°‹9Ï÷þºË¨bùyS hê•øŠQµç¸V_1µíø;wø+I°zÚ¼7.‰ŒàÞÂek¼Ðu¥ /c¤€×#e†ùô×xÅÔeÌŸQõË `¸4ßïlÅËÝë9ó ôúÌ&äY =ÇgqžJO÷óØOñ:?®¨Ö+Wã= •2ž$·/Ù*ß¾–„µ÷öûŸ+L<¾^ü{€½þºwýægãð@ÄzG3_)Ž1³™9‡öìÁ`{ö$ƽ¤gSï»W¦ñ�k9ψóû‘s KK:1€ïÅä3÷�Fÿ}|”A¹Ê“K`Æ_<]IÃï³c ¶®íK-úú)Ào ÅÈÂçr>oK òU¤‡×Ùýw�¦êK�–úvÂð9½Å{&Œ°×¯+?Þ0Ç8C3¾¿Ð;ú<~Ü/Í÷hO^3&9 ‚Àć8¾ŒC°/°ß·ª|ž‘ô\¶Ïž–Ôq�§§ch 8o—™Ö}.zã›ÝØcñúÇúÙ:ÿ3~Y¥QWéx{ۚѶÅÀB¦ap©X^TqU`•Ä0Û2’޳> †6²_ï@ØoòÜS ¥1Ò‰Žéå%‘!†À×ÓÜŽOàÌ•g¦ë”™I=ð®ÄޡζӸЉì4&„åVŒ¶áÒõ¦š¶üj«Vı±œu¹^izhz娚(7 W"›ãûû¨]c½˜ÝÏŠ’8е; 0\‰[9¼ú†�OUIð(ÇSî(ˆÃ-ɲ·bÜÛ*U”Fô¥›Rc˱lß»úîþïoϱÇM±c™fÞa_9,"`9ùrkÉLVoþð¼³ø ÔÖŽkÌQÁ�6P)à"[A˜½í]¡bè1cõÅr0ÀÕ^ϘW óíTÅû‹Ç•4‘ŠÅyÏ2?¼hdBúó°l{e@˜ 3SÌÃü¸gòÅþ™‰ @ÍUÕϪ z¡FÅ8Òíg­gÆ•ÜqÞþôÝŠT1†¾Çú‚ô{\Å›¦ÆgCÝ‘,ÆŒ]¨–Msy¿Y-x:—ãÐì}eý bb¯-ïÔ8˫˕ÏÏ÷vô̸GÔ\¢•ƒ-Xª…{zãÅJa€¹ŸŽ­”L"ç¥|ÿyϵ¯`QI§åµÛ‰t’ßÇ~¿ÆK‹×ÀHþäL©DÖ~ÕÂÑÉ{7 Ì—ƒ§£˜k×Q÷§#ýæ_PÀ_Í™ííÄÚm–ëŤ³÷D/xñÛÌì}gåñ9å÷ý¸”¡‚æƒøÞ!]%q¸;éýž^ˆøò¿Àï5#0Æœ›ÇíwÓí<§~\R‰(%êgÆ�°çûõï÷ßǰ±·ðýÔL1sü“ÅžIçcÅ)�¬û¼. )Þ_[¯Ž)æ-·cÌÌŒiF+IŸ©�C%Ø]Âñ˜bdÎu¹Ò=©¿Ú@¸'ݨ%y?Ü/÷£KpŽJPòß»Œ³£ïƒ–‚<ÊDCS1½ÆÈê2ºPÒpJ38^åÓJ,�.ÒŽ�bž b™b†6ÆéÄù;J*›@˜‹)¦òUÇíï4P0º¢ºŽ(æàYÚóŠq–Îl¸VlêôpâªL­ÔÇz)Ç´-¦p$·7¡@�æ*î Jã<h¸¾ïó2”+|ÀñXï1ê‰v4~¿¬Ã×o¿ÇŽ®gÐípn­ŽŸ¡žÖÞàÌ|›¯$>GÒ�–Õ˧%oç¯<o_û,ÿsH'Ææ9¶¼þ »Ã*ªÿÐí¢¥‰”#KõÇֱƞ¾WrÞªÖ—EŒÑƒÀ†Í¹sT~cÔíd™Y¬}Ù[Øaveåf@¨mOVUîh«ë®àäÏg|^nǰ®�×áö£Ô¡=Ëy¡Ï‹Ñä@ΜT κþ ÷’–«|븭ýl/,O+—ë*Ž£M‡Ÿr„F º=SÏù>ß[ù¶¼qÀ^5ÅT«áÁïȺ `¾ kÇ~µÊ–É„ŒÂ]ÅŒe4L:oÃ?Ÿ¬¿£×¯i>’^]÷òvÚÏ•b½í|áÓ«]qÞÑ1ìØB$>ˆRrÖÔB<Ë TŠŽgó¥}à%qÿ¨ƒÜoc½¸íÇ:Þ[!ýH¿Æúÿ`?6é™JËQïý£gFsL¬/ ÄŒÑñZ¤7ËáK{uÇñyº@«Lóþ/æt«—wØWõP¿Ÿ†’˜­—¤°r×€Aº=“§¿�(žO4ž˜šåÛ‹ËÙí<ðVµÎoÀ¹`dN-{¥×!À6Ó¹Êñª-Ï´ÈXòw(4ï_׿Œ@×H$ræ˜}fŸ—Û{¦€P_ eŠq51+±×ymL8o{žZšo–ï=ý=¶€o¡£’‰QrPõßät -˜·¯Ži¥ ch!à²û¥çEd6­ô¿‹aÛËW3®öÊQµ7–c×>Äsó<”‡¡¿‹ß5¤«Xb X£ÒŒI~@K¬ÔýôùW#©Ì~ �Øo°Íb«ê_̰¯Ý_<lŒ±bil±ÛÖ1ªràJË13l‹=°+]e W8]ÉD¬r0Ý€º5qÀ}žŸ"À`¥¨*‰0L×:¯ƒ;°mûfÒªÞ�8ÆÑiåÝ)ÅÊ´#ÕîÇ Ð»Ž±éˆ=‹_/pÞ÷H"ÕåSAÍ+ÉÉ^É”ÞJ%ÆêSùLG{×í:|;­ç¯÷RdQ‚ìç&SC›š 3�2¦2¾¤bHÝ®‹+µ@¿Ý_›iæŒL3Lgx¶$–y™9ö+ ‚Õ×H¶°ÿU@Ž-{Þ- Ò¶ÃhóØùlÚykóZµbâû­�Ô<ßΗQ9b°}/rßÇܸô¡=_}+GÖíøê/<@û3äûÃ=—g‘ŽªGÇСØ=>¿ëùóQ›¾Þ`;Äyù/ùw^ŬÊSŽXõ­€»Çòeã×^~iþ&òÎãæaý•Â.”³ãoÆÜÂúvž_¦à`Ë¥Ó�®÷ÉnÙz�Ì3¹³v˘Ël¶×-Ÿ8²óã³KÚŽl}-?ž3¦"p%[ñøòoúIœ·ožq´û^ï dñžë:®Íëórh÷{OŠ} Ÿlì«iÜ;Ÿh:õü¯c¬XaŸþ¹}ùäã=[¬rø³÷õt¾æþº“¯÷_b}0ö»O'–'{jÇ32ðùx>¾w½…Š¡Ôõ¥Ò«ë•§÷^ìëô<#Ë<·í©™Oß¾'þ=È%ä#P3™"0hï/_(½9†šO¬t`šù¼¹tôÈ+Ÿßjú|¶ZΗç}¼.)ÄiO_ùÖ ª\Šr–KW6ü*&ÔGh?mÃt8F�â#ìcŠêôÇч@ƒ–HT@ÆÅñþ’s~½2ÅDR±»T½ºåÈtšêe{3¥ç2ŰâÛã¦�ÓêùèÖ¯Êב:œ¦�²¿³óI,0º?"0vHúpÄc(íx(ÝŸž~9r™³ðõç};mI)þîö¹a9CÌH*þn÷Çð1ƾÎú¯cˆýÏchǹgpy­]X9ü¼ãçL'œ,¶AÇ!†ÒYŒ‰lE%ÆHÉ�ýq? ]ù±üÙŠZÆÔÙ±×Ácðü9d¦!SŒ¤£&ÜjE¸_qÛïî+I¨sòk³ö‰éõtzžnŸž´K¸x¯#q¦çÍtêçeÏV&[Ûq (†Ð2ËcC͘>+½Èøðû8«Vˆ"óˆIر؃\rmý÷*ޱbèiÆáÖ|¿‰›kkÀË#-¬¿‹ÀÑìO/¡Ýl~Q’.ÖG¥¯�V+ÌG3à<óoÀõèh&ØE:v”ƒ‡—ïÛY:rÔýòß7ÎÔZç똞êx²ß3é>db©|9ƒ Ó]ŒÓ›E@Ý—çÇ=ÿ£ =kèÐZûþ{§ œa®½ûÖŠ\•.üàW`ìSü>k'ö#¾fºžÇ˜aJʪj}œž—H#ªè뎴÷›¸¸·ãõsšÃ‡8¯^ wËß3µ,€Å—˜Ž_XÇo~_ÿ®¥Y³ö‹í² *æ[�,ÈÈy>n+MW»ÉVì)v|çÏý{hOþ¾e¶Å£Ü±v*?nJ‰â õÍ$󰤙X“9…€‘gh(8�Ó»=éøÆ–£u˜àWr'±<Ù{8M¶¦¾®ízy�b„ñ¹§ÈÅ·ó²îÌ•Kùµ}É5ÅxªŽ<½Êc²7¢xoÞéþücºì¾ÇúU JpF@Í”¡½ÒtOéûcŸïîø–½Gw&˜*Oý½Ÿ€™ÊÛÍyï†ùÙùN-IGßß}Ü·ý¥Àü¾ä±÷*æa”äÇkË%öàRßqß“}ÈtU;õ€ šùõhÑ“fìÆàŠR<½çôËËÎçå©¥ »’’ªœ]@ËçóQ<3í£}|î#„æ€*hQ#±Àñ¥c4ý æ—*O«Ü€´ã1Ävº~½oýïCî{+™j†æ�-ŒM Ìüîbˆ™Øa÷Xc™6=“ÊÀ••8PS± æVM˜c9ôD°’Rȼ1]¿“Ÿ+Íí¯ùÀ'–›×'Ø{é\‰ƒÉmj�™þ²•Ê™+:IG˜Hy9< Pñ´ºÖý¬^Kǘj/~]%Ì”1.òšöj€eálå5ÚPvþrLÇ·cýpÇÏ÷­rlÿìŽ_Šg¬> Ã�{™9p†Ç'ðyý^ÆÄº 8ew�iyÉ⯉ ëOmûXã@Yê°z•#ù Ï/€5 Ó‡â@–;‚/ԑ€p–~§ÿ`�&‡I7³¼ø!îïÏòýòï)^ö†ëÈýŠÖ‘†b $ü È`±¦ÇQ=Æ‘â«m7&þ¾¦g|ÉÆ— c¬ky9β=<ó?¦RGü~œ–v[–ækÆSî<_%ã­z¼ÄÞ›ØÁ30pœªÕ_uÊgM)(øôpÒGÛ÷ÎUí¥8­|µ.c3Éx¾@e_’ŒªÞó¼ñU<Þ0}:ü8J%‡Äoå|oF;ÄûÙrTtSM†Ø^}ôº8ñÇ£M‡·ýî«KÖ!ž9îÙsT-X}ÉìÁKŠáAÓø<.IDlA[~ÆxC]Îà÷Óæo™E àÈbˆuúéã!¾Gj+~¸U ±GE’g:ÝB]ØZ'Ù¯ÛûÌÚ‡÷›º|°Uß—·4ÿ~[�Ò3ßN­çò¤ú–£zµ@þ½cDéĹý¬�:Ŭ{ù:?Ø­= äùöˆÒphñ=Ê¾Ë ˆÚ{> ‘µÈ̉ÙQ‰Ä•?ÇXbœñT[îI[÷E1½üö% órª|» §ny>î@Ó1ͦ<áõ í‹HÛ뺉}I̽úFÃq2§”„"•0ܰ�V1¹0¦˜e�Öºî§Ï¿n@Ö”Nœû ÃXb|»kûöḭ̈1ÀžþSîà cŠÝ%³`½|À¦Wöv'Š|�¸VJÍr(‡._1kX^¾B{_zH9÷Vüû•¨ Ú™cúq‚ë÷W:§¦8‰#§‚¸=. éd (óÛ!h=ë2ýj)EVú¸_ß¹«]IÏ$óŽÏX?ŸþQ÷‡–öò±|¬ƒüæ0ÇX?ËqÎñç»^I/jÆJ.1ÁÛѾÙz#0ÀÄ’^äŒ(eÇ£„KÍ$Â|9Óè";op]¾BX9d+ÆºŽŸçU�Yå�ß#dx©ë'ÐÉʳö“ ™ˆhõ š 8bÀä%fmùÙóYµrfþý˜�TŒÍÅÒ=©Ãñu½².�Œ):r¿ÏÊÁîË´kùûúîòþoW¢ò,ÎöŒèŠ6à÷KH±’V÷z±ób»ý¢"Óûµ¹Ðåhúª>ü¸vL>‹¬Áãí²b±!‰ÏÛ> ‰ãö\Û…XäOãßíž„+cº¢±~"–Gçëįvõ Ž)]¸Þãµ (†ï?Ù{õR@C¶ÀCÕüÉÞ/”„dLeoôJˆ®®|ÊTL°÷ò{ËßKTÐØw¯ô®PR°™r k+”›Í«;–9B§cœL¶$J ‚ÖkJ"âv¦o4F*æË0×Å÷lÅR@?_¿ŸÜ¡®ŒözËİé°mÀÏÆ{ ­f¾W±¿Ëœª¬Ñì͈«˜a•äà÷ñ¹é0™ðàÔŠéq¢À°}ž:Ê+óy‹±ìV~¼\1]›þsDœ�Ø;OçÁS:ñ“ž±Ší ï¯m<ަž ”ÝÊ¡%ü¢©ûæ['—Î[åãË£8_ûÑý²rÕÌ*oe?s,•Pª…Õu㫞{åT@M,§ÏŸ·Gx¬�[%}X¥¯—`(`l/š¶jÆ¥ŽçÏ¥hg#m¨b{=*eˆ–2Ñ”äáçÿ¹ÿNË?j�ìý4¾˜[F:ñ·£‰9ûõÁëÿRû$¶Ø™ak¥G”XôÎ|ÀeæÕJéçeÌ)•xÚ˜èdŒƒjE¨}€ŽQ%Q„ŽjëˆdLîPˆ±f»Ž¬=ó‰)_¥6ºL¡–)iEÚŽüÔçm])5vŽÅžÄbuFíT@’r@~£çž1<ºP[t½zà¹ðv÷'Þ¡}N˜%£qü$Õ”Ôš¶N}#ðëÉŒØ?ÙÿØûh{>,¾>J’-–%¨|?»€ÏôY5ÈÛCõ“ÑÏÆëxúçPÞWšž’¢œíWþû|–t¡È<�y—Öwö ÇÓ0.�°÷%¾ÿ{]Ó2‡·ßþïïø:~³Ÿi}/!cZà+¦é.€Œ¥“:Ι±é‚gˆÅñFÐÆ–¶íq†÷¼ûõÐ@Øpû#úQéê|š Æëù}_Í|<͵ŸZ0„ÒÓ%,³·ÆyݘaȨB€í$Çõ‚�\È‘¿gØÿj&T¥ÁÛ+–[9È™Fv]–Ÿ’ æ¿OŒyo¯n>µ€…çs½uû)ÃûcSØåq0†ÍÍÖ›_\E{ëú=Ö“íÎObypái¿G³÷Y3–c¼Ã`‘ï™ê¹žæ}úÊzº÷Ï>ß¿PpÃ]¿Úe2s8ì é)`NÛî‚Ûêº0šÝ÷Ž¡{]¹ßëXdJ2±kž÷"ú* nŒš „€(OW9p{=E§½pA‚e‚½'dö=¶@„ÀžÇ”|)?8L—;O¸ƒ>»œ!Vëྼùý=.‘Èkþ~—J|‘íÒ±;ÀòøRtoUz*Æ”*çQàEY{�àsQ~̯ˠÒõUöÝ3/L¥«çùXL0ÕþQ’1\sqPDR°ÚchF9N™`$ÖXË ²-)D ¥ùþ4Æ!öÇ{Ìþ L³.ólpiÄ{“Ü�® ÝcMf˜ÙwÛ¯«-SlnqÀ™QÄãÄ,N4ªŒj߯h½8Ç¡š g–}¨m¬²ñ•®ÿÀ똕ãš×/Ÿ 2‰œeùäé¢u1ú»rì¨ó’üù•Ýõõg…×ã"ê2Uîï²]éD^î»Ø™P]’z²ÕÖüs陉§ÂáΆÑ6–Ø­t(‰¶È7 bf˱>èv`¸.dèdíRמH4»Í�Ð È Ó.ÓΡÿ;C:Èã1·VyüJøP/ ‰ýWÒë÷ù5=~ ©():ÅP@&X>Î> ÉË?ÏW½qÖ;x`lýþ–\Ϭ7aEûqÏß_¿˜Ãm³‹ÿ>î¿c}ÑÑþ ¿ÛòdõCë.ø±¦û­ŠAµ¿` øëû»Ëñã1@hÙÚÈòÃ_ý÷ðR~7÷,2ôÕB•nù[ÀXjj¡ÿ݇'séQ!)dBÅri„7z4Jï1^|ºSQ¥Ü˜ÏÏKÎ^_Øp Ûýòã¼æ¤ciÆWVž_ ¢bíÆ4ž 0%xÔ]£z= „j³65Ó¸š¿Vªï1SzöRi ™bö8[ÈFO€Ë�_–¹ñ2°¶×Þò÷�Õº ÈðÑ÷‡ÏÇ×}~ƒëYº‹‘3îû{ù­…ª¶ß¾BÿÆÚ'ëÞ`Ôû"ôcí1@Þ‹ýÚü›<o5°ÅmëX}ƒë1=öýT1ìv€»é!À[}Çíûõl¶cÜ�°ÛÏÉÆ­ŸÀüìÜ'Ž5�û ®_€ÞÍžåûݳ(\¨8ÂÜú{˜#:÷rß>-PÇË­g™ŽÊ§Ðˆ·ïóf:£ ´(‰Ä®al¯®ˆuéVK~ªôy½µ%g¢)FåGYþü>!@\ 5P7­b€ÑßH(:&Ød~£ ´ÁŽoØ¡ëî ±{…ÿò�Ù6cŒ¯mÍ<31¾ÜvŒ%¡8[»eœ�� �IDATÏû…chÙׯÿq»þClŒA'zµT†föxàI[&%°&ºÓ¡ÎŒWqýÜÇ`ÒvÂŒŽP&õ‚Ò]À!‰‹î><#ÎÖc ûVfXeO}‡wY!™›¼¦£¼#Tû=‹Ã ?áÒFÊÑv¼=˜C<ò¿<p ¥T{’ZK&:—ù ./7³sÕ:ÈçÖ¦kc’ݶSzñç/�ã‡;¥×¼D[V¾ÎÄ–Õ{×Q¯ú¯ È #ìV~Õ/"ãììÚõl€3ÆœµÏ׫;ßKŸ-€ÌÆJ[@ðÎc=§ ±Ìþ<¯üâÑ•Þj¯(5ˆåœ9N Òˆþ;£�O“+†2–C(0;š¿³÷/öÿë}Âr0»€¢°÷õµuê 1F°e¼G kœ/<è~†H­^R¥ä¥Ô”ôXµþ¹6^žsxw¼žE†þÑ‘ž»c•û÷ó"¯Ï%±çïúù‹Öy?2©=›>KFØß÷GOž)Üa<Ùñ¾–˜»È~Ëç7Ó9‡vëŒCØø<[p‡ þИŠ3g”Eù=ÐmËß³)xú*Ï ~=¶Â<ºývßëJ">?Ïðg>¾Nž™”}Å�eóÀ:¶:‚¯Ôp~>nó{cŒ§ósåøÚ·Žþ·1p–Ôƒ—w‘“!6ËŒ0ΔñíÔxVO`à ȠDâ´Ú=ûi.‰yº?»ãýU.^Ž=&RíðWé_áºn»¨ô<öòðè˵ |=@åJÇÉ3†}žöæ‡Wx& z‚÷cYþŸL0Uc<þrÈLºOð~<Õ@äú1èí?G±ÞèãÇ»†ÌÄwxN—ñçu_â[ÀoßEËì ).À°ªÇU\Ç“qÿïwc¨)iƺý@Ë™[±ÝñLÜT†Œ¬Ü`Ô`óò©ú>‹ò|?sÍ·{|^P×]ú¤˜R ÂßQz1ana>Ž¡¦�6sœÆ<#±Åªt0=ZÞŸÌÿ¿±íŒ-¶aÀöf¿Êó–ý>´ýç…riÄ)•HÒs ± ÀeË1zޝå8¹[A\1=^áúW¸~ŸåS+¨ðü1øÒÖwJ¿y§–ðñŠ] 4›¿gx]Ä„¨rœT¶j‚+l};¤"L*fXƒ6Xz£rw¸uó›GQÚí±˜!•ä‘«üü<.¬¥ö”ÃKæ]… cÜe÷µ+I¢V´fŽ´X”\ó€×bÜL€l¾ï?œ#ðüå¸Ï�ŸŠYôcT¦€@Û.ø²viþnï¾wÔO`+2¨l94ü­_3¿ ìÏßÏnߞǘ`#\™Dx¿Øy%)¡Ôäâxÿ0%W{Íöç€â©D©ÉÜ2ICêè|B®hŒæ¥§ý,ž÷.ÿ‹‰åõ[UŸ£† x´Û¸/Ô÷}ÿ=í›îÏís°u7ß\ª7Ö×óv™$+þ~béúÀIϮŶNw 0SRÒ žD¾`ïCfêýÆz{å„ñ•~Íldù©Ñ.@ÒæÇáÑ ³€?¦`‘I4[€Z-´:ÝÇÅ|ÁŽm×Aö‘¹†é®tÖó”-LÐnd(£é·òD†ç^ÿµë˜îõÑ1¿;þæÌÕ~u-~݉Å÷'/¿•NìHé-é6Ïœa){ǹ¯…½›ø;}îM¬°A¶/_ÀØË¨�XŽ}æà¿&OÎÑéûß3à~›ï=0Êæ=Ý…€X1¬û|¹¢™bÊáÈg¸ïpÝ~„#¼ícêþ}äX|Î#C i_Žza'¶Öf;Ï~à*ß‹l\ð1Þï�‘/Ç»x¿V ÌñÉ{újÜv†í¦ÚÁ22™q†ž>>Äs[ ñ}÷Ï9Jzþs–¿IÇ™^/\ÊnÀy0¥€À©ÊŽE ­ºßø{ÕoV =¿\UíR-IÄtv¹ò¾ÞýûÄÓÝ—PTùUÒ³¾=b¾ R1ÄRƘ’R4¶%uH®C@--×4œ¥åøiöô gŠ%@kÕyhœ™6™`‰}k¿±˜b(#±Ä~G$@Vì6P³±ÈøÊý|¢š=æ~%½ž¨³½rt镜—tà Œ™ãËÇÚõ í6¥aPã?“P©ò÷×c0ñå(à@\Ë”ÄÆ¸|?ÛíèC4ª¾—Íóóëb­÷ÖêWµ¨‡ßè쇽öëÂn—ö•ñ å ñEë8h«ûÌÚo—YÖ›xÄØDÃì_ Se:ì_á|øô.0X×U@W^OŸnгßÕycìÃÚ¶|4¡5gÐyæ�c¢ÙúD�/žç½ú;p;ê´¿«ve€œMOÕ§jÏéDS1¶|ºòüX†Ú01½<pì•‘^ÝÛÿpç±zïšØþ<õ¿žqà[&Û?f»Ì°K;…üÊJéñ)7Ó€±gŠêòž¨í»)*àšZdÜÅy}ªX¯Y»gf Ùö°€®_kÆÊHV3¶ $›?Äz®3Ý…1X,¿¯¯’žŒÏW‡1‹í;íd~Çù Zj¾¢ÊǨ±¾Vñ"wh»’ÿüïßãX>*…V¹Iú¥ËƒÉï÷#+,¾ÿù¸w™e^©r¿„”b}¼’ÊúH¾d\M þWØ#ñÃö×0?ý*ç¬|½úw™t>Å4Óå¯L1Poíêý#'ÓÿwÓ·å¬ß—ý7¡—ž7°@s,ýÈ Z€ÏŽa¿òéwÚÅ2•2F¾"à㘓 SÌÇáò™å8µæs˜î@&ÓKIô½C:/cDIÄÉsÇ'0Æ€ÁX®ÅÌDÆiÎôöÖÝ”3éÔ}WÏç£L¡õ{âz1�г½QRtpø@DOz/Z?8ŠÍ롨ŠuL*òQ‹’„ÇÄè»åŠ1ºðú­ÏçõÒ6ïK¤Øäétϯ�*%a8aα½Tì±n¹º 4,×ÌGgîø=†Ø<æ×ç_AR±²?èöOqÞŸá|”µ™jøú÷•”¢[ÑÈ&Lch‰46 ]+,c:lŸ™8¯•‹—n¶‚r¥“缜 §™Eü׸r~]Á&ä¸rìÚc*ðú*c+WqsÀH­r=ï’B »d×…vÁzG)¾AÏ뛿Ï(†­C°¡1ý>t±g±Ýu­vëÑwüV+—ýyœùhñ[{äŽ\%5rd&/çÏ4} ¬°zD‰ÅÌÚ{FL+ˆI°ë&cG]7Ä>3–¿=ž=¶|Ètºô2F_Å×`ý®m§y¿:€”ýý ˆí«Ú?é¨XYKâ³#Ás¾?—?B;q ÏÇÒ;@Ë;Èçy?Ëü‘i½kê½gŽjUÅ4ŒÞй€Lco=˜ç;-XºÀ×QwZd„ò¸ÈïY^Ÿîw^O·ž8ÅŒo0ÀÐpüåG³&VYáv½Âp¹ÆÝ>¶–j=U+#±ó9}÷Ù4wïûí%ÈNd\Åû‡>WÇ'S¾[^Æìuö¹àßí OXÆ‘½Ÿ»ãâ¸>Ú?™ßµ.^K$æ=hÏ}Ŭ \[g)ËÊ·£ô1ë€å’bȬR€Ó*Q5nžŒ°\‚ð«dFW1,oÏ}\òy+ï5Ô¯WãoëHg1ŸÐ?۵ϼ>jhqžÂ€í¸@õÒì×¾ÚY|ºÒmhµ4]ΜP×gˆaºÇzd”Þ_›×)&¢e ¾†WáÛd„¾¹í4d¦ÅöÊž[Ëá 1vØûŽù¥1<mú!ÕÁ‚oƒ?O,ÿgÒŸ Ñ.rEÛ“Dû(ó7ê]@²ýçz2–|{t¥õV9+IÈGgG¿¸ü~kÖQàm|¥{ìúÊj†Z*æ$æ«€Ð^{!Ö€Uþ»ß³ª*FÖÃ^‹ó+Ãt)°Ö(_Unj IÇ1gˆ9`ì btÍ}<^Ú”LüSJ)þv—0üw#½¿Š}k¿™bwàÌ,”pבôæÒãÒ6ŸÊ1‡+U³ó££jÙk±µõ´éñ@ V};й{¦ÀÌ­äfR\h(µ@`dÒõÍJÃØ­0Y�‚3ÇüŒI­ŒÎW„Wíwܸ«¥Ûþ9ë­àG»–®Õ^¹/ÍíG¥;±<g9!äFš‘Æ&Æv¥vUîŠ9ÆÎ_¥ñÒpgz»F½¾f4!Sm•Çׇù»"üþP~´ÚuǺÒ6C Á,½ p©ž¼/™c§úëµdf—)ˆ€•M7JÆ|nçùíùSÏ3¶. :¶Ø{ÿœNè3«ž³\úÛ‰Ü\èäÅ:’dÙ~T©Ö¿(©CÐU ‘ï|ñõ¯ê{– 9z ðªü}Ƶ3ÂècD&|ÂŒ×Òܶ~‘ÑÂ%*3Ëß>>Çßm{eï©ZÀ€ lÏPýy½X'lë뻤Oç8"°2ã ìÎ4ߨoDå ´9Na@ óy”?òç-¦‡�b†e¿îÛ”H|‘ïi¨Ô몕c…_q…vx¼ô@ÿãí¶X?/xu磱úÑçëé,Æ1_ö+ Ø£JwÌçþzg„Írñ÷üz¯ßé#6Æž„2°,ð54ßkvÿ‡sF£­OÇA¥ßþ»â³tÛŸã—;0vT¤ÙÛQæLNô¼C{a,ºþs¹b„YIÒó>pæ#/—ÝGàkŒ1žÍôÌ1דùõùõ¾}“ëÉJ ªrÍÔíûªÚ'2ò8ãmµCŒ¸cú¹î}—ôܯ—œKfÏ¢Ÿxn<y?ðÝÌ©ecŠ3¸bÌ0U•Ÿb”íöG»Œ¯®vÇüªžfŽçÛ¼\”íÆÈë¿XO^ÍPLci -¥˜šŠíeŽW1ʪrTÇàf˜aJ ÒY)™8aŸÝcÇl2Ä~…}»±½nÛ?ZéN ŠÈC†Ø}?J‚0f{øÄޝt½’¨˜oÇbðYl”$Jk % CŒ9ì—c`Jyù O_ð'~â®’·Á€«Úr‡Ãœ8{ nw)Ó3†#Ü>›]å(C¶ÓãwîàÜTjžÁʯŽ_!çy:íW•«Éá’¤ $ð¦uŽSJ”gû^ªd2cƒ§H,‹’‰7À`M¶Ö–s&€á Lÿb*ñó.†¤$Ñ€V?µ?Äûÿƒ;NFÝÿWŒ‚] ¥ œ)ÆßÖ1ÞzÌyœÀb™X6=Î4ÔŒ-•—(/R¢q¿Ýƒ+—BôŒïèŽ=¹•ËZz‡érLØžylCœõrÞý>ê˜`ü‹0ŸÎ£¦€¥X.õtåê2¾>³q]þœ ó¹–J¬Æ³˜ÿ-ýŠIŽóøÄfý72B£íþ"p+ t,ßb‚]}pÁ¾û¬~lœà˃€—fŒâÂ;§(éD^ÿ ô[˜_¿Ý™× öÿ)‹LXÏN}j ç€š@Ø1X¡s~¯¿cŽßÜ3 K`ÁŠyY-@E³Ì @YÀ¨·�™‘×büÅ'(EÇž§üûÍ ”"[@Zw Ìcß»(ý‡Ì°ÞŠú(%8÷w%Ër«(.‘øõë¶‹>~Ì b«éØQW÷^0†S5ÏÌßl} ±x~îƒf2Ã^àú÷ñ¶bOâ>Æ~,w¼Ïhا’L|Ëþl$%wæ•ú»Ôc@)é¸>p”·ÄQ&–{I V’y¿ð(�øÜ~OóöG”–üó ²gÑ>lòò*éÂÊUÕ»bú)€Œo+àI×o–£»`c¯ýº�›xŽ€EÎkP*¶WÅ#åhpä|¸Mf˜)*±øÓб¼~C3Ä�cœöë=ÀªdÜîÀ`iÅl ÌŽ{@$N¬§TÈ<Žé«tµœO°cnì°|Ùñ«8oC+_&Q‚Ì1̧?=å�X”¶Yq/=¡VÄëú³ûº;Tpåî$¢FéÊê=ã+.Õ°«?,æ%;‡ßç}¿ÀQtc–õבTÀà±ü3øÌK®©V‹@r/‡(cŸÃŠÁ¨VF³ôv¥Xºv z�Ç<SÇ2r¬Yfc¢žAÒÎ2xºælàšåêô¯ñ¸Ž¦®Ûc°ÕR‘½ò"³Úo¶Ëþþ©ïYæØº”L¾Ø^¶<gH‡¹ÿs ÅÅ(ó‰«^ßñ> éaw‘| ç£äò¸Ï%Ž.¢~‹ùmìxµJ•×娌9Ø'ø Dò£ D"°¥Ê‰RǤ ƒÕÓ«GDNƒáBgŠ)ÀòÅ…,×pþ€ã˲÷=ï>j¡L„­…ZâöÖ®dÝq8ÖÏnw¥ÁYýì¸Õ¶w&µ6·§°õÌd„Äô¼b„ªO¼•„ûÚ£¿o-\Up…7n0Ó+ý/°_)FøÒîK½rÜwIÄÆÜÔ‡¼ÿ±ŽNÆàc[Åœê{.ݸiJ&’žðuŒñòtÞG{`k2ÃÉv’~—ÿ@IIUŽ%Á˜û| (dˆÅ|ò؃ªŸß5 \ùû­0«ÒSÆgÖï÷-O¯ËÌ‹€Õ£@œf åí´ÌÞßÔÍ­zW»pÉããæÙ÷‡Å&Ë->¾~þÚ~Üχ÷b1Ęeˆ �Æ”TbV”d±±æûÉÆ Ø›õ»ýŽ©X^½ï˱ÇÓ€ceß%FZ1Žºçó÷T;U>þ÷*ö×qãýg»Œ¥ÙÝvð@J}~@9•}„tºù«ô3%ù¸�jU¨åV¼_ êJ’óÃl Èš@Iÿïì|b)`Gb‰Ñóm ±ß`;aî÷¹ÿôË&ƒkÚb„ýæö�[Çó|¤t#aˆýöoV&`Òó*åà+¾´dဠ­—`Y×Åfå@Pç3 ð[lÜÖÖ:Ð*©­ìwæØ°L»"~Ðóµe탒Œ³Ypr›oáèª$‡Ì4«š8äŒ1ˆ<*ÀP¹óñÝr¹¤Zµî/®ûð�î:·Kà¼Ð½]‡ð‘X+ž6ö<vµ®TLvþGr¬ØNY~—À‹³ÖŒ¹„ŽÊÉTCàÆ%XÛ+ _?Ç?S)ÈZZÜŸ€4^ò±ã¸öƒh‘qõ [˨[RƒK:Ó3×–}/Ö~þ»=Ïž’œ¬>ØžÓ`ë>ç�dù:·Å0Çtµ„ª|û³ÏQÅøÚí×4³ªät¤Ð|{ðû–çñû]3ÈöL3¿·˜ÏŸ—òw·M-,|9³ñÇî{ÇÞ¿ì9àÀMï~â ]ÿ8ßaVâ´ŽÔ1oœàøý"ËŘZW1Îd-¦˜å~áZ¬·µ¸`Çþ™t¸bšñç+wD¯_ý“UI*VöÒç¥=:ž€Þ£=£g G7Ï®„(¯ùK(¯vðNc 0ÖCëS¼_€W¾¶_×±˜Bü}¨�¼¼V@ñ,—lDà+rP¥Ü2³J28?9mÜײַÃr:f˜?þR¦7èu‘Á3ÓóÌ.ü½Ë™i/áøcöRö´ñþg÷;"—týnŸO`åßÏX\€h½àÏBÓžÇÆzùS›�2Äž^’Ï'—´ÌS½Ša.˜Ó1®V~ÌV»W3—YŽ êæ<}ý½7c?æW•ޝ÷dT½»€•´ß éG&•??ä{ú]K_°°|¼>`ÅX]] “?Çëû=Œ®xxûàuŠ©¨Þ§Àûü?màj2¬¦! ô/û;abUåpf�«Öùư®ücc4–Ù4+™ølS†Öç_þw#­Ø³_Ãþ-ß?K¦˜ÿó›û(ûüßã÷A˜ccw¥éÍìëÄ)ßZ+ßOà.aâŽ+'ÕJn¾ÒÓOtp“3ªaäj‡5±æ@ J.¡C` èè|¹;Âç·$Rl¹pâ̺±½I8GÉÄñëÁ6b‹UÒQµDÝW1Sö?‡¹ãHz{ëCkÓŸ7ÏØglœmA¯€æßå@Ð)3`ùtgŒè÷X1R}ûg4TÌ£žÄL€øaL±h¸A@ÍJâ ·õ±ÆbŒ©ØJH;/ùhc®Íü<ãm•ÓÚÅ\ïÛÑzë)ùÚÅ3»PZòä÷ágwÝ90û¼£fµ³0g}• Yà<Cξ9°MƒÈ¬³íÕ15nè,LÉÖÎïÚüþd’‰Ëv Ø}›÷y_:w´Î¼Âq•õá’Õª}þé½òu[h¿Ü[_T”D¬b†m˜’$œßŸ%é‡í²»rÜKUŒÊ3ý>ª…m øê1@âÂàYcÓg&-Í3Ò˜túL¿*?Ž£½TâZhäç+qd×a˜³ñ§’dÄúÞ®Gå �öÝ+fS,ÑÚ?Úo,úQ,+íw¸±P"ñ±ëÓÎržl- :†“gLø’Tßß0ŸWÚðzš±Þ¾ zÈŒ¡åí$ö°üÑ‘ÎÞ+ËC�lW ÓåŒ0Ýž¬°ïé1¥lŸ½˜a»±ªÔÒ˜¬`Û=6î×Ïë&CëêöwÓ©< Ø›ÏO™„'îûô"ðkÓgédÖg¼dïÇ'Ôcî#cŒÔ÷_,†k߬^ðÖL™kÚ^5pÜc0¡d[Ÿq“‹¾7ÏÆra,­J1ZèÚezVL4µ�ß~?àUÅ\«Ê—3J?dú½v«¥&Q‚±bbUí§$(‡8޽Ϙ>Ôöºn ¯1†¢þféL im»«+ÍØe¬©úÌë‰t£+·î, ¦€'<î¤�{ @”°?€Ãc¿Jfêl9þm·�ûÚÞËwgå’;Ýgv¡d JžÝ„ÍJ~T„lâŸÍFâ³ÞÙ‡7v{èˆûlâƒÒ3¸—µ/·ñ…Ò”±>{ÒU_–06ž×]©}£fŠ™mÅhÂü8pÚPïF9Ô…QóKÖJßë¾Í†)Ýœx»w…˜òT¢S[NÓþ÷«™ziUÜx{­ýSOí³ãcT޽=ÆÍeTý„Œ, …Çùu<ÝKrôv– '˜"CÉhh?Ót°Bfœ-×íü4ŸÔa¹W¾o_翙㶾8C³ï\cò¬tÔó•?z¿+¹Â®WÏ=2Í+‰Ä¹Ð"ÆÎ¼”,ßÂÊö Ž ÎÉ’ª< (ñO4s¤2»Šów¿_sY3·«ž~�ë/Xi}y0Ï}âý®­bbóûœµKö^.él,'.$Ñ y¸"Ã*µg†]D;pf6+_U_6žÅr¡æ3ó¯î}ºq~ÂZqaNVÎkò;oO_Ÿµ -g$vǹ§âÍ;\)¼Œ·ç9¼»ýH^~?—;¬öÍ·;·,Ó™_—÷‹(¶¤Ñ´D_6`¾½ %‰¥�ïŸ qy@ô% Q‘¥’4Äò{†Øõ¾? Ž!ƒG;öÑ._í<œø|ô¥cs«bÁÔõâÖs¨>j XxX[õä̵ŠQ©˜»ícC”ÜDã´l>¸ú efßçáóy׿‡ëÐ^#òäw¦+¤’>õéÆvžõÃ2nNE:¹Õ±ìz1µT,±N nù{ë·pÁöéÆìZ€Zï;ZnǤñ¢Ta×@â骅ªŽ‹Ýrªç¥’àÔåõå^ŒÊÝûÐmÏ<ž>ßÌÀo5ÂÀÂ}¤SX«Ì¥ß0„ (³Ÿî@Ò_€úƒm'ÖÀ*›@˜–TìK4þ>n�Ùïcܯ¿`»ÌKoÔ’C7cA©s;ˉ'ZGb„ÇÒÑÀUŒE¦ÒÇ y^ßÞ ØYŽó×DÖ#=ê|Ï‘ƒÅÊ¡¦ÓñåɤlÆð+VùŠá´>ÓªK±åP+1YÕ÷V~¼_.Uß)%u¦¿V­Öµè`<Óã(µ¸_’Kë×^dˆüøëöþwæÈšŽ³è ÒŽK;áEà˜­p·×¡eýaåT磄bÞ/q3dªY@çlWÃ_­ïc£)G³îPêÏ3Ô,SÌ3´Vº¶·Àœer^4¼Þîc̵3\‡R’h«¼œñÅÚ­š˜q<“\S¿O[Lì‹ûîfR˳ÌQŽ1:#pï¥_pÒë‡.e?¡®›¥P¹õ¤»û±?©e™bfg¼õ¾³ß%&ò:·¿8c 7á�Ï*·o'gÙ÷€-äÚ.‘ùä ™B±¼Ù÷û'– ÎPb·ýÁ®„ù³Òd‹™áßPÆ4óí:à<'T"©z|Ä� ¶0 0ß~qáŽu¼£Õ̰+=_k(Ì£ÿŒ´P´]`¬ùÙ=UŸï’”ÕŒ^mì~"óEà3€µå87K§t¢ÝŸÌ°g–Í«‘éµJúzo'Ãm/&:è£”Ü Úuå\-Ê€/´kˆá¼êû=ïŸv¤Ÿ6WéUç{ ÐÝt´ùgË®ð\FIIv_ßCºqá@‡q„R¢ ðæþ¨%-ê%?¯0Þ?¥ãuLw9Ðgl°—¯ß5túc„Q€ m_®““"ç±öÏç¹^Š2|u?ÒYè÷]@ð´è¸ÇhuúÚg†©|9@ñ\¼ÿrdq´_ª�¶žääQ ¤–ô@“íÔïÑã•Ôâ¾´¡JïŸ^±+Õ¨®óÏE7Æš0”FDàËH-ºß»€×(�-"¡¸kÿÊö“XhcŒ1~º3¦æVKbŒ±[ë|ÎöìOùËÍórSõd+W;+Ê»RÖ €.?=Ó cf¹ÃV92Ô Î‹H§»_Å ð¼˜Û™Jz±|Fº¿Ús¶#_ÁßgúÚ’ºäí<WÈ]Dù1]w}5ÍR¿a.0µŒUçEãéŸ ‡ã¥¸þ¨]‹ô€ºËôë'� �� �IDAT‰†UäN®ÕÊJ%áY½ïh–A™’³½Ö{ö6¬#nÜçí¹�| ÀgÒNÕ½vyÌô}ŠÒ޶¼(CFÂŒ4SÍh?»tÎDJr2®¼Dd欔b,ÿþ<“ñg( /m€ò C+Ig4Ó#.|Á|"ó1_ÍÆðŠçáqþ^ô˜¶U„®Ç{Û ˜Ë¤(±„ýΣ ªÿÌ)§TŽÝ=GŸV¾çã’Sû;DŒÒ}R¯XoÛß3Å€iÝ…\½öº|áFfì}›ý&*¬ÚG€K1§<ƒÊ8;ãÍü»æ™¤vüÍ"Ž0µg>ÜsŒÕ> hšaæM-\ªv=ê>¿Œu­vàñ~DIEª~£f®ÒtV}ýV[lÿ’Lf„e&u%ùhË×Zh:gZfÆe¥ÌÞQÓcè÷Õ>ÿ§/G8Ð ‹@E%‘¨ 5öºlôÇÕ8ÞáíŸKžîÄcöò C²–"Ìg¾ê9<ÊìÂça£é, -ZGA篴ÈTTåôïµ^¼dbtp¦Ì—ÞïÛáZê=œŸ�jO,V tàÍ­•"µíÃŽÇò{ ðãÞÚÅ2_Ž}÷0z,&2âã>Â÷þ0C Ë‹€ÂÜîIji¼iŠi…¦˜X^âQÛis¿ºÞ›jÅx:δâí¥Wq™eß\>íÙøïû±æfý«×2Ǭ"�J$~‹)ÆÙL_c ÀìoqeY†ØÍãKI(þ!Žÿ6ÆF ±Ê~ÉÆ?¡<ÂVÙ_ã&¨ê¥.âÄ%W˜$îOã’-—0±´ç³Â=Jöºn®}–±Wj͉låXö5Ñ2¦Y</2Ó!aóµ­×Yù¿V–£ÄᾩD F@th‘ë¿+†ÇÓyK¤µOwôVÜŸÅu|ïqË×3ÇK% µ'i¹kÊ=Z½—Ä®ŒÊqÅVì£ãz ox°ûۉ±KÐ^Éy™4#«6lèJçí0u³ýÌ ¤Z>VXÜ”ô#2®ÁõC<?QÑKBj&ZÅÀ˯[Öiû¼( Ó{#×MÃïq¾ûØ’W¹Ð&{ƒ;dzŒOü:ê\+`ÿÚîçùÇ™C;vßã²ÇpÎZd§>ŒYeÓ͘ùƈ4bjÉyñ ±ãÇ1r¦òûÇCSû*§±$¹ì÷GK–GcÇÏä÷žTª^h”N£vDaz<ٟ¸}µKÕß!p†LU �2¦*Sš@Éölœ˜+@ r‡·“|L©¹L£”»—²vŒïx»‚pšé¥˜SŠ×3%¡õ<2ϲŽrëhæúK)d i_±ÂîL1dŽÍü>/ÛãÛ>WsnïëIΣ­! ÀxÞÏc¡4"Z?†ÑÆO¸ÐøØ<GFºg9¥é°zñôø›÷R¤«—ÿ¥YÞª}V¹<3L·W”ƒ†Èlš×{†Ò)\çÏ_Æß. ŠÏåÚ?•ó5~|µïf̰Å#é}Bû`l=7y¹x=Xûs™ï?–ãôÅ‹Àenø¼Æzev©bl2Â^Ìþzˆ~4ú¦T=+ "ÆvÛ•¢Dà§+­§4(òüû ´])Çc�+Z7Ƙºÿ•dfÕ¾‘9‡Ïÿ^!@¬²ê~=´PÄH¦L+³Çÿc‹Ùõ¯¯|±ÿÊ~7ç9›’‹•ô¢©§³C,2ĺ1¼\L±¡b|õMI%Þ¶¿†mUÞ/éÄÒ4SŠt½ŒµJz‰ ÏÎQk'øV‚)35±ôÔã ë[9pq¢ûJ¶ë¼Û›Müsa'LÒ†•˘«=Ñ‘cËS:_›¿zGitôy‡k ¸RŽ.²Nqµ§?/—XŒÝ¬bú züq›÷Ûo•*ìZµÞ$èûF•³r¬æõB ¯Nm_ijóýªÓᎯø>[ÜîÊníèšçù~Ð2sQâÉ_—[Åüɬ·r_§·{~î¸ùQ^—j>_ÆÌUùUÖº2ÇräV¾™Ôá[#˜Þ<+&MÇ2 ù“ï†ð¹U½f§½ s™ÂyÓrIêÇøuy/ÐÿÔ¿Îâ—½ûÙ†î/°¸Œ‘ŽŽöû~ühûs ûq×î4׎Cp.Äè8•±§óÖ^`aÁhøwÀmÌ¢]å?^@¤×_Ãø]·‹Zð7Ëå™+€¬`„ô0n¸ ¬Z¸ÄS`{904™FGÇ·ËQwùÚ¯ú%=Ú­çWL`·ÃnýNÐ/é!}³ÒaÚÑgj pžéÍmçùËžÇ÷§Ûøc†!`§Ò³ÏÛdlYéD+Õ©]Cžµ×ÛȤèx #LG3©ô|†sVÿŸëN?]ÇÂBËŸ¼Gc!д{½jçï–L´±ž<pµß£!ÐãœÈxB©@_õþèï3= 8õ$>ÆŒn-Ìè<w[žÏw~þ'”¹?MKXŽÖõ øšõzÞ‘Îîw ÒÀñÞ©f„©œ} ^äÕÂb¾J’/¯G—Á³ ÌÔ€Ú?cÏíûY=?Ýkß;ÃÓåëI~”שëUyôÒúN=T,´þó…VINû{sß™´ª|ÿ.Λ�—ºžJ"VÌ2UžˆE†˜2Sì106÷0Ær ™aÂï]ÉFV.4¼Ã„¸3ñ¶¯—ñ+m+eZëP\¿ïËiú•Ôb‡ÅÊ‹ùÁ¦l`”Å6ñ\¾\–ÃJÒ'Jº‹›²èÀ·éÛv³+‹µdLêpÛ áœ8ÊZ·`]%åã€Ù”¬òŽL|>.¢Üßí~FG‘r=_Ås_I5Võï®°\½höýЩí3WÞšépÀÜ›u„æ�·?”®ä¬b˜eÏñë8öœW vº£R•u¯ï܇Êp@ÇÑiÓÊÛ¦{Æ z޹dad–Ÿ¶þ^ï ·Z³L¯~ïæÐKV\{ß5rý®åéG†X%…˜—{w¡HWRì*è¸Ðå<ÆŠ†ÀØVLRth"ch¶à0aã5ÎÑ㿼}æþbZªïÆn¿ÉV\ÏñcBUì0Ïܲ÷µšô˜­•TªZ ¢óÉ’ñߣ’D¿U½³…4¬œÖ²…-ñL»wM÷§Uý’Bü.‡víFم̾Ë•ÇëHâ!ãc ïxeÀлìi}íØBÍù{k5c…A¹y•9dÙ‚-+v·D ËWwž´­¤ÚrÄ_é³$Ô|þ‹ùÑ]€åÇ-L)¢c)yßêXX~›§Ó]í4Û'· Ì]iz»¶�0_ýô8óÌîgR‚üøs—$ÚçqX*ÆÝ ûVpܯ¿cªf:!päÓ‡÷i1Â|¹^:óµ „†˜î—ßF|Þ²öÏüO ¨™‰§Ãã [dÆzð–$žÅ¶_¢ÎQm•4aø|l&U3ÂÐŽ.Ìcd}ÈóT:¹D` tÍ|»Ì4núùQL¶*ýz¦–·Gï»QÕ§z/ú1ÂTy*�ª2 X%ùü«8Æ$ÃߣkÀœ2à ƒb}»Nå¿O lèXcGm2Â~s[ü½b¨!à§$À¬!u³3uàá�|]§>lÞ¡ƒÎú ðZqZÇc+å¬CßKœ`L”2¼P“:ÕzÔ—IP¡ŒpŸḭ̈鰰ׇo×óÀtœ`9üŠß(á8¿Ì”$$7>qŒÒ?[k½‘AÖNê®XÁÙ}¹ýöûWösF2§F¹ÿ½L2å°TŸÉSp$Tåë9ž«ZeÀX§õtйg¿Dºþö=ˆíY¯HϤî¸9‘þ–™eªÆùÖÔ§r€Øò_×+Ë�¿ìü  Ý|;ë°øÂê}Zé#£ËžwýœJ/GÇy”PãíçóSoZ® ø6Õì=׿ÞØw@- ðÛï7ûëÒ<¾WÛhU™7UŽ)³Ø|×Ýy@X<ƒ+ø÷¿Ùtr—ËÚe{ë…R¼>y̰ժ¹rÝçÀ”gf±úï�åó{´Æ…1åã‚?Ÿ±Œ6Ÿ_”tÇzªüp‹ æÔBšð†ó/u–H+ìõH5Ó¤Ûö¤e£tcþåÜu󵫨ffåè8Ÿ¿G c ñXCÖÔ<yJ!¶ýb„a¬0[^¥`û تš~»€@–2S"àq*Æ—ÈDñRŠ Séðþú’öãu¿Å ™a/›#‡¾Dbu¼’ìZ\í¦«ê÷"¶¼¿x[k(Áç·þ¾¼„zêy {®øŒ@ùª§ZàaóCæÔó�¶Ë[ܽä=xú:ë �òÏ ð<ãïïòºUþû®P/_ïÊÔBŽDæÌ(ÌÿClëø'ò(PŒ†ÌšY¤˜9Ý™,U¶óëQFÚ<ÿ¨/@—äß®Gp`úí´Ç„¬Ë£öçóp…ý*U¿}Ô´ôã.�†ÖÔk1Äðuð2é¹ò$L³1†Ä>=³*X·ßá’‰£ËÌÚ7Œ¦b™)€l™%†1Ä"ÃIÇóÖ• ºY=ŒëK q)F¬Gdt1Yd°aytÌ𣴗t‰A¹ßľÍÇ:öØ@¥ãè˘y¸â7Þ·ý=s ¨‰ãr©vŽÏYò\"L9È>5ó(<Q×#$1þ~Ù ÷þlUîéý>1)[.”ŠYí ¤¢*fT~^lŸü裂_Ùû¥¤y {1wtûä\ÈøA�D1U¢ƒ·'iT9„ªi¼rVï;ŸGËìyÙ{›1à²zxàkµ÷ùÓ=Éû™`ë:õ<Äü}úk ÿ®íJ¶Æïß×½Žú-¨à’Ø>j»1»Ç¿×tî—Öñ¸ â±ïCÕ ƒðZöÌ-Æ6~ï7aÝúÆ…Z¤c í ôøú‹¼|‘ÉÉ™K¶t™ƒø<ô{9·|a‚^¸Æ®¶ßë-\ˆŒS è³ó+Ç k'\ •jfŸ?d ÆŽYk¼›–ÏÚz~ŽG³³™'.eàã ]~]ÃÛYóÛï0ÿ=Þ‹9-sÀÞ�ŸÉ8‰3&x²…ŠlÔÛc<ý6äÏÓ×yŒé’3T}»_É#½^µßjŸÏÕ9Ê1w¸Þ2zƈL8Õ®ÑòqXu}%Õø¾ù¾b}´§Šá¥�Ÿ]c_„`WÕ™FpS=ŠŠ·ÍÚv�%<#3ìmDÞºþäžë @Z‰3ß÷â=U±Æàe®ÿd�²—’ÔåC†]GòQÅŒŒü½g1Vß±¥Îû 0Å{wÛý÷.æ~Wc¤²|ƾ�£JÃDí«t»÷Å·C=ŽPåÌ¿q*®ß«g DªûÈË«ÎÓ̽Þóœ¹ÕµÞó¨ŸÅܪ€²ïÒ0]÷;2Å6b’¥ù£¤"æk�±§œ¶Žw/zÞa Å_óëWq~Å›åÐÝ}eŸX:ÝKNGó’4ö¸L «Z)©k妮°Þ`Ù|lóÖö,¯ÉvÅDòõé—FD.ÆËÃG¤Ê®à˜`Ÿ‘\ %”ÛW@Yr½šà£CÏïG§ç]‡ŸŠ©öOI)b½‘ Ÿ#d¬ä±uö[&gžô®Î÷0I1ú÷ZI_!pÝ•4«JÂ%j§1 œÛö>¾&×Ûã^²6ÆDÁþ|Œ!¦ã<ýY_~¾]ß /õŤomÿ_õƒ¸àâtÿ..‰5ïHÃþ"Lc¬l—.s±’"2þÜòrwøÞ’T†¸.–²ëˆ¬z�^t”Ç邊Åù˜]ŠT|¾"–¦9ú]�ýpõW1I+&#+aÃLðÊx¿Q- 8’—`D¥dZÅ8—Ǿåjüx»Úç{ ãA.ш±µØ¸¢Œa¡kÀ2G³2Ë�Ãô2 Ê ÀÃúç 9rF¢-UÌØÍáNŽ@ï{Ìü÷Ý'¹Ãæÿí»ebÿ1I»íÆÌ2¿bÌ ÿ\ði3â>/w†ë^>ýý¼—ëSK¡â{åûXÙóØx+c”a{¼Ç»—®‹Ç¿êGž�”¶Ëß{5n«¬éçaOßX×R¦¾?x¿?¸Úgª €ÃPÝtQJò¨1fæ<Þû^iFbVîª0%™écð)&åÜ6)¼Ž[ì0Æ ²×O¦y¿Ÿ4s.ö<oÉö=´ÛZ»í9ûIõžñCE&®ÖºùË!ëЮÌcL3/!ˆ×!ƒ@C—„ŒƒãØTåP̽šA†íÇG`54 Ê|ÜgNõÚE‚eù<ð¶�Î^y*ëɇ˜„X2’•e€ÑãÈÐRÒ…‰D¢’VTåíJ<Ž12ÉÄ_Äþ_°­b~ ~Þ60ö'äcˆÍýßèycŒñ{#ŸzE<—F©®Œ©A¯#_yµbð•XàÁl +ýpå²uH C;“TÌ4Û•tJ%Eã¯H¯ƒ»Ïà{¥Û¸‚ùVÿ(©È ¬}Õ}àŽáí¿Ú!_9´51­$ £L­\ï­ˆíÄسJB/_îóýw¿Åö{´ÔPÀŠÏ÷jnª†½v9ç³]Þ Û¿9 1¥èÜ5ì—ÝrJFàýÂ~÷œ: ,àÄ$rÕŠZÅÀ´ÏI.A¯ãŽ^þè?»öRŒY|n‘±†À¿Àj)NÎdVûÊt~x¿ìqÍLU¥ÍG©ßü|]Û^Qk®â¹×Ãn”7xÕýöçU{tÏ­ŽhR-(ÁóZÀ¦ZàÒ°#Ì—?Þg5ÎQÖq¯t}ÿ¤F¿Ó&�m¿;|áźÂ;¶ëXZ•”Z·¤œqu–í« ¿žù{)Ç«ì¾0&Xöœè~ÁÓ,~G¾ÓŽ*è˜Rg÷{¢ççùòuë½ÎïrÊwM-”¨ßO/q†ŽnÏDx1v/ÿŒÁuuÏa\ÃËqï9'ãëÓßß¿$-0¤ú3´jÞ‹µAéÇ*ý1<h2»¼c~µÛlÇɬ±ûLóÏûcK2S¾`í§%G‘ñÔ{n+éÁ®Cý»b�FfÙ£KA}ù¢”ä1 {N=WÈ”T¶÷œÏåéþ|"\åƒ 1+…ø|ßïõ”Jt̰¹Œ°OÍ4äÇ×s¼€V[Ï•»6Ön‘qtÌT¾úyÍŸß¾œ‚¬_èY»ö!€þõ®C`«ú¾^á¼Çq–ߟøœä@gŒ80…ÀPmØ>ßn¿¨.Õ^þ9®�¼ª>}ÉͽúÕ1ÝÔó\µÛi Êc¤�Óß°}|9À .ÂÔjZó:Rn,‡K·bši@,_7û¶Ë#ëÍã»vKçÏ;“̧ûkXìå™AÓ*@ÀŸWI‰tF¸rr:<í„·„­ô¹T® F‰.–^î¨!^¾³�9ˆ;š7{¼Zñš1Ú®ÁA²¬°) y{ýšH]„÷ pЖP+È�C‡¹®ñ²¶;±¯í˜Øß”¤"gy½ŽZ—ñ³ÎWù?Sd÷|ͯñÇ÷È8PT3;¦¶*¬]©Î@¼¿ó1j÷þcÌ—Î;K -[¸ùÔýMîÐG)±8¼‹’µÜcðDë­Ø?ʨT¹t¤Jß’R]’_²èþT3‘íñ*½G׉êö=‹ß/éõ@;f5ù»`¡bºë`zióýjõ^G@ûó}YÌhIÀŒ F[Ξïÿ.D)í×"å c ™î®$¿[ ¡”!ªt3®–LÌ¥í÷"“ì­,ޝ|OÕe^Oë;ؾö"iØúø3Q’¯ßŽõ­»`q:|Q*l¸ßOâ9>QàȶŸ}þìóéÒ33Ô%¢³ÀÍÞCÖ¿Ùö°Œ=d˜dóv%a¶˜3'˜‡_¡Ü @³õÈÎü~ŸÃûË];òïG­}Àêö¸”¡?þ83Ì×C¹ýJ*ÆY·§´Ò ¬¼ŒqdZ‹a¦{ª½ïáŒ<л—Î’HTL·õ¤øß_Â{ýÒˆy½®´¼³(QÊnÊØû£bUL%Õ©%J÷FúϰÝ5l×ï78x.„ï ÂGGÛåø·OÝOT�N›“Ýü}/æ–J¯bÌ=.m¸D•ç=—çW±ì*Ãô@”0²»Ž¤£^»RŒTÒc°¥†€[¤1²b¿ŒÜ"Ã+šž~ñ±Æž Ù)ÅÜþéÄÅû­FÎ ˆ®.ÿ!]T”*I5Í“ô•4á,×›H7«ßÚV6¿,‹¹¦Ì:Vðz6±±ŽhVn›î…8И”›=^ÅnaSŠŒ�ݬǮy‡‚gäEf…²-Wš’P$ÇÏcrÔõ˜ÝõÇ%ýó±�Ô³8ÿÃdß ©zêéß4 qHEF^û#<Ü©J©J²ÊÙë×êúçYŸèJ%qGd|ÎëØ‚¹„ –·*'Ö_—¿³‚X3ïªöSvìýcg3 µÝˆ(ön¾Šã»åâ9T) 3÷fÔ®ã|Áˀ뾻?®ÛçQ€roáÀñéYÈuåúŒBµE1¹·¾ÇȈÏêd<©Úª ‘÷3é¡ ¤Ï¾v\š»êÏã«À”zRá8^äfóSÌ”Š±åçkAE%•Èï×…¦¯«b.Gë**ìX|®cfDö~Wý^¸Ã¬vWå+öW½.UÈ¿Xñ9Ó�-J†ùöã±q¬y€'2Ãì6�ñسšvþþöu¼Ò@½ç¾\ë~M†ÖmoG /gÖFGè«Û÷ :e}�¦7Ÿ 239—t;Þu0FžÉÞHæ8ðÅma;*½ˆåŽ ºþûŸ»ì¼  E©M^³|+&Ù.ÓÚ–—IÆy&ØêÙÉ{ƒR‰n% ;À9v2Àíc`½=“åîCåð)Ž×Ò¢«¾Y~}æÐÍÖÝxOׯ"ͺÙq€A1y?¥Û¥+…×Ñ‹éèØRS*°Ë0WÒ‘'ñ{·?âí¹Ë€¬³J ô1 p—ñ™lÝüŽ~qhÚºî@:oŸ¦�³.£Œrª¼? lÚ_Å~ß~#^snŸ*�®kK"qa“9¦, Öcޤi¸ò¿rú i¶ÒržŸO@â[I—TšÐj€âfjF؉à0F¡¯£^¯™ÅSåÎS|l"¿®÷õ¶’¼<Ý•êî~U޶$–Ø´ ”©ûqÌ! ì¸� ¶°~Ñ¡¦b}¡[8üá÷#JŸbýÕ¾²]†UïW¶‚ÅS›¤ß­å:¿–ìãï³îYŽ2ºÒ¹ü¼³�–ª–è–ë(S«‚PW½¾»ÜY.jáDUúNúj!Fn»O8J÷rìN£àÙ1²CwE&ï^>ß#X”Õ£µ¯˜× #[[.Šõí·ºN5®äL à3¦]创߇9¾›û{ã.-}hË7ËÃb4æý<†ºï)KGÅôB‰66n=nŒÞ8²çEFß~}¼ññì£ï'JjÕQó–ÿêuÞTW]Ó«£©~C1ÂöÆõcðù^dL`ýòv(ÝuD\V½'¯#J'f±”Cä–ÿlÍ´±†0{‡ô5p‚Œ²¸½ÁïcäL›]eLC&t,ÖË·Óû·;�÷b!ÕÀ@e{Žê£ö"ëÅÛ)‹©†ŒBÿ~ð|^¾ž·ùž`{Ùç¶#Éù>"àÖÈìïÏßÛw¸>¾Q°û|OŽóë®áø£þ ¬Ï Ó@zgú.·]N1g¬ô¥§½|ýå1ÄúVIrÛg )©ÁÝtðx·«€-Õ.y¿¤b¤éôðº«øÝç«Óã1½>ÊqPתûT‚G™yù÷§»õ~÷O[#Œ0©ÔùÃù)3Œœ—¦›ä¿%嘔cŒábO=æÔ¶j�«%UøôËíø70Äv`³<ÕÄbš—A;¸ò^Ålæ8[÷”Çl8‡ô<“h¦siP=îÙÅ|8‰zÌrØvÈ.«ýâõ(é‚3î�ö1¾˜[*þT="#"—œŒ÷£k �U+m kšI–N\Ul’ÄA·ËÚ…:f}¸íd¹ƒâ"Î[Ç1Y^»º½ŽY-Ý¥˜(i‡×ãußHôÒ9(ØÚÕð Jaj†Ê~}z ]i"ýž¼‰t VµHï|ŸÿeãüN{tá¡Qœ§Ò; ïî²Çß÷cýâUe¼<]`ì¸y kÕ /Îd½„~ø±þ¨šnÔß™.ã-eX«…)-ããKÕŸÏzrÉ«]Ó’×õøm äh¦ëߨûË1µ€Lõ£g Íúæ+깤bçŸv”ñöV@ÆÀÕ߯³õµŠVÑ`¸m>κ»w€ÏôW8~uÛ]ë38zLÑ} HÞ"*VØÎï»mb`߇kr_ÕsÏÚ™SÌ04uÿéBÁ§³Oÿ«‡}ÿb„U1{X ±LRRWÂAfJ¦!�gÓµ�(¢Ô"s”3É·ÜüLœOÚïè‘~,2·nÖ†ö^l»Ü÷É\<Îàš†À‘ª__Úo÷$Ðj /Jx"3sóë¼íOéøæó¥úNåsÆÆ Ï_-õ1^ Ï»=î$ß�öÄ�r^.%mêÛ+|òúž žKRvˆËž_þ=«ñ¹hè;”¬ŒñrOæÓG»^#uw??þ,G@ÕqÜG† HºÌ%l7´cÒ“â¼gY¯½Û³ÜßíóvÖù¨|yz5Ç÷qÏD"©U±´fbrQûü?!ver‘Øa]¦M¯ ÜiGgZ2±²¿`»i„}0Æ¸É û�¹?pÖŸ:䌡¸M1¹f®jBÈ'âq›1æ´3ã�� �IDATÄÓ\Pã×ÄÕ3ÄNf"ŒÌ&åèè´cÖ-(°-'NÀmŒ± �ã�žngÅØz%çí×k™/GÎ `Ž?ðQë:æ6$œ*¶ ÆÌ¸ÇÖÍö-:øý/päVLºG¹»Æ&®·ãó½U€©¯÷©„T;íþîæ»¿ºü¥]ÆO'ÿ#Œ¶.SãyÖO*�«èT̈^ý{¦ÜpÝXu—fzÙþÎk%ƒ+ÉVÎÜ®”ç÷—U½rÉÖ”å  Ö•Žë¿’ êŠö€õ ßµp«~;•5~Õo’G¡cý:ÎÅø*ö¯È(¶c½Øml|’ä= Œ?ï«Ý•ÔlmoÅq>.Äz×ý9Žg™‚….W>®Û_�ØmdD}·U1¢ƒî3»?^õ-û)>2Þé×Q Ä*Sœè/ìqëÀçR:†v5ouÇ?ãÂE6¯»ßǧsáàÖõbóç£/Þ—#éOGúû½Ý®øšùXà‚aJº-S^Ñ1mZÛË¡vðãþ*Vìªï©?~”qö"¶ª>€Ä€`^ÅìÚ}®ýùàcÌÑažwž´×1ÆÇ#ìã«fϲÆ/²ŸQ*ñ“äÃí«v‹õî�òÓÐa®ƒ<&YôF ú1†Õ³Ì1'S,c4òúOëÅì3¶³i×óãÈÒ€ˆªG!„éD L1»H«Ê¥ê×5”íxÓ¢Dæw3u{L³Š1X·S^®æy`D2ÐÅ›1ÀT .¼ÎØ–4â.mD` ëC7ça:.?ÂC`L�eŠ!Ö´ ð5%1¦Øc�Ù’HôÀןá÷Ú2­òivbÏ-ñ¾]§!« J¢D‡Œó½¥ï96ÑÏ6–!¦˜JœAÕúm¥XlðoŸ^”Øñ+`ÑÑ{þr¤\¤cÃJñàïЃ÷ëÃR`÷9k,§rä­ô½cä:ªXH[¦ù‰Ã¯c¥ë¢V+Þ½}0¦ÊsŽ\_«‹tP~¯Ô"Zµ2¯ÔsÙ“üÙ—dì=—Íëw˜ÊMZ=Õõuä6u™LñüØÿô®çpî�‹,}PeðM§|Ýû¹Û{ìçØçöŽût®‰#ÝšrDu™OÇ%É`:UŒ[ü|¸ÿ;öÝÚ_ÇÉï«–lÕ§’BÜ`†í2# Q1Fów–O«ïB\(†Òˆ±7{ü­ä€_¼¯–¹6cÃÚ÷coá.Œº¤Ç;Ì $òv·’”JjûÔÂ=Ÿ®’^×ã„þûÍò{|¼öØÈ/ºí.nÏë~xé³mÀñ«Ü?üiE+úZ¬y2¥ú¦˜Å†òRQºµ›5º€®/€L:V=pöžø#7€Ò3¹r† :Úµ£|1Aq†éÝêéŸæ–Æ…–¾¿àþ„þB9n €n«-¯Ç¾}¿hò­\WWŸïbœÅûVl”äf‡ÉbðÕý9zú9÷Àø²[¿à0-éÈË?%§ƒxJ >`ìõ+g_ž÷Ìς҈O0BÀ ®L r”û>}d8!Ó‰9üY½ª÷-{˜Ùö¶ûk«rä̰‘ÍûEŸ¯gÐ`Œµ} %ưñL<s¶œ°«˜i¼Üíós¦SL·gÏP¿})@~?_ò¹$9c°û(‰G löê[K7V€ãñýÍXr€2ªF�kY{Ì¥kÊA%“rªã´Ü?ÿ†#ÿÒ‰ (›ÀÕ/° ™YJZñ·1tl±(ûó¾õåþõkþÞyŒ:÷Q2q­œU@UxÌtUyzÌ«%mâ'< ˆS+eì1H÷Å9l9r©‰UŽ7Øâq»/®\Eà'nËb.ӑ‚±3Ç˲ø‹ÍÇ2éØÀ0[¿²³‚8>—»Œ…C€J=!Pöy‘ƒ‹=?i×=G󣟇n>šasçéüõÿ,“¬b„ÅózŒvçtŸÃïb¢]Zgï2º2A´·$Aµ×òV¼!,WfʱœµJ“©zf½ˆuduÛ_å÷}vôøó p çÝì$[ WÃïï÷T» à•3eã}Û½s]à§[ì¯ÎâxõÐö¨Üª¸p䫤OñùÒ’„]óãÀÕ¸`ëQ³é°þÄŽ‹°b÷­bðÛq#[ˆ•׋3ÛìB(%™¸ÓÌ]Â¥›pa„bÞÅ~ɶG”DŒ×Íq®ßâB%¬dëŠ; 9tl¬Ýà]»•û¥ä*÷¤‚uÿ´ÇÙ=‰–Üs7­ò^¶~ï<?Ó–£\9è‘ÁÂc^EéFî@Θ›Î¾zÜÂË(ŸËw–×Î[™U�»eŽ072O÷Dëƒ} ¨ðéÆ˜¾^~±”D¡ßÚzñëc»øôŽ„r÷|Ǿ7Úª&Љça½°~ýúêJŠîº¦yà,>ßì¼çÁßSÓ7È9ئ4â¼FJñD¯Wï+‹±–÷x­zÚãCîóþ²¼ö˜a5Ã¥ mMFØ1elŸyÜÜiëNó8@˜ë3§zý×óæq;Œç¯ÓéµÃGùœv¥+“Yo.øî Ö{ÞŸnû(fŸoŸËúªçB•£Ç<;n()H™Y“Ù•H/¦1Ä’ó)ƒË”óU’‹î89Ÿî/†Ø«¤¿~G�lZu¼¶ „9†˜aŒ¹ò%À%öçý¿[:ë±{Ì•Ä^{ï(ˆÚý¯b«bø|â„„9ÔŠ`;!º•Ó\ÌøÀÅOtÕ„_OrfÃl¿,$!k§•N”²Ò6çáÛ'Æxý×ÄëÅÊu‚ãØC‰žï´jxs}Ø<ƈŽ>\Ÿ�dj¿Çë×ÓokÛt<B9„/Á´K8ò½V¨µ4 :ºvË©€Í>7*Kï»Z­¶Ž=%þ÷·ä¼.`Õmµîï»±¶vÛ;:´{ù¬ãßý^¨÷ ªq~´Ã‘çÊÿ3¶ËÈC‹nãt{ܺ ÿ˜ÿIï×”.è ß»t»›ß½œW1$×u “[;ž3ÇmWVŽ.ÃS3Êá LYc ¯ìñÌX~¶~¹”aÿùWrcô¤ìx{ù…b°i·:Î/Òay»~(Ê*ǪZ Í­’dZîÔïY‚Ñw›ûO„x½úß äÃvÇá½aJêI1Obè�Î|Ôõ´1ÂìþÜ2¦˜½ïÙ<Û;ÎC¯á8J½a½³v˜ÆÜÉ,ÆÓ&NËzjÄw†~ÀÍ…ž=ØP53ì±÷¶v´N¦“ï7Ôû¯Ó¹ºtb¬°Ç�ºµï%-C¬ó]ׂu±\¨öû �C¦˜*—øÔ҉ȀTé¾Å{¾ï¿Àù‹!övÏéþ»‹63ì3cvÍò) Iû^>´züs Øv²åÀ½÷­ïçoоÞÃyï«£E¨º†’U:ùûÞ2v%5¨¬ê‡°žœqÕ×"Áã\ªñyp HOÿ£ø½b¬}´ûép¼dŸŠãÜžËöª~ÿ{g2»†×®¥€Ö4#éèŒÄ$›†ç§@]#†Ø<þÄ&¤~)+Àm¦?/·?�àšÌ±¹%À½n( ìÚ8rÌÐ±Ž³ s”žÑ‚]Ë'˜xÞ™N@¬1)”n™ÀO‚.î<dl¡iI˜õ;NàýľŠa²þË%)u;Ìë«›-/:Nb‚ÑqÌd¦†—£ L9S1ÅÔÊø§3w0àLOÜX=â XßßCË7™(1¦*|¿’ðS­òݦÚI9öôg7Üb¾]i×ÁÞ…„z©mù£€CVú׿yY>gqÅ÷²B-æÛ{s´Ãš¿‘×M�_ £ÿiÀ+ÖÞ÷O±wÂßýuÿ¤­½û[†j_9ð4£5}c6¤ éùßlÖW1{0æK,y%Ù3 %œ=cÿâÆU¨ ¤Á™"B¶?c½FÆk½4À.@;I€Z[ÞNsürYæÜ5Àºã¹Ì·�ƒ³WG‹ÒˆYy"€¨Ê{NÇëvŒZ°vÄ&01±ëƒÌŒ¾„Tµ†ß÷Ú¾Û"§d¯c5£Ÿ?'9°ÍbUÝŽsغ~}oÏõ Žöc̽AÅi߯ïOþyEÆÔ»JoÌçy•Ë–ûô忚ç±Ûϲùâd’h&—j›×Y�Á2Îf~1ÝØŸú÷¾Š%Vדµ÷j÷])­•^~¼ÔÀRç)ãÜ÷â÷£†é®û]—›!LºÔ??(ÅyuÌCkyL-ܽãÎ>Œé˜åƒ‰ÝTŒ°œA‰û*†_·•åw‹ydåWŒÌu_{Lk%‘Øow—ïû¦t"Ú’’äíø(£æcô�lŸºèI<+É>•îÑXgÏås§Îë¾9`Ï;¥×éúT@®bpñô4à¤ÊY¨`Ô@Þ€rr¦œ~>qÿ_b;MI î2¾v¥UyÆ‹á•0źåH˵�±ÿwn¿€¯ÿF ¬�Ʀ!CLcÑþû-@ëi7ÝClM°üþ²½ K”Rˆ@G¾âDM´y©j ´(¡bËe8?áÖ�O¶"Ôæoži§ûñÕ>Œ¡ÙüØç#“Ò°@œ7/ùc'ø7GŒr$ ššnx˜ô†Ž3ob;Íý0¬òk9v0¶kŸ²bÕ—ƒK’u×]|¿#z˜™Žç¼½ãÌŸé~¯í®—‰ûÊ!Y9–øõZê¬+Ö÷]1íþ§!Kî[몼5#㟊ýÔ(w9qÞúŒCÕâs–;Úw×·ýS¦axl­þ¨Ç`ÕG޽ÝiP,^åw£bD »ß´ˆ Æû6>³ûlÁG6^Ü1>>½8àmåçÍã8®ULˆÉÈg±ÃÖõ˜>pžÙ°ÆU±Ü|åz¨ò@ÆfµŒ(UßœQçë}ý<ÞïÓ@ÀQ—ö'¾_¸@.w¢ÔšÏÏ{Ìb¿ðXªº_÷_»L¸Þ—"ö{×ô÷ÚÔ÷M½Ç«Ø{ÃVsß¿·ÑQõJ÷½I"N¦WjSqJ%~â}­õ '¸okžy½oç犯±åÐ '´L#…§1xyô|{Öïf¾_ÅüXú¶~ä­zïH(lWúûã‰Ó<s+îÇ–ÌËÏ·ì÷Îw$c(Mæ×,wàÁö‹éñôUŒ±÷q �Xåwbù} ϳ±Âræ¶KÆ óýaø¾Ÿlz�ùwáY8æ­£½÷åÏå{ñ{÷ù]@Œz’_ÌßÅ;&”¨Ë©™>àWT= ¨b*áþFø}W€Þº®’ôçëü}¾Êb¬¬]€¬þžñtyýk©ÂÊòû­�-}}•ÿLWÕ¯|Fhêü¿ÅMe-`¬!©ˆù¨òPFØ´.ó«kQ2qa ëahŒÕ¶•¾’J,c‹Mûö¯åƒ©-ê`¸r¶çà«Vd¡ÔÒ2ï8ˆÝ˜ª:1ÎòÆË8Òl@Ã&òÙD"cL±•Ích Jiã3‡PåîÖÌ‹pTÄrŽÛ?®ß—>â+¯QU1Öó“1úbË8ëJH=E gWÔ­ZYŸ3Ž ðì[-‡Œ3ÅÐà1|jÇõ÷ZlŸ®#É;~+†_d¦áý{Œ¡²�íF¹ª€ Ëf:UÏT­pß w­Šy„û{1¦ôp¶—ï5¤·#ì±iä?gðÂó8¦®ï?Ÿ¹U ôtihm½'‰´ï€ßwMôì;õ¬§‰—-G¥²8Rùó…[v|`Ç àæw,ï9WŽ{_ÿ9>²Œ{ÏlëQ*ýx|Þ?ÿÞXf‹rÄe÷e݇3m\°–=¹RÁÌG¥£Ê—3»ï÷|:†ë¦Ã¤6ß/¼·¿S<}ID>â¼B½ÿy;ö]\kËß3ϱûø<z¦!Ì;I,°a÷T"žß5&96ƒuWNw†˜ pMûSȶcðxÇ<JþñòƒƒŸÖïfœyÌB)<p£ã=“îë¥3÷{37À}W ±šiÓ³—d™ù?°> ¸Òõô÷ÅÆÌª®…tìóº˜^z±–ÎäýÈÇðýÁŠõþµF™aS ñ³¸ßNJ%I9�|u�äþó䦶žs¿Ó>±\7{‘#ì= ¸iZª¯â\O Œe]‹ ÁÝX]h�óÏÄ*U�šºæï•ôßµ8Ÿn˜o-i¨Æe#î1›n7Ìo/6X´ïöv%'{Àn PVæ�%dudÎIE•þŽ@=ÄK™fhS‚qÚOå” Ü´\©ôþ`¿“cóø®Mvþ�uV"v&¶q?–† °|yŒ°i8>‹ã482›µÇXE&í¢èé`†¨¸‚9JùðzžËÿÛ`ë’c-àæËÁ…óøj·³tlðv.»åÔÍ Þ‰<¹rV1YÒöìåϸJZi—àþ](Ïzk=P¶žC”6ûg°®éç_S5l_érI—´CÖÏäV1‚r VK³‹ã»ÀPU~ÍÊm—ñ¨ò¯®«�knëùÈ%òÐÁ±¹âwc×Áù?cõÝ@Æé…^¿©ññ’õ ïg|ß«÷º*—«yµ £ €%L2U^õ=­Ïý1 ØaéÛó3E‚¬~j¼ˆg3Ç,Ž—j>ƲºY6-g±²X;ù…Lqáš=cë ºér<ËÓ› Ìpü®˜y¼ý:�+¦g[†\föŸ×Ð3“êQQµÃ’ÏÓþ¹…R>fØ’â;jü»ZÇž‹=š’Ì%þpÿ$ç›¶fˆŠö=òûç%-?K?[pz‚3ÿAVþš ¹›˜ð’sï&Ý7s<“ÖóJ%z¡¦Ÿ‡êvc-ß³à=‰-¶ï å«òš±u…ížÅò(&V”êËž×éÚóøù'q>2¤ô{ƒÌ3›Î˘ҋS’«C¾çRˆ…DÞSd°"#Lù·ø÷GÅtcÀw.©zýbº-¦ . 8b1¶?^y6T{ÖR„*†Øû×–ïw-ÆCi?U¿£ãŠÿÙ¥µTâ®uošq·Wž}æÖwÕý= $=jÝr©ëãp·}0F2¶º ,¼p+VÙ(�4ÂsåN�7¬ç#Äþ[ý€L±û ¶µý[4„ ¤uíjþ.­ðqß÷ç}a*†3ÆäÉVv¢¤ ðhG#ðÚXoÉyö8JZKæk‡°_9­Vûú¯r/Éœ™>[!¬%t¢cÕ3£.á,\ ­€¨¬½m¹l;YÉ"KÍ:|+É$Þ~|aÂÊ'ØWé08ä(EG$:•£’8.+€!wìt¥ºÔqIÞSü × wýEž?à|•>w¨ÿÓV9Ú"£gˆ-g@ªób{ù¡D¾V¾±'Vô�à¾ô*¾®% V[ÈÌâL­S @Îó|9®EºÊþ§¡]‹ï¯­¥=ÏŸ¿€ð ˜Ÿéï1ýjα7¿;jÒ@w¸®kç14óKŸTç¡%€2‡8ЇýˆýÎ0æD×ìø«Ã` vð:%©è÷GHÇîã¸I•k¥WC¸~Ü·Ú˶'W±²8S?Jˆum‡!–Có¿˜ÖãCÕÿÆ(h äÚîóºRf‰Çbèø^èc O¾ßÂS˜@ËQ`1Ʋë.¸é3‚2Ǻe~1‡2ëß|ù‹\_±ÁÞ?/hz!Ñ‹»Às€³…¾œú!`…†íâÓ÷éf±Îð<Ìç¯VòÔÆ$_¿¯}þýà¦$ú4ÐTIôUÖëªa]€c”!éÃL×טbyb?Á�%¼ÿývœçûXeØNYÌ­ioC»“I5Ï£ïWc1§ž¿JôñUÂÏi|òL:O_¿N¦Øgæ®éû¸ž\1gm½ü¾Žu *ÞÎ]C�ì}ó9=ʼz‡©cÚu-Õ¤DÏä¹ôÆ=l�Üx,v¢6^^u¿ž‹ýx¼'½XY  U�蘳üÕRë*ÝÜžC{íÆXÃý½vÐíŒÌª±ßÉ~—åÎCÀ cJ Ñ�g˜^•o•~Zš!¶Š¸K¬²:æ]¿1ÆÓ/÷-w×·¥£©ŽòÑ•zŠ‘ãW`Ú €ä ¡y¸W1p‚·ÎE�N1_^ï+Í—R‘±•IÏdŸÿ™ž ޼Oç/‡NtÐXææÇVF£qæœYÁ�¼78ßJ]Äzçù³é=ówc„›Nß”W9«•ùäºK±ÏïÆpÓ±m³‹(¿vœ«Ø?È,Ãô¹CýQ¾ÒQ;Únß5ÜÔ’¢ HãׯúœÝ6{X‹ëÚzù¯tö€\p"Žtfl!¿ÎmÕÊõSpða~y{Uö?ÇËÛ_3ýuÚY1»åyÌúë0æßå¼¥@X— v4¦+‹½¤‘KºŠ·ûÝÆR½ÞÇS*Fêbzu€Œ¬=²ñçy( -2¿& Å¥ 1f,_ëÉÛɗжßj_{‡§³˜Á”jàBe —Ìüøx1&oO"¾*‰~Öw𘴓r�¿lŽgkÆæ®©ùå^NpVÞÉ:xku�戮™`ë8JÍ’TŒ¥´\Àô²Kæ\9MÏþfÏ#ùaûÙrÏöŸ1ÂÖñÚ0¦ÿ]?Ïȹ¥ã-M©ŽÇþÿ–º’ößýâ]¿1+v”ݲóYýc뽸NÝ™]æWeJúñýàò¥ì×®8±õ{Mö™qÀ{Þ?ÏèT âõþ¹~!#@”íù§øñÅRË;ó— Tâ“fRblµ«xo¯´Ÿ¬¥%GH‡íGI´Ü4󴊦ÞK¿6|I^Ľ+UZ1Õ4`w*Ò9Æ<××{Ó�owŒéuð‰1Á”D"·¾”cÕ.]ÉÅÝtGqÏ磜‘î–GIVâ~7]hV�yŒ!v…ãÓþÃEí2¸†½Þ0ÂR¦We ó‹–™h£/Ødˆ­¬�S¿´¸šéO kn'æÊ¥¤7�2œÌ­€w&FöƒŒ„5EG@åÈŠ’N“!†ønìžÿ´3@ØÕ€†zgWîÕ^Ó «Kk‚cÏgçÕŸÁ踲÷ï" (ëæcŸ¶";:£ãø‘Ø"Y»ŽaÐ~Eá>#…–WI'*¥™&+†ÁÑrUR^x|¶ßþÓ†ÀÆB +^èxß‹éôÿÛw`õ¤cú=:dÆj�(—Ôåó1"ñºÎÏiCvXþ^ 8 ”ñó4“Ë9ÒãG‡ÙûæÛSßÝ<f[d~áõ]æÔ(ÎÛ{_÷™^ùuñ9ãíѯßd‚Që` àë�_¯ àòã›ã¡¥ýxÃ^÷:Ø÷&èœß[e-ö»½+¯fÛ—D\ £|»_Dýz 5vÞ­W¿ÃcßF 1•tkæ«ÊQIËb½q>pMÎÃq3úâüãÿ²÷6Ù‘ä:²0•)âhSoVÙƒº¸Ë»¨tÖÂt"B#}ƒEÀ`€ÊîwÞù0Ëÿè$ÃN‡Á ;ñÚè™ë×ähû_ïJÑÑvovÄåïÃý@§n€eΫíB?àö–ß1ë˜Ï¤ðiõj–Œ±IŸ¸ï0˜__ –�æÛ蕃pµƒWêßI1],pÄíoE¹<×X¼nf¨tpÚžW åJúãûŽò½ c:)~(1¸×îº}k¼`÷§µ.#,»çúŽÄ%/Ç3Do_ËU?”TõÃív^>Ï›@ØK8,fØ41 Ãj«‘Yû¬õ™3{ŒèÈh¬fœß¥‰q[§4âKr”¶èøŸÛ+fÌ.(ÿ‚¬™rˆT×­Žß,�Ëç!G-öÃrª/˜Þz„øõôúÞ龤£ºN÷¾Ê›÷Á{ñ;õs¡íÚ.E³JºphiÄ G®ûOv¼Ú^b?ök.?÷ÏåØÌ16ªÿ*ö’ˆCÀë0CìZ<¨ññ« |øuµÃRI¹ÄÚåŸ_*‚Ô/µ4!›H­…ãÞ0<»ë¨  ;o}¨3‡22°ÝÊA”EÛvb/‹\Æë\�xâ’KÖ±³ã˜QõYŽ=ßïWã¨R+ÛµÔÛãñÈ}³¿›CIÇ‚(Ùv·ßÅûn‹¹ÉÆ×¶ŒûKë<´£0åï2d8öãÆ¸”_Þ¿úÓXÅëIƒV@˜Ž8ïUUUö½q{ßi<çÌLÕ¶âŽj-yXIǸžUJäQl¯ŒºgT;«ãS«$;K@èsûZÒúèx`%Ñü|™gÓṎ¯$ÑTW¥�pº.Nq=™òZz›3õ£Dà4&åe×;¹ºbù+@kJH÷$û÷Þ|ù\ÌÓòœ?X?TŽ`¿?¿úL¸jûÝÔž¯_7gNÑyoGt÷�€ã™,2ŽV\?*´£ÄðÚ8¯b€¼´j'Z;ïÓ)‰Hë ! / ™h%ãpÜâÒú#\Çî?¦.;’…·Á¿¿V?óaÊ^F=~{Ó3í£ßï™4â­tTr«¤ cySÔWX^忉'rkÇf˜(U§ûK{±=ÝïùŽßÁŽŸL2‘ï£ëçýqõò B[/vü;,×öU÷oÜXy5`¨ûœÚö1€Om¾=‹Ñã÷æx€sÛás3¯±¿ŸÅú¾q¨»/™x4Ô1/¯/Q‰ £=S€^u¼>¯Ê™X‡òöÌ—¯lÈhìö¿>º|ý9,ó÷†bÄéúªúwSL.Üóöï…í©êÕŽ&P¥ràkŒ¡2uDJÑ-¥¹ÆFØû1ª\ðë¿)&˜cPUeËT½„¢aŒ=–klݾüR}°)‰Š,µ›;¡³Ÿ üƒ8N”•ä¡@€s£�� �IDATwDèôÊ<PwÅ<ˆõèLuΰÅhòåÎú,Çæl°õ®~Ÿ(Ä­¡ž·3Ö‹1éŽN',„Iˆ°\c¶_#CEUG™lƒæ £†ÈìøQyœá¢ì÷e9ôt)ÍÞ?™wÑ R‹gz¾/U¯ÿoÙÑiäq  ?¾ ¤éõžÃ£’°ÛuÜUÎ~ô¸£Ö…Yâq3w×1 ÓsRò±ååìJÀF`w÷~âí×õN‰ŠáÕe7$u•qIÊɘWŸ©Lt¬#…†ª*‡^uÄÐ5-:°ý<2J"ÎóìüÓJªzV9Z«þX¶ÞÙ8Û `b™gç¨óý‚íV�G |Ë®<7ol‡bÎU×›v)ºµý»‰e_Rµg»Â7ñL\»ºõïqï1kž}™u["csSe=Â�'ÜÌÖÖ}¡ @€€ªñÙÞŸ÷ç s õ~±Lº.gžœ\=±}ýÜPÓÎnܸ’� »¬x±þ±>Ujn5“+g|D�gw†yuçÇ܃þzûVÍè«P¼Õï ˆÉúëMl·¦%÷´y�l2ç®nÿºþuÀ³ëÏýV7á§JËK€1dnžàüŸ²×aý–1`k æØ!ÞŸ»žnÁ–sÛe‚i〠ÖO-Üt®1Õ?]ÆY%Õ¨ŽçÀd4TzãG?§dÞ‡Æp|ï2­4® -ß³¬Uåî2±ð<_~h­~ßúº U3U¥ÀѪH.¯?ì~”0$@Ö!IE”‘ã0WZË~Œ%I˜ÛϯKý•¯‡ªõ˜bG]˨t¢Zo˜¿Á®ä?»Þù°ëhúÇÜÁ@¯7ý¹Þ¶òˆ[.]“•ûš–ç{ÑÖŒÅ@bõàF5sMTì°æ?ØTn ^>¿|åã<æ^Ë#�sGc|¼‘ýÙ‡}‡q·CD·Ì2}È 8*íÒ0˜©ã*Ç ¯ŸŽßÙeJx{lZk­—+ ¶/ß.›¬b’ zÜþ¯ÿ¿Í5û^û]@Ðï˜þocBv긳røóTÝïy¿þÈøqA `‹kà2ÛR¸nÙ•Òm·+ZõûàxÎ"Q™b’©÷‡•ÂÛkDznÀ›7Gœ—±~ZçE‰p PBcŒ§º=þ~¼†y+>EF\GÊ ç-ëw×¹p랎׻&ë8Ô÷Ãl·¯0¿Tý­Ç÷+Ý?…“Y·Ë£¦ç÷v(éD½îÛ×Âr `íýnñl/}·£,öë©�x¼e °7Ø>s}½~.UàâøÜ?ÆÊö"Ê­Œ}ÇXE—«<£fØ0U¬W­!1] ¾óµ¾ßc�Eçz/_ÀÇpKÖ_|=·ÅpAãÈã@XÕÎ €LÀí ËÝòTU9Ä¢±û¬®X¿(ÆßNÀ̺Og}«û£²U£W³þΙ_ccôJ�{ÊÆ |>1¢ežÞÌ—½ Øá¿›wt# ³ËÀªs;îæ òË~ΰi<WØ‹¸3ëƒ~™uÔ¼oy$p¡˜IáùÝëäíÛTv=B]Ïdòß¾hšý¡rhñߥf|qòõA@ß?Zb²ê§êº­lÂð:ŒUç##Ì�i®Æ*™Ë FrŒÑòº�Ú´F±Oû¥vtsŒ}ôZ“¦�¬µ<\ÿ‹íŸÀX Û‹}_·¥xÞ¥Å×j{GëDr)i%áí"?ä™ã⎖F9±æ¥+´C;ŽÎÁ!€ÇeR@1·™ê˜ NIPN l7zÞm¤" •Ägø!£­ïPíF^³û¢zÝÚwæ°Y‘™‡"|àúøtà)fAå@% ³šÙfûáÄüw8 G²Ê¥¬ÿzï:¬ýññþEfØ€ã|ygèŸYk `À-U¹ÿ¿eö€…öèïïfd>òã"³ sFV†—b¿ºÞ¥y|ÏúŸM9`Ç«þá¸`Sc=”,_æý¯ú¡óY¾Ã´YïEHžÅR3ŠÐf€NõÞ¿çóóxÞ€/Ì9«s ¢t™ê¿,Àê ó0;ÿ@æšš‡vú-¾—/ù⯿/qÅ®Æp>]1Úýv–Û’µ£î ¬§RÔÀ~Ë­–T«Æ•<�­~~+Ç£¦Äþé`û•]Ûß8”c=sXæåªûA�·ê0P6ÌòöäŸW+IèÎ#fÇõ{Äçh=¹Õ¸°+%js«Y†câÕ@‡jd†M¦ê#)v{pYD¹% ™Ô_nùkõ¯çsàéþËÞuû0'Ý)ÜohxÿeÏ92¢¬änn3¿þþ…­½Šã±Üׄ}Üü:È"Ðj·GÀõš]×-gÿ¡65ÀáM1Z%™XÛÍü}¤>œa¥ësŒký¾y~%E§�²]`±ttå"ÏU=º€l_’ËïjÜàï_qy=P2±Ï TíÏMlo”@­�DÞÞÝñáÓ˜"Fso!㋜_ZXÉàÚÊQ66s‚áþŠ1öÃä;()¨€.Ì%ÖÆþ»X_RŠÁÒmú/MÉħÿ‚£w&œÞ0Rd½È ü°]ÛkÇN|QÊû GǃbôLc’6VÆ–‹9¥X¤t¨XIÃëðõÕ’;k?+︅#¦+Ëc ±ÈL[ŸžDbp­>ø²ßQ9Ñ¡ï;Å8 õ¦RX¯ôs{4Ïßï7o}†ç,Ò7—tbýñ϶`v'-‡ç©«)¦öÝaбv´—þ_‡à~oû.íò«ãø}uùú½çý‰ÒŸ`ññ;´XÞ^ýªý*GÛnüu—¡zÝ�„-ØÇ%/·Ë�›†û“q}øŸý° ™8v»:¯óÙ’9º0(cÌ3EU/ ˆp�+ÖËîÇù‰ý=ù<ˆ3Âl LƸ²ó8›Ûk ˆƒõ9N§#Ø÷Óu\ÚóšÌ!b¶¶wæŸSƒ†Ñj‰R&}^ xiã"tkÜá%=ˆ±‚¿'wbÝ^ep鵿÷ž8Éõe;ßHèIûy@¿ÏÊ�­·|=æÈ>°É\™¹ÃÆÓ¹ýbkrý "�¦ž€¸0`Î:ÐïõÅÀØèHÇ~~QºR· Sà|kýr÷ù‹@ر,{µ¿e/0Yç4Û5Õ œžan§õÜÌíõ[7@Íß7êþîùÊÎ%çÇ硎õ×ó¹Âž Ôùꎻ±r?�8ŸŒ±¼ð=fŸ¶^™ÏâxrDº:Jy^?Ç*‹õ ëÇs„á“öBûgÿ9䌩wñ;E ±Ÿã²w|ÎX›ö^ej{Ïc£W36þ~û+‰¾:·Y~þ>ã°*¯®%w¥-½ifÚ\W9Ãv™rùu÷I†I†Rˆ­óUyxÞd’%¹ÁÜñÕõ+À«bŒ-†˜‘<üøO£…¿Äz`’!öÔ“hœ†�VSúÐ0Àþ‚unøz­îxûίj— ?l3Éœ8¡�ëÎkìqD«otäG‰ŒÀõûû¯é2—–Ì™Ž’ÔÈ${0BÚ/ùuÎ°Þ•Š³Ç)�ð-iû Û¥˜g«Ñ”FvGr¯ÓÿüÑ\nNŠ«+ÉÕ=žä ÃõžCYàZ"Ëž÷?È(fTGîhV.& áË©…‘øñiáLBT»õ¯ÛUÿîmÿ®»¡âϨz+@é"úå\�›ë.¨¤ y  ¿o¬V¿gUžUŸ3Z1<Î4`~Œ)Úì]Fn€%R‰Ã+·¬òyؾqæ¾gHY� %þ8#}ˆuþ>އ�³ó¬È`9W‘ùU)ØþTaó<œ"#•¼Äö)�@üwaõÜ‘DºŽ(QLŒŽŒI«zzÃߣk—CŽ9eW1íྸýÑ=º7ï€y¤ò’‚Ì¿k·ÏUõíæˆ´^›‹hæÆ‰ ‘¼g,ó/ Ä ß•fDµK(gn¿}øßßJ,V�öýúë;ýÕ¬[óåp©Hd–Dæ2p¸TÞ /°ŸI¼ySÌÛõX¦,ŽO¬ÝÌÔóÈzXµ7+·ÎÑÅwå¿9ÎLñL —¦ƒ².Ï—{“39ÝOì=ÄrV±rc¿œèyý~;}ÞŸ«}vëÙµçpÞ H&¾ˆçû…õJ%>½„òÕ:2Ä–dâÑ@e+%9ûï90øzý§Y¿JÛ¡H¼-ÿ±'j_*-Ï•ÔgRUÏ[WJ° �Èë€H”€ôû÷¥�ÑÔ—M@ä€Ñ>Cl—éV…xO€©øªúT9Ϫýµ4¢b V¡­Gs)K%�3Ò‡ÿl–çöW@Tƒ¹æöïæëÚñó‹aõT=ý{$‰Â0‡Ø@ÖÂsì¿a©%C;`}J&òëÔII½!3L«þ)î¯-“,‰L«êƒÖG€2G2ÃLÕ“1Za¹ÌÆè;¸4àëž1zJ’0»îrØ ´O”,ñ¯è¨³í½Œ\3ÿ"¶O‡Vt÷iÇË·u̽Ñ~¬7<.—àᎌŠi¦¼=@êÓœ£õMïWÚ ‰®n?(i)ÜÏsÚ\eùjÿQÛ¾¦Ó½hhA6h!p¦ œ‹¸NdºåŽönæ§ÈLâ×Ó½š÷óYǪ¸—IJ «sqäú]òz¨ßTý¦{«zª;î»wÛM‘‹*pf½·æqH² è·úãéì˯˜_ÓH ª'¯‚pý}Ùugó!u<Fòc®)k1Îwý^à Ûièl9q^éÙk|¬˜T(‹ûí:Î;m?a¿s‡w”Äžçùy2ÓöçEŠ hçƒñ<-µÙ B¦M¬¿Ê‹Ö{~Y�\‡iÃê=Ëã×9ê`Îß»7¹?–ö2¬Ø3øÇï+-ïûæ]›rˆOÀÆ?ü—fý˜=7v?d`º[DZÊî_xyuÛOCI@îåpb�Jî@¿Òò˜t¢bâæãÀÙ<žÈsÒ dì3>zwö‹Xj�q¼üG¥ânbfõ¨$Pl§ÿõóp-Ïû;)8Pêñf$ß }`Ĥ££WCžþ¾½}1ÁÌuž Ÿ>ìý…@”ïlǵ=oP†í{ܱ}Dâ¶<½ŸÕÀµ¶nŸÇïK—Þmå«ê{¥çõ†]€«ÇÀŠíÉë÷.Ê«¤�Õu´¤ã,×/µugvÊv™z{¶+9X3#2Ævp{÷]\Œ1“û‹æþ2çÍýs}aP¶%¥HÎWõüƒ·›3 퇾<PôsSB´Ÿ°ŒM’Š`ÿ%NWÛ…„"Ù~·jxߥô_›H;’Üv˜h•F0ç5ÜÑt5Eûa¢V]I"»ÝG‹ÈÂq Ž”\’ðR:,,ƒn:\0ç‹èÍ#/àè¸ÀËJeŽ­ªsíøø{ö¤µ!°šY?GÖŽW@` ITõûL‡Æy]‡ºÈj©/¶ý*¯Õù¿Ïz=y)¢½ÒUŽ3Í„â7}¿Nü5óûpýÚÓ1Ís¶uE¬W„«P…L¹ªXN娬� ¾%85îW~ÿ¸Ç¸`>g 0QõŠ@Ù®ÄØÐ=[s‰’†JòPI&®¸ø}• ½öië80lÀÑ}=JY±ùætÊ�æ°a¿öœW¼‰uÕ.˜è÷›×ÚøÔJ½v^Äöt]·¯«¶3 G&1ª$+»÷‰]b½×¼¼ ¡¬ãÞÈçÁ{9~ÖQ{óej<ªÚÏ÷wãk›‘œÁrÜô{‘ÿþ*7·)‰¨ý{¾™öÍ ÷uɃ7ÂW½>`7òfx-–ö»lû9Ër…áõØö(‰{„§*‡»žÿŽÌáúRíýQ¶§"#.¶7/§ÚÏŸ#•kìEîçõß½îQ{Ù'3ÀŸÓ¾J3lPšS“½@I1İ}ÌOó>øóñla“16{–H ºõ׸ [@è]ýóf–Xï}Ûe6Ïþö¦îó—ÒÑîí],kI6õÄù;jWºt4Kš¯�h ¿wÇW¡ˆcó¸êxe9�·+•‡‡ïÉx·c÷8%ˆõóå)FÖ³Ï* Uoû9ÛzåÆþPíáåÄœyü¼ˆ«r‡!óŠ�as=ÎÆo°¾ä:»9Éœ-ÉÄ%yè™VßÅ �˜2ØL°ÿÛ£©ë ðÆ?˜S|g¤~ yÛ~æñ˜;b^mO;=g¡$Mg˜éH÷Äøµ¯Û¸á€Ò™:”X<i¾þ1ò8‹pfûßhyš©†ýiÛc?û#Œ9²ª~】—ÜÔ¯wÞ/˜Ó¤co´n ðÍ^CÞáVIj=$z†Ÿë€öq äi]FJסÏm_*ˆ÷]ç×¶û»ì–÷®UL3,×ïW¹«"àw¥j—:nˆrcËm½"PçÛqÙp´°þŠŒ=uÞpÇG&žWÝ÷B¨{ö(ðÇÕÏÍysùP?Tã¶Þêóun$ÖOUîÒZ"Z¯w$WñÞ²¹›ùƒ€‘r˜YnÇùA”>ô½fŸ·*g]ÇyãÑìJøñvÇ€0œujl]‚ݯ·¤ǰóp5²öÞÃh–™¶7ß×ýs¯·ßÞ¹^¬©/Ïþ×¾*[‰¿'€!ŽÃ]‡gŠÍvïk¼þñw;Ëù»ýnœ9Î2‰.Æ$ñóô“cTÙ^°ã ¤õ˜9Â>×-ð…’‰Õø¬ió?ËdYßÕÈ�Ó ¤ ¨²îa(z©´sb÷{ê^ºbŠÇÖíŒ'»9ÖÑ”¤¡îÅØÂr•$ î¡ûqh;Ê4Ëù2ð¦Ö»’ˆª¿üöÙÞŒ ¦î7?WÎê7%µÊËg�Ìë°Žó)‘8™`‘F–Oç‰o_#™]¿Áý5ÏîÖ_ ðó̳.Àø=0}ƒßùQ«™.·ÖöÝqã98úù8ªs5å�C”üÃëq¾lr�]?Ší9€Y[.Õ·<©òU9Xïª=WíR×Wý}ŒÙö|`&Ç®÷îßê¾Áã°^Ýç|ž€QʰªÖ‰ýQl¯�+ºªóv°ôøæÿ;Pô3�aŠqÅí,¿¶OØçò2ÂP&¶k†Xe1ÆÓ<&aV„ìý JcÌuõÈ¥4˜±HZËT#‹¸U’.Ü2Ç/GEìæšç ‘Ôý£¶˜tømx`gÖËŸwN'ŽŠÑÁäû?hï#ù¬# ׫g¬ï¼Žð¬ÃB÷¥úà:Ózd9 v"­b„½oO>Ï iT9†•Ä[jèÈ}꺛uy*â¹+ýU9„zǩ簧ì­"°?.)tÈP¹£º ~œb2°~Õã// G@Và •÷[_ò®wµÎžÿ «>“ª÷Úµ}|—©U­õ®´¡’ŽuÛ_ûÌZÙ?}‰C9–j¾Óur‡¬Ÿß,À™Dkÿ+ݯƒÊY}I›ÒŠõû‘õÇz?s -25*&˜žÍùÛ½¼³ëœdÉŒI8bà•퇫ì'PÕ1Æ|W÷Ë Û;J pøÎèÄá~7ÇÜß/a{ïýÓ P¸3µÿû˜ö+×Ó½\œéqÝþžÓa­ô‹Œí°«rÝàsã`hð¦x™Kܯ�²Ñ¾Qê 1ßþüÉ,yò–Ÿà ±Ÿí/È$!3�“›æëû£–Hì]ŸS•U —0B�€ç^ë4O& –÷R~ñTåb{ªŸ®•~´÷¹` éïãeÝyÑì7z:÷ËtÊV®0¬™/çf×17ØÓ'£ë)2»b=Ù8¸€±Ø/£ØnûÃ:x{{{÷ËgËÛeF¢i`NAºS‘ß±û޹ä\ DfÍ1 ã}äÀ”’6Ôååõü}†9ʪzu™¬<÷X ìî¶û1)Ågñ^ÝxÞ»˜>÷‰¾¯±>ü|+à™€±Ȩ:Êä¢F˜c€2’)07¢ä¢:¯Ûž™#-m d-Éùÿ1æØWùŸ�ד €²¯%J) æ˜bŒ 2™K íV¬k«\»Ö8ö ¯ç¯ênƒj/‚-NЭÃã*€'öº©&jÕ~œøÏë¨#íu¬C‡E(g’7¾\tŒ]¤Ç:Ê,ó$ëÿãnbÅlSý±oôøc–*¶_ê9 ´'=V9|Uî1bC£›­J‚ê:½dîx¾fŽùr‹ú¶û„‹üÀSñ^]_µ£D»ÒŠUûªztÛSõÇï±]Fcõ^T�X¼•kßíÿÚñÅWëÎ* Kߨ^¿¬Ÿ¬T.–¡ï×Î8RIù*æšð�¦³ ĹÍÏ ™]¶~ŠÁà™bh³Æ…|‚’Î1hö72­Æàó8Þ^TðõYGxœgÚí Ó¨ý`ãJ«]}%f1 My\ÇúJ> oèßµå~ããÁ Ö«öç|®¬þ•FÏ!½;o‰�þ,ç¯Êr€_9蕼¬ãu;pI…ˆ=ÝÇ?d„Ý>´/GöÎË£©Ü\ ÀÓ¹òrfÓ4ÌAd0o (°Žø>“iãÊ|ßiE5ÎîI$®öúeÏúÒ~×¢âø}Ü•f¼‰`]ç˜t"LXå+†f~~4öþϘ[(™˜þh¦>?•4¢Í¥õ<üýølZì™a›Rˆf2¥q™˜ß1çÛ.Ъ Û¹û<YFçu;{Òj8Qw²ÁV¿L€Ìç«KëÅúäoZ<®Î…çW¡¹ÇBv#@Ñc²uL D)†X~}ÐÆþÍëY÷eXÿcR ýzå9ëžËrº Áª½§V9Q ³ê'´ ¥û0h†™¦PF°¤žUýçõÛ ±i>çÖb|yàLæS@Ø/”P¬rŠ9Æc,c¹dâ­pD<J©æoÜ«y :‘(v˜~õðºcJ*G—GÀžÅÄÜ3¦fdñI:yVkéI+åhϳÌ~™Zx=å›×Åf>ñŒŽü šýésƒœÃk.1Ü®÷"ÞU;— ŠËÙÞøAŒåîEFú~Ó¤Y•KÆf¬\î0Ìû£i•c¹Ë0{:ûë&Àš+F\$bd*Þ§PÎ€ã‡Ø¾/1õ{¬+½ôÝ@Nù]åOÛ•Fü]õå¶û»ï;.ÕýÌË«%ŠÔ}Så�QÏe—Aêì©ÂÔȸÕ|s@™2§Áö¾µÛǨß3&µýláóÎì^ó•¨o(¥lëo·£$â}žà¥‘Uùuðy˜’úS (DEŒ9UÍY»ð½Çd¬éÀ%T PRrÌ¢û¥š'q¦H”NÛ3ÍxåS÷3¼r`× °cïÇ~?\Å‚×䬾i .—.Ï ¦ CfXWRè$ǃS�[ïêfFÌi6SL@±=ȬC@Aåò¶�› ÌY�Â2ø*iÚ9^{ÉV.yÚ‘ªdVa/á>9²¦r€U1*7Õ®_æå«=½vïöW”°‹ýÔ ¼­%%U=×}w¿ßòû42¯ô9ÆöØv©ùk—†ìyˆñûg®0×{ú|Ž>nâz±œ©…€ž’J¬Úí� —LT¦r âïuÛ|cN"ok» x¡[@¶ë!Eàc@˜çEɯëûWå.ÓLuÝ£¡4žq„íî3µöf,}©ÆcíyÞ<ÿùë¼.c0/_÷[Î\|´?j¡’Åów8PõôJÖï6—Ë ]P£Œ2˜%¹Í\9?†’@ü€#Eë1®~‰õ_Š!VäSL1Ê0¦ÊóŽ©ÝHã�™˜Nf;gÒ\Ór%Ù´ó!©¤±ü\sz•›;(€á™cxÝÇ�ì/ÄYg÷A’YÆPcãVòç©H²Ž›kÈ:ÄÎÃç›ë±<Õ?hÑA…¹7l?ÄüåhRÜUÿv% ìu‘10`;Ö?{ óˆþ½ÿÂÐAÝÈEV]÷Q ÆÊqéth³%9ûÝÜe ì·oÿ»RßU¯ï«÷WÊæ¸Þ´Ð!ߪ^»@ÖÇ¡} ¯Ö»ç©z‘ãV?ð@‚»]åyUà:Œk‰ºéºëX3ó=mvÔ}‚sþhà¦#aw†ãçúŽ‹Wó@š¾Î9”“_ðaÏ—0ºPG½eì¿‘rÕ¼b•S‡dÌ;/Áù§ŸÇì=ϳ¼ÇÜǶßy ‹‚5®ヒŒòKŸ#ùh�^åˆÆÀÄ—BÂóh MŸëËÏÃ~è»#ò�³U^>£šQòŸ_õƒ>npƉÛÌ &Þ0ìþ`ãn9‰'íJ¤ÝTùLÒÐJ¯ÍþàŒ^¯1"àaË‹¹ø<â¾Sùwãîx³€º øöÜ6gÞU†¡JR°Ë¤ëú_2€Ê÷ÃQœï·—dDxM·c}T;ãÈÏ™f �ä÷Ú)<×oŸíyså]Ãü`˜ãír 븽·$2æ22‘|}VO lJ&N€ìI·ÓÿþÈ<´ý4×pÍ%Qýö�z` ûm_r°û¥³ê•-k‘Ó¹Õ3Âvý¡˜û Ž>Ð¥¾.±\^ŸLì~ óq%ùÖï“3“4pS¼<Rÿwqß=—3`dœyS Á÷â¼>0éËÛ–Õõ´T"žß ‘«LÝ?UùŒA%m0´ºÌ²y]ºN](¡è¶“gjû`åX†Øn®0Üÿ¯±eO3g˜bˆ}ô�·ÇmJrð¿‹µëùg÷A­^ØÞ:ÇŒ/O]ÇZ´0€‰9+V—ñäsO¨$í\bïj�(” RŽžJÒ¬˜Õÿ�� �IDATJ'1‰%¹hëûÁ3³2xcÊæ÷uÜ_ ßçºw<Ù~S€bç~@I¼?ù}f«ÜÑÖ•ªëG6o�»JÂlã¬ë¨×íØé§É>`¿ÕõJ7u§#ÅŸýÏxG?Zîw1”k÷œ?N»¡rÉO5ýg� ¯’ø«�æ£ãèy —cp|®SÛÍmøÀ¸R>�™Å|þQÏ7’³yŠu<Î÷—}/X ½¹îÛ‘e«_ô:Ö“íqž‚å³€•µÝ3°Ÿã®'9ﯕ,£^ç¶Õ�£êWû{F^‚ÎíÆ¯«%€Ø5ßÿ(éíèûo•ïª'ø‰å?æñç|ЉœÉWõéÝC�¼Âö¹¥Ûïý÷¿b ç MtH*GýbNáùFÀgþµÏ7ËU]}ï¹Ü[Fqlœ‡û1 ó Ì·øy…¥f¶Íþ|ƒãǰ€ —¼‹ _Å[×ëKNÛ~ÁyKõ½¤©®4Uû¹#vKGSVÜ œª~}¦Y¾¼_�]©GNíïÄ\ó8U~4[cïS–›°¨úìJXÇ1fF#p÷)ÔcŒ¦T¢g¨zÆ`ÌzÃðÛ9 ÎBeÔ¸à-~âvnïÅRA±3gØ ö•”T9ö_ªŸp²7ÐçUL¦ü¸gQ2Öð÷Q€L•KJ1ÜT»TýUŽ®n.,ƒLåÊ:橘_G¥+õýTImÏó{�d«ŒÛ{{fJ°ãª[ÞãéÄQ”Wp-€îÇc|ü'=ÆQ??ÿ¹ €¡}\¿�›ë¿0ç+C©ÄÿÛûÆÜ5•]Jo¨ˆ6/ípmàÇL;š.ÅÒŸ¯¤ÆPŽ1Üs4°r­ô!û`bëÜq£#н#bF0ŸÁá”;*ØuÙf¼þ…~¨¡'hìCïËiY>÷³ˆóL‚“Ýû+¬ý6¢¾úX®’ïÈ)ՙخû,>œ¹éïh=ÀY:²ÑÁ]9ºÒŒ{À¸¶ÊáßKv �Ýn}rÀMåpêÆ‹w™BU9x^Ôt¯w¨ÚìªzîÆßíÖó$î³Só>Žï;íˆäçsIÖÎWå¤À9atQ LhÕ8°„í2Õ¢$¤zßÍã¼cP€Œ¯òŽÙE:^0`ÆI>—•fâkI½Ê”ƒI½_ð½ûF÷{àè”üŽ(Áݼb}Ùq–16çOv^x5S¬šÿdõŠãþ¹p> dïZ­„`Ÿ­yk·¤çz¿0ðpÚ! Øív^eõ8èGÇ%!½Ê­™ÁCçºÑ‘Â~ ³ñáË€ùUI¿Ýž8Pnëç×9cuž fÛ¥¾§T@ÞÝñú®_ë«'î×aãÌËè·y;6ÿ¾ïI´x¿LàÉÏÈiÔqú’„×ô|ËpêÙI”3×{L±Ê"�R‚X´Ï+2“˜„¡¿?kÉ=¼ÿ°*ɼ®oïzñúÃÝ.m±·á™c¯á ²}È ûÐÒ£yN3Ìñ7¾žóʼîîçwù¥„’ 0ó†¹Íª/$¨({–*_~}Ÿ– 5£æ» ¤*wV·=Š™´ ¬äõV6–PìIªú¿‡ß§)€× 7Êãüv]n0ÚË]vÜ4ë§�EÏœü¦ç�\ÈÜv=a\)«€-z½o(?Ý‘?Æãéß{W~ú÷° 1Å,Ë« €ýœÀH$þDéDµÞ4 „u¥‹¸cF}èu-FZúåz,PêaúÌÓF•kˆ;ú0g„ìõÀUW#Ý<Š9ÖT„sÅ,âŽÁî#•£´ÛJJ¯`™ƒ¬ÃT™Ž<ÇØ¥˜�^¾þÚþdw»Š´VP~½–äó޹s¸?l»j‡\ýü©Èj.Å´öóó#%/™T4›Î”ŽðiUîŸ]‰4%½˜H¡Ñã¿ÁªûIêv¿ üþ“tPåíŠÓ`.ə媳ǩí»èð¦§ê9ë9`U`EuŠé¥ÇK«lDz£R¢0T9tÓçz¬çŒQàGs’óêúrÀ rqXìsèñ¾Û‘>T¦¥Y/bû´3¼—Ô8¯½Y/³ý–Ñ-ƒ�:üýN–1PY^Ü!Æ™V§áEddÙùÞQ〚ÀR¶—»ˆçŽ}4Œí ÷[Ü?ûµ_¢7•ËøêÖ ê ÝdîÒÞ<âZÖœ6ö°­Ö{@åGôû¡b×’ð(µ7—¯°Ì%üÐ!»Ì~§ÍëÙû™ÍU`ƒ}㼎±�2¨ç—õC·›ÕÓšŒÁáˆS�¦c,mùÃ¥ïNô÷ÂëF‹ß=üûGîôžÍ DË·³öeÇéЯ-O3wM1ÆÆ* NÏh-à‚ Â¹TŒ%63™÷©}Ûqa˜u{Êîç_ÿ‰1³Þå2©ÀSsøó>àyr@ØÛÈ\9Ü£tÞª~½òb;•m(Ã|Õ#Óh{oft¨¿Ë;Ùß©·ahÈdy÷ûã9œ¦ñ™ŒÎ©ÆçÏŸ¡™Z»õDãýñ<ô oçÓ­ªç»ï«öq€ç}TØžï�§iæœßÞL+ÀpW:ñèïå€ %5¨ŽÀ\9†öÛß8o®ÏåV=Q"òÇÆ¹ŸÌ­ÏµÅ›Ûÿ‚õ°úËXUŸ³ì—b„5™b˜SlYÅdÈ^·°~üÞZü Ã=ß#NU½Vm$oÕYn‰iun¦h ; YŒR'ãðö’ÚñÃÖ퇠w¨¬zØëŸFLŸK)rÇ›=ÎçàXýÈ?H1×Y-ýc#µ/ƒ;ì2wE7’1ílûÆX@ßrT®%~2G“fží'ÃU/ÞgøÐ˜÷ÅÊòûÊ!²5®| #UìGG82E�í¸t&oï.àµ'¡Ø—XäÏIY@œ•{çâ8•óNå,©Ö•aäºâTN-=mW¿ó z*Ž¿†ßi×ÑZ1ʺҩÝýÔºÒ†] ›0¿v ˜ìø3¼çÔýàÇqÕ?(“¹ÑºïofWx°Ï6ŸXûÕ{T18.Ô»k °Ä÷ ›'©÷-2㢄4ÏÝeëÏZùû˾ßýõÏt;“|ÄúdÒ¶½ó:Õ| ÍÛzn‡GÌ÷—³ëõ¾|„ŸÛ-p¤|´Š!-53XY.Ž{މ¾´be‹ùhMå£'¥Ê¿[‰Þ®òùyº?Ùxá̼ÉÜóóáÇIËPªê ¨Ÿ�cÔT‘µ”'2ENb<âýšånC›ïS”Hµu'ùžÕ÷Ovß,@¨jOnº}»¿ ¸ô¤ ûÆgÆU³iú>éæäáRzLªQ©¼ÜøÜã}‡@šî®áýþöÙN+5š1±ØuÞ‡ž·©ž%ãß¾P*q®›œaW9?DéIö{dÀ+2ËîíóKÌÝÓÍ]•Ih2 Ìeùýû^l¯ú9¶ÿ\r D1zây1;ŸÛ3(•KÏÛQ6Ý\aùxªa}ÉÀnmÕo•U€$¤] È×7Þß påýÕ•ììçlë…,¿·ï«£óÓŠQõGq<T™9_ÕËmO˜kU=ÿ`Û§}b˜ 6*¿ü û¶Ëóöu0ÀÍ5ößb©­ç8Z/Ðÿ))•»ÅǨ¦Ð[cù+=îLöÁšEÂZ�cg"µ,Jïy€”Ø®*2*—èðõŒýÇŠú Žaå0ëDL­a:JC>æB³õ³q»(­øf–ö*SZñmäîTï¸ÓRU¶]k=%¯n;“³_z‘kãýÝÇ'â�Æö°öEëŽ3ZbÇØ�F Ï#åP`K÷qá9’6¬ËÈɸkû<ÎPª¦™ýˆ^) ¯ „±ñ+Ûߪ^¼ÿQ3:�ó�”XV+»ÏIÃó¨í2:2»ªv5˜j¿’zÄq ŸƒeÈšæÇíá¶w�/õÏ%}#�†@ÒlOÆ|¸–@+ÿ%‘Ñ•–¼‰ýü}‰óT.ié8~TŽ*µßç¾ñ¸ûï®?.tþ’Y6_ÌîÃü½ZI'òõSr\—a¦Úq@íš ¸[÷Gïƒ[18p]/g¡Ö�”¾Ý Ûgwë·7Ò3©5d*¡´^ydЪÇAñD$™tÛ<þötÒdl¼¹þ=[‡Ì½+u|Ïr^†ŸàºÀ°±ß×ïÂhËÌS¨u¯0³úß�€z9ð䌑åªRååŒ'uÞQ@�¯»ÛÎÚáßgFì~‡âý••·€Îø©çËŸ¿F>6¿º‰q#kó[<ÃñÏæ ~pÒˆÆ\ΰ;ƒ¬vdÏçÛ¶—}ÉÓçÏíÏ0<§#«¶~ΰÑÚ^NV²2«¾wŽ27#@TKŒvú­î.%¨A½g�Ztù×´¼çä½lË/•¼¾Xž>¾ËtâíÖ€o¸Rå¨ÜYÏå}€ýéi 8áïûèý¦Ú³÷¾ò¾Û†‘Ae€¨ �Ãã(@u€¡å–Õõ»À›©Ö3Ì~L ìiæc•¾o÷ °eÈ{,·XÉÇïÚûëÛµ—Ûæ8Å_ÕÈGp²¸^¤t´·Á†)4Dé íxg�BvýŒÅŒGú" sPeÒ¬Yû0Ò|I^¤Å3¥Ð!äûYÕ§rˆ¯~¯½~?]ƒ¬¿’Ræv ˜½þtä‘òè0÷ýÈ�Ô’W«æ½ò¾å�1Ïǘ…Ø>{\X3«üÎs¤1n C_9ì ЖSxÜÓ¹í(ëæSýÑ=¯º.þ^ãsKÚÔL3î>Áubd°*ªëåûWyÝrºýùè}\ô<s?R@oîŸÀ,–» ãy(yXå�k\¯ºO—yVkÆ$ÏEÕ³`ÖöåG«�¯Êp1Üú9¼gU¿U ݈çH2Gì{r•zùÚ¯®Ï¥„•TeddQ3ô³÷"ï3œ™LŠ™ŸIgâ~u}öžUsœ·ªßWZvY1tc;0�)²qþû]<¥¨4q•õþ{öÞ丽5o9 xí:÷» ‰í¯$;{€håp½Šï—kêÐF E<ÿË>>ÛñTŒŸŸŒ±/à ¤•eqñ÷z^SF+Ÿ ¸B�Msþ=pp �cˆ-¿À9|Ú÷éºÞOš1ŸÝ/˜ƒH×«Ë ˆýw_ß ÍBÆ–/·6Ônðû}—_fåÔêfÆó±ßvç=¼ß˜ô_^žÊ-xÒ×íùØÛðŽù×á™c¼gÜ~”J|Ò÷¨í}`ò @Ë% ¯r»moW¢íE,Y»¼ñûO3•ª(.÷K²Ö· h¼‹eç}Ö35{³ëœl] F%-XÕö›ß^C•©\gÞ* P÷ƒïÿŠ©†Àäº/|¹ª_ãzu^ŸÏÏ¡\ìŸ|ü×ÌÇîÌ{ï½¢Ú÷ M`É�QJ²U)P•ä�ûã󸇤IùˆãZ9Ű>?ÆW•€c!gØÇF¦~‰¥.‡ÛÏ¢œŸœ5s‹!C¬±ÌGÂUÛ«umÝÉî=:ðÛ³¬cÅæCË"|cy~;ëaÞ“êñ%ÈóŽ \ zhJÊpÖÛJæÙã}}4SLÕƒ9h°>Ñ!u.Ú»žJ #Ý»Ñ=b%ѵڅûgÿ³e¦¼í<%*‚Œ3ÃjI§AÏS�IД´"ïgå;·?pŒU’‹ÊÔq*—9ÎxœYv¥`¶Ë4ê2Ó*‹ÒJ~½ËŒRëçÍuµäõí÷Ó£ý昅CÿnÕ~g˜5÷Q Œ) ¸:ŽZ2>~C.?”îò#øÞZõÑïs>.÷>ŠŸ§�]  ˜åU;žI5D¹¶¾JZßè:ÃöUž~q|Ï$—m{-@Ť ¬˜òÙú’œŒý�i.­ÜÏÝŽ{Û6OÈîkk•„$ë7È¥�jez½ã6/€½Žr›Y‡?_êvï·*û^Ëbñ»C}GuM2aà WØ`–Í7—ûR9´Wû½d≬ñ€Á”9úÁ©¾ºÀCà‰µ4\?Ìë;Î;¼§d¢b’a¿Ý’uά«ŸË´±ÀF.uÆ)Jàw+öWǵ�ï±ì~T-]-dåTƯ/â÷C@p×jæÛcVK$^Ýs}3÷Þgv|`@›-/æ’C©ÐYNlw' hŒÊ¯ñÂÎsÌ/sþ”Hü`Œ.Õ_È�õý­ÏlžÊ˜1wfØéÈ÷t¸¿âûµ^ï†�XdÞÄة᣹ú¹¡·NÈ’­WUZLTL°Êž¡œÈìëJ¶*ëÕç(€‡ÛßÅöçpÿö˜qJº²öÞóUεªôù]¦ÛÞs"�Ì„‘¥�¯ Xšå©ó†åoc&gX7÷ú°~Œ1þã.™øôï-éÄU¹';ÂR3͸Uõù5° Œ!@¦¶šºÝúÃV/íñd”WXSz½p* A;RÏí¼ èØ‰‡m —ü«%sÐA *¹ ôØzªÏo&mxwäh¦†’¾èDl*Ÿe°ùþTŽ Ï¼Ë¤œ¸ÔÓEßÝŽ†À«íÏkϾ­l¯ë¡™†cô^w`ÖŽ£ìyR9(úq$ÇÆ1° ë2ló¬bÔ Ç0ÎÎp¼’”k4äü®Ã¯ËxÛŽªò+©Au|UÏÝ\]ªžUÿ¥í2�ÖÖïz”ñ¥Îw@XøõÍ%”*Ó÷J ãyžùr¦þŒ¹ÝuŒ`;¹T³v3{•¿Æ÷WQ2²3¦23ÆœÎ&ùû™¸¶’ƒQš9*!Cªz/ñù¾_c�’¿Ÿç{â$Þ»¶ÜÎü ëÒȧr<ªbl;U –f´i¦u|Æë1ýž÷@Ïw¹sU<¹vhq«z_å‘=‡Ðº¾«gT�A€efñ^ê ¯ëWw|ÖN5Þ##lŒ1Ƨä¡}óÍu 4}\Êv2‰¸õ+^?ŸóHìöÚc×¹DZd†u•JÞ Üê}X1g»ñûX]Ÿ•_K™¢„àž'D9ðyK˜= ÈåÒ‹Úöžó<Í¥ ÷ŒåЫÌß:Uþþ ö °›™¾™ö¢jV/¶Ì¤Ø|½^Xy“ F%s?Sž« 물¬ü÷áoïãzè~ˆõFâžÕ9¹T(‹ƒ?*‘¨êut&R1v–ULÕŠ1¾¨¡i d/7U%ÁX·¿gÏpêžÌ*¦]ßv%3J†]±Çq{Þ>¿ºzL¿eßL1¿þÃfʶ€±Ya¸Ñë`Æ ôýxúygˆ=mäüRÒŠ`3ÇØø\îaÊ1† ±/�­)¹8­þЪ¬räyÉG_(*²q­ï”É ‰lÏϤ–¦y‡NŽ ŒÕë ʤ<ˤâ½s¬ëx,]!2t9ZòHtµ#âWÿF‰îÃHržc,¶?ÿ »|¶;FÄûÈyŒ°gíNDé,%›XÎ’ÙÎ1ØïÞ’¤¶æ?ì}½”äSÌ©ëo‹Ïo7W–?~ÈãSëæLÂý•4c×áCÊÛrÔ=ïýaÊQ�Gʸ" 6ØœÅöª]Q*YE˜M]�LÕG1°TûÓvU@é4%U¨Î¯Öi?å@Ö—áÅ Ç»øž>»ýŒÁàÇÍ5n`yU KW²™3Å×}èbàÍ+œÇB{#¬Øûˆ=ÕÙ{nˆú/ÃÜ‘Øþ»­@þþRýÜ ¸ñæ%‰Wyú9T s^“I°³û­T,“FÄ÷›jWfùý^l¼|&YýÝÁ#MOaÿ÷B`Ê!¦bG™ÄGm/ò|1Âí€È<NÇžÃèø=}:º££NYÀÖ“u›7ê«]ÿdŠÝ>ß mæÚ£¾£üs·€<k17ptT"05¯›îWé@W×aýÛ6838æxÜ hó¦$Un¢[Óñ«žû—¶C¯×¢}ÿˆb„-Õ#~ ¯)�ÃÌ2³¢´&ïŸÈp[¿«tºÔ–QÆö+cå,)Ä[qüêW·|±íù÷Ãë¯<`+æÄvçV1]†[îZ?*©¿<g˜23Ì÷Dì÷jïºU.\–ÿ|©dUýǵcÀÜ{±ÿQ —®Ôg<ÿØõk`Š3!µ½~7Ë/5P‹÷ïc@i%M)Ê#̪1F*1˜2¿Ìùh”iÖ�Æ\=Çb˜UåWû)#lb~ü‡3Ãð%aÁ·ÏcÃ-wíW±Ž€Ù—„¢RÄÈî0¥Éçb»ßÿ¸TAõA‡55¼×^Ü€Zd&̈âØ-ɸóaÀ“˜SŒ÷¦ÏñT1ËT$3“¸8…ˆïx}èìGæcù*âyÀöL‚‘IKeÀØ•(oFÐëÈúºý¬ÝÕþõúèÙ}Ö÷iʯÙå`QŽ™\2Ps¼ŸFyü!ë2yˆdbº¿’xL$î*É=<ž ¨ÑrHý —X~_Ò'9¨¤Uî+bçbÿ…•Ûèo<Ž–ó(C±{ÿ¤Ö§* ìnW1Ÿ¸†qÉËö=b™È‹1„ãFü©$c; à¼Ø{ŸIÇùþ}F%«'“4´Ûm;3[R‰ÝñòÆkl?ëgö¹ˆýZͪ@(먵ÌA ta9×% «ÀžWzÝ8³ídï_Þ¿Èl‹ýÕvÖÕž0v®×)±c×%�uD¸ïçu\‹aݨ÷Që9²…¿âU8#’Õ¦«œa-:( –K¢MG0Ö£üÞ@F×'óËÎæ:2Ⱥ8ÎM&¾Ç°³r¦M³u4[æËª_™÷£äâ½ïy°³@ÑNÿY[üŽG#Ð{OHl·*'ªëÜIU}ùþG0ö{¢ÄàQÆ<;O^ØOl»R*aËø{iG0I¬]è¸3ÂnŸŒ©—O€L?!dœø¸ÝsÌ0"‘øû+ö¿ï\vž[ÅÈ›ÀßwGød†}yFbuÜ´(©§¬;æÒˆ/J&N)»çpŸåRGûÛÿ\Œƒýë `Ôo»Ì£Þüî9ynù:žï—Ýóºý³ÏPãíëK {í·‹›jŸË÷ànèK—Âã€:#™¸%Q8 VT!E¬¼¡#©¯’BTû+Ùã.™8®KÌ_¤ÿK4Ï Û5d´Ér ¦ØµØRÇe(�Ìø½„ý~{ý!™[Wè`µç{¤c»•U Y.FÇëí9*€u=qÎLåÞj>òžµÛ^çú¥“°Ü„ýg#ÇmäuÆ”ã’?óCø®˜_ýkëkïö×Áïž×“ª_³»OI!#÷3Ï ýfû£²£€¶‡3,ür�3Di±þ¸?eû�¬*oWz±Ë0ë2Ó*à¦Ô¤Ò}]€gý0¬pû”ܺúý«ß«êïF?l7Ž;v«çå,cñ=ÀÊ[y< :ú¯àfŽP´N€ÁZ^Ü{…YxïL ׿§j©f[_Åó±ÛßÈv|E©Ktp*U|/fäŠÉ¡UÙ<3Ùø}�kmÇC¢›DX¡t#gÜÅuÆ,ë¾ïÍs-p=çsGÝ™ã•÷ oß®½Èådéö.l/î]·³{~÷e†)æW¯ö¤×™Ùó_HM¯g2a»À4ë­è�›ö tÝfn0˜¼7j‡™2—3W˜íi¬ïl‘’:´çßäR9ÐOà8ŸL³+Ü"³§kzœ}ĪÜ[5“ëØõêøû²"j`Q1ØN´œnίŠù:JÚ!3±f*åým–›½/˜$bxñBFÜ×§ €ºÊñbŒ-‰¾¥4ÞwÅïî�2|þ±?s`P¿O{Ûýýü>ð¾ÈMIOâ}?d åLÍ`Ê¥Õsp<€ö“¯ddÍíØn4<.oïó×õ¯éqX~eÏ_õè1pÕÛsŠåõU팽ï²Ý~V9Òöê÷<¾h¬Úµk(ë•Óg æí[×W�‘2d’b˯€7z<‘`¬rÏóÜö°ã’‰cp&ØÀ>~E ,Ë™dŠ1æí§</·_òüÏíÈ+r‰©ªš®É»µêE²û!‰5ª¯ùaQ}ú×%u¤µ#}(Þüq™pƒry`uºº< s’Ë]Ç–ôcò+ò9J+Îã¬#42“âý“E`Ûþâé*9øÛ™ˆÝž9Ü,SlFÖ¿O¯“–QÖ5&e‰Žµ\ùEæ¨åqÜß“Nªë¿ :_?Ÿ#¨´™cãÞ( ¦¤´zöÄR¸B«¤õð8U^u~—ÁVÕWÕ_µ£ªOw»º–¿Ë¸:ÄÌÚ5Ålõãü=Ÿ%¶Ì¿§P¢NI¬­÷Â+)/ÖŸ×ïq[9ý8wþrüs CÏŒV€“ŒÍ™h0pþ”6ìd°ëäxY׉ï¿êx¬“Xdñ³Ù<Âö‹’n|ç¿™ýø^W÷ylמ#0D¦T&ãuÃŽÕ»zïjf]/G£´éF¦3 ¹Øœö(CL­G†˜²=�@×WE”Ïï ÿ�Ž÷Q¦0Fý<Ldzgn¬+ÜýEôV¬3Æpv|Zÿ',¿€Dâ‡)ÞçÖ±6|Ž#]7”„Ë€¬ûï1sl-FÉ›(o§øÆÁÀÅ<¬Ë÷̨èöÞDŸçUÛ»ÐöìO_¿ã÷¿îmÓªø2 ÀS¡9�Vçp[ýžËœœ\ù¬ŸªûÂÏ ø8’1’*†Ø”<ôÇ¡¢*ïe¼.&æ SËÁ<Ev<í’Äz±ïø.ƒè½¸ïPQ_ØNÎ<A¦Ïwõý‹Æ`ÝÜaUÿY ÒŸ×+Ï2û¼uç `{ã™s¶0�� �IDATþŽúzªÿÀ±7ÃÓ÷A—Jí¨~p}?-¿ž¯»9èž›ï‘ýœ`=ÓÏA¯ÿ㺊ÍF¬•«kš¾ˆ´!½è GºcŒ¿'Œ[O?ÇŸŸKݨŽ!Å™c»Œ1ŒýRÀ×'Pö«™c¬‚öqgîðÚáìFŽžÂÞ»£ªnI&5ˆR6Ú©ºÖÜPâvéMEØkÀ$ÆÀ²åu"‚­„ŸuL¡¶<k7Œoeõal#´ßÌuâ}Ï[^¹}5?ص7(Å:8ñ:Ì=¡ÅYýâ´ü°õáë÷ã.Xd 2Û^õó™'Ñ!Çi$—XSÒ’àßeâ|Ÿc?é×Ëh16$þ¶lWʱZîÖëQ­W×íÚÀ×>CYfpG:ä8•÷§(€ÇÛ:\EÌG¥Øö¤&ðå%€W=9Ó™õ6"cܲ÷j—±Æ¶ŸmoNÀì¾Ôã_^¯¤z&5gì"@˜½ªß«bªûyÓšg( Põ¿rt±z]‡ 䈒‘Þb 2vv8ÿA‰Åž¤(¹G:®_=o(€è1©D´ý‘<LbGÎý¾'p|œ`ûQ7,üü­ÿ»O`Æ4^êp:ä™#=S¬°÷u÷»e˜ó¿–þù|ù”H¼}Äùþå¨í(‹L7Þ¾}G7ëŸ[¸N”¢›ÇMéÅ1bn·˜ë­7/ˆõRÊ ±ß8@âsgíú4³¬:®räçŽæÝN±½¾|ƤÌlý®Š¡³?’z‰Nxcùþ~Äñà–Œ`¹ŸÁºìNä-)Í>GËÁüò)™8÷/èóÍ-oð^½Ùë 4âF}< |û?çúgw¿»g»lÚþU ÝcãTA«°[±UI%îÖ;rÞa=ž�F,=fÏ£ „Uíæí@ R‡5`äÅ>ÀÖ­7/%ÿêûŒ×û½}|^Ÿ¸®úIÕ£›³­zàq»íáíz†ß¹î¯­ëéDgß�©\]´üðÕ*ç€I†ØŸŸÿÿɤ-CÌæÃeÛ¢ÔaLuËÿ%ŽÿÚ>cŸ@Øb‹˜ª‡Oôøí:ùôøÜõ=‹!þ¿ùA½˜GºE ã«l—Šx¯,w0¢Dû5»?¼g·}FÄ[Gä²þË#º‘‰ä…×�\ sa} ÷®·[ËžÅHË"¬Ö2a¼>—pô9^¹Ïv¬ÇAG::|Ï®_"ƒN÷§oI—™ ×q»z>îëüz ~%Û¯Ähû³Êñc7 ¸Ì¦4où‡Šc4>*¸k[ÀÐ�UJr&õØ`ne5 ´*©WUÏ|PLʹ\@·_WÌß_|—C›Ù.ùÔa{0PÀ3ª®�tôËÜÛ‘6Äý(³í½|-#@êßkú>ñïYÞdz3� ßçù¸Ÿ3¡,cxoŸ5äçw%)풵Ϯ#Pè(.ÒQßq4Åë`N:ì7=ô¹8stˆA@ Ú*Gó÷2A^Êñü±ñþÚØ¢{IŸu¬²€¸<@â»Þw7#Ý—·@ïg�ØñùÉž£”wûƾêŸÀØË¨ŸG+ý¦÷¿Ûr {V/Õ~ @®íLxà²ó=ξàúµYG¿tv-Ï(dkÖsd¢¼>3Ìw±½ Èâ¦þ]ßešáï/xb.0ÏŒÔåy`ö%ìöæÎó€[ryýÙr ÏDzƒålÁÀ”½E�Ì1ÅÔõðgûo50íu0G~ßÝÇ"€›;ì¿6°—ÆQ50öê÷(ДKéáq»s×Ö£¾r DUÞ{h÷µu¾– wTòOµWËõïׂ8ƒp÷|õj©Ì£æËy—õÇ~ê1üt¿:¦ÔQ€ÊXÊS�\#÷˜;®‘ívÞX’Œô¸æÿ¿‘!f×?~-&mh¸úKlŸ6ªOàªYî´Ÿja±¾Š Ï#«×Ö²ïÉA2±}­rþÀï cì9Zíù=ŸrH@²æó«—¤œ1¢üuFñ«€ŽXŽjg°PR?(EåŠþ×ݗs­ú`fõDGçUFÀëðn¤–e"œ³Lbë"Ëï1úê\!Æœ1ƒn2ÑÔýÀ"í3fÄ‘~gÖýPŒ‘%Eêûc|n_÷“—”\Ïc  ƒ÷*ŸÃ]@^IAîÚwB�|`Ê3(êîÝú¿ûïû­p{åri=íõ×÷C¬/ûà^÷¥¿ÏN�€!p˦«¾Ü3=ŽõÏ®u¤´Ö¸]‚(½5†ñç‘]y|„w"••pë€ud_ä}®Kª˜Åx¿Ù~µÙü¨Ë·õÀ�?xàëêó^çý«žKv{,Ò©Àv]”~Ì®‹¿Ö×ö_*óÌHò˜�›lß'¨Lâ)Ç>·]çDþËËŸße*ð¯W4T@°O¾v{ßw•„Úd"q°2)Ú¾R”û™+l:¤ƒc¸à,‡¿î)Œw~œˆß§¾ÜúDFJ§y QK/2ǹ–¶Äóù<bµ¿›¦K™`ûw¸e/ÂݶÏ.õñ=OHŰRÒŽ±Þž£LvÞ[zþ±q¶–®TåŸdy=éÄx_x è$Î[¦æðZL•0¨&¦{Ô”ŸJ$ E×_¯°Þ'vÊ'À÷}Žo^Ÿ›tlóíJ"±Ý>ÿΜa½ž©ŽRÌ¥~Ž³Þø¥4Z¢¯Nöfl•d໨ßQf[|êv÷]+ÇÚ^û»Ò‰º¾ùsÕÍ%·kÏâùznL®'8ðWK-ö˜ £,2ØT®®®U€TëxÃTkå6Û�Âþç9IFlÿRàdŒM)Ä/ÙǼt¢]ú%En±i‰õûR1¾ªcŠ!öUo`ŠíB\ݼ8ŒWdŒÝíEÿˆf»måj-oÜ¿o,²\÷r¤xd®/.§c]IüUõdIî9@…Ì Ð SN©‰ýÅ>�;‡ +ï:.ÒA´k=êÿE|`^‚c«'¥‚–KJQ1Ô|„?ÂØggWš*wÐN ëB =ÄÜ9üºÜž9w%·1tŒ^ƒ£øâž3 TûúŸ€Æûï�p×¶C«ë˜¸ËÊ5_ÕC]¯vØâõ¹ÔXPºˆr4à…Öp±~~Üðíêä ñ̈^ÉsŠR§ŠñèÇå󗣸¥·×R?>Ÿè åå¡t^|øåøl¿gJG �ßgùe�:ëû°R¹ÈëHwYج2˜ñyÁö `:àxtq‰°¾¢¿oøs»î§ó×ý‰¿³=OÕý¬~'XÎãu`н\£«~‘QØqôÇù—¿}ù|^Úp9>{ö€Ïé �Må‹ß{{jžß+VŒ¸ª_ЗFôýÇÁêþô†ö/b{”@<Çoö^Èž½@¯Ïz Ñæ¯z>Ë÷LCÀïúùœ]‹ç¹/Ç]Kzò*Ú¿yv?J«uœUþ^Ð@åeë½’z“iR×TûÒhjÝ—§&]?æÐ«sšíÕ2”nÅq•©œh˜åæ-ݨÛùFË‹€ò«)?þÞú9›L)¾<c¬æÆ×G¨·õKæ?±÷ɱ- àÌ·=³v]>»ÀHtŒóßeg/ôè®i—ð¢$]Þ^Õ/1wW8PVž<YUžÊ-V/]Ï¥jw>ãÚ—@ôø*§Þ³œV@Y—™»ãáµ×QÏ—*¯+¬˜p¼]æ ^ÇòºýPåêR «Ýã Ú-וc�,œ¹íU.3Ø~ #‘8%Èúûøú{ Çûûéßž† ²fn1o?¿–ÿrëGM¿$§ùûHþ�uŸhÊaŠ‘™~;J(ªiGõB‹Úûñˆ¬¬íL0NâxŒ°¦#wQ„×rÈóð:ÀpG¥güTÀ˜en)æUOÀç¹’úMG™¢£N9žªß3¯ßjoæ bÌ>À2 RÙÅüg?”§ãóü¹Ý:N@fµ3g\u?hÑq¾¶¤Üì3¹i©ß_¾Œß_öþ`ÀµrŒ(à“‘¯ò‘±£J΀è2ËÔø¤$ûf=k€J1 ù²ª_µ=2ívÜ(F g|qfåj<:ø^3qyù9sKµs$²|ÅÈóVKwîHÀi&7;{ÉöòüÜ÷«÷íYŽGlp@³e°q&éÃ`]|Ÿ¨÷kƈƚÄùÓžX  tQó�Þï÷þ<Ъ˜ë'òÜUïñn`…í&ëëýï)%]=Âvàx}Ž›?éûýû®{/Ç3eÖºWªèZ-!æ•(näyÍ üò¨d¤íß'Xçße_•KAgŒ^õ\ÙõÚÁ¯Ýg8ï)•=ˆø±e~½iÄ1î9ì½|\ZãÎó&ðt2ËÙÚ7³?Zt„cö˜3ê÷Y9Ûìñ™Ä_ÀãxëçGJì›ô<T޵GGª=)Á‰ÉüzÈy´¼€G®Šy”=×ÖPï7Þo^"23õÜdïù(™xMŸëçáï×÷Ïœ`ֱ럳ÔëæÊû´É�sKÞ”4=¹qcN×âùTæ™2‹é³€ü;füzßÏ6¯ßÙíê‰y4´Þ^ï囿ç¡Ó�óiæUPÈ6 U�Z¸h�*¿¯ðº5ã,Pž·gh]à籜a Pì¾§z hUß:wÛ1Íš ·WïˆããÉ`)Ê�SÀ"ÀYKXfË­˜jàM€,eŒ‘zãñÀûç‹É…Ì0”}üúÊ1¶e¿|î1·Ïow€ ™a¿cìã?#cŒURŒŸë“öÅêî�ž€eÞܼãó¥Ü~7Í,SækˆÞºe'8îº5‘Ç‚X:wÌ¡$n¢c…}`°òsÍFìÏueÖÁËá’pÖøõµ¡!FÚò£ÿ [L‰s(§j7ZÇkûi25“ÌþG²bjù~9:X‘©q³ÖR98ŽJ™U@¤µè`DÇœ–®R C¶Ü™ÖïIÞÕÛóv{ÇB:€©}Nxû£Tž¿—P½Šòbd¹ �èTp©•JRPsqý•– àõŽõ³gýÖAi±ϓ–ÁdÛ{%õFÆí,_2ØóÖù¿Ïr�‹G¾fŒàl<P�›.¯— Ÿ~åëðã³ xPí°’ˆ¾^1€% ̨š×8aÇÛ–w%‹,à¦?§"sÇ2—;U@Ȭ·ÝÎ$@=S-ŽCêýÚ ¸ÑãöC¬¯¯¾bî;Û®ì¹Ï�n=Ïöv,.XÛúàïIõQ1™«ïž} ÌL .�Å_ùQÞ\5ß_À§ÊuÈŸ—ÉlXÒƒ‘™Á™#q„F ¸c!�oaÈ�{ú ¬›Ûgn°Ïõ›‘FœË °ž×·Žö+ù]ùxšKº±\Mon;~Ÿ^Å8æ–™ƒÌ°||Vo.žC4³ƒÏÔ‹Õ?æÀ:6Séú*€w×Ý^¹ía{×Uýrë‰òú~˜xG2&•b Mf¤­·•LT¹l~ùn–UO¾ÅpL02~ dⓎP ’1Æâ¸ºû½¾€Ï„[þ;0x<Ôƒ]oÙÞsZçãOLë3ÙÆW¿Ù%Œê|zTްšY„Çï1­¡„’”ê8U^u½z;Ž»¦€+ߟšÉ5Zç×L'UŸîïyŒ9¥~ÿ÷â~ëJ]bÔ’Ýrs€«OÅq÷«bd5€£j;e€a¹ �öG±®ê]i)�†öc �ÀôáÃrŒá˜c_ 2 €=ý¼—o¥¿Î½_÷+g�d°šL±¿žþ=ãë_°äöK®ŸÌ_ôxSŒ1nýÇBI©ù­é¯¶w\Ýiôw:-c&Ö%‚Ð*‰¾=˵¥Îç�\dæ0©ë˜òå^R«_å0ʤ®æCÍ;¬ræ™]2‡7 �óý­´*—ÏöWý¡™o(ùö68L c¸½'yu.~gú;©ú²ûÝ27V¿úû6Jrc.UÒ] ®‹ðãÆFó pÃ~ª"®1×È5¬ûòNÂqb5.õÅǹÈÈèI VLŽLbÏcÌ*Žg¬ÿñ~¼ ¼vX÷€Ò hVRNÝû³Ç¬‰–Iö]Éýqoÿ™Ž«§Ð¾K8¿Çl­¤@c?©RvÌMo™½q\ÔLF^|ãx€Žhd¸fÒ“u¿DiΊ‰|¯×…>‡ñþŽ5ê½¥¹Þ._Ï_WúQ„t™Ì™Cy¬þ�]í¸Ç5oéZhg†�På8«`Þ^@¢ýF棃öW¯=UÜjÖbv…•KaG¿CìUm€Dÿ»€g#ë0ŸŽèÜhGG6NW@ûõC̃áu†Ø—þCï=�}:²QŠÿû±œkúµ¹Íìø‘IOrãÀ›Ê¿?jE£6UΘªÚ¹+5¨s]ùíÿ¤ Íö €Ã¯×5 tÕŽàkˆšëö¾ö÷Ùj¯ß?¥0×ýý å©öZæÔË×r]¯b´Úz/FÉíséûåù“)¶Ê¡wÄÔd€=½Üë÷aÏö Rÿ|/Ào ²@ÛûÀßÛ3U@Âúß—?>{e1ؼõ˜"5�†öRlõ"°»ÏÚdFõ¥Û®îx Dä3 ÍðÙmÆþþîФ®U¾Ÿ»@Lö`yMÏÞ˜ÙÝWíúŸé¿º^x^O"™€ïÍç¸.—Ÿ÷\Þÿ)™�H 8ú‡mŸÀZÂ,«¬Ü(`¦$ÐGj#[_9Ä(¾7Æøgåƒ=~_n¿ÀšÌ°/fWÊ@û 2,çW‘[LF ÖÇã×⸞EÉ=4¬ø\Fmú~$Z¯ü…rjœ¹Û~ëpªñÿ¾cΗGîŽ_=;Ó ¥Í%e?OÆ‘„Žš ØÙeâd€FZ£cŸ•Ùz>GrÏ’;Öѱ·ê÷Ç ºÔÒržY°öÎõ×ᶬ4ì¶]1�”$¤wì*«$}ûíóĤ¦®µ–å °ÖeRÆög”ý@µåg ƒ1òÏ“|üàÏë‰�2~ì×�\\èód¡³xœâ­#¤÷%lŽ÷Gôý¥Û³¦ÿÙ²'¡Ø±£ Ði9 °÷~¾’ñÛËÇõ‹,çnZâÛ‘ˆ(‰×uÔÛð­¶(U‹Ì\<ÿÆsáŒïݘã-˜±Ù}Åâï¡Ïâü 4ù÷ dŽñ£ ÕøŒï};Obã™·(TÕ‹3:ùùú9S°ü=i¡G ù{²g�ÊK¨%Ä|{ãqçô¼cî»Ìv#~ýwÇž;¦f²aÎ×ßå¦a9¬*惟Ÿëv#Ì1¾¦}2Án3Ø“Ÿo~1Ú>jÆê û³qè^ÿ<ǵ$Jz lBo°=¿n_×í-|\å ÷%û=ßãÈøB� ¬¸™‰ùuüõúÆï3M|{^Âß-¯j§¿ÞËæÿ"ÖY!0<¯{‚û6Jò!3Òß×'ú>Œ’|^4ë?öÜ<CÉï_ÇÝ>c7w¼•JœÀy~ž Clg³úÝçÝïD´ùñšš„ý/¿¬Lù}©%óóõâÖpÆð²ùD©œa(©Þë(ä×Ùúoò®Ýl§_Öãd7 Ã×Cÿ¾¾~ïå}äËïKLrÃ\u•tã{Ñ®n}êþPëó|õ<ûóT.³ZZ±[¿®UÌÉŠ‰í¨^-›L¯$Yeˆ8µrƒaÎ/¬Ow»ÚÿƒÿñWÝ/fØ”Vü\þ ÒŠŽ)6†¸c@™»~4Ïûu0Gšæ}Òã»ÇnœBw½^_<Ò9F~ØÞ5ß‚”ñ£w-LîËå¸èJûq)@.)Wý>Õ‡sr ËçØ@‡[dXõs®Tý›1¢„"äŽÌ3_޵]GœŠ„ÅÈ~Ë Ñ¤•”"JeÅœ*¶þ§¿ŠQ¦êù&`¦¥Œ”$—­—eøwd®~cý¼"ó½ãåJꃦ¤‡ŽZ`ë0,W;|9ŒéÄÍK&²Ïv_£$2Nj@ŽK52澦õ¤±2·&2šTyŒ‰QYx8jˆÙª_l¨�Û^| ÀZ:@Åõm}; _Öî|¼çÌÑŒ9ë™]ÞV®GÕŽ3oô{¦ã XI?ËxRÏ3ü=T?2`Kå´ï9œ'ŒÁžãúý\»ì:Óìý‰�|ÖÎ1¸if*0© É$±YŽËAí=vÿI®«³Ž½+)õ8ï¯$$¹ êÝY«ý§¯õnùy}5°¤;ï™\<êyݵCC&Gج·gŽDæÕNùJŠÕ»�¬ùw‚‘!výNi»v€ÏÔõý²Þç¹t¶êW¸"à­€œ=�«ÏàÊËWL®Ú<,s{×áËí¥X׹ش!ì므ȀÄç™e³\þ^ÅûÊ?ö~·Œ³ø|,Ëæ¿ÌñÊŸÏúŽBf˜j5PÊž±~<aå.ÂvãŠÇû¢zÚ7&–ñ™À l? ,##%æØRííϬx?uë3‚};T;½aŽ9<?e àÊC]j@Ð÷wSÌßßû�OÅXì)¨þTõ]Ç)‰GÞUûU»0ZI+*{8ý–ã15� 3Œ©?IJ²]©Å‡öWŒ/¬?æ Cû!qº?�[Ý8°À³+à…@–�À¦y l®ÿFØÏÈ k™Š8µn#ËÖv%S–)&ÌÝ4Ðå²£”ẖ†É½«lǦÉËN�$Å㣤JÕa¿)¦3íèÕ¹ŒrG¼ŽH¿//à�×§ïúðö²÷Ag%š”¯ë¬ê‹ýmûù õXýs(©)ìÿÝÈõç[³½Å˜ÃlG&ë‡#Æ€•è~¨ŹÝȧÄè©‹á ïØŸ ¨¾&Çóv‡·Öñùó; @°¤âq¶|ýÙ“ŒÍ‡ñÝaLèÀK:þ0÷XDZÿ–K¬EËÆ©Óà9(5 ˜çÔZLõþÏsgié=}vA0Àr}‘¹›±ÜóçxX½_.°=Žpñì÷ëQâ´b’ç :å€AiѹÄ÷,24Q2·÷eÛ;@ßih†¿¾Ê s¼b?Ï¥b’ãó¦ÞãXOÎXõýËl Ègô�«ï5”ZŸ¦ó#]Ïæ¼}½ýú%‘˜ŸÝµø»#ãYŸs{'€†1C8ó+ÖŒªà{1w7nž~S9ĔϞ۵ô²Î}ÿ6øwjdas@r1HtMÔ}€Æbñ¾î+hAÆ”o‡–ì=)5³´÷<×åp»ÁùX¯¸ý±‘ó–Œ\ùöÕ¾ÉèRÀË<ÿ•”c¿ Pa¿!Ókç¾A©ÄY,7šò'Øu+™˜×gJ'Þl9O�øQ ÇGÆ„‹÷YG»»³Ü‘n÷K6oŠÒÄøû{³U š!³ ê­µ)¦œ–à«ÚYYþwè3…z6™C5šKØ!@ÔÏö˜i)ͼ¿¿/'îÏëKjòò+�­Ï¤êÒü>x—÷…j/Þ¿{ÏC-ÈÛý¹$Œ)‘_s+5#­˜2¿0Æžþ²æù¦œ p¥9ËÆçÑvOû1F`„qæUÜþÅ›Œ±ÏÕ?Gb(›’ŠM¦—À~}-ÿrûÂú/8¾kõ_5¡R *”õ# Udtѹ^|·¾oêEžG<:ì׌ÔË?`jGYO:Åæ®ð×YåðýѤ"Ö+É&e]‡™—hòÛ-sl˜za9Ì‘=ÛÏ$#Y=Ñ1m¯Ãî.ï`ó¿çI2 ´t&sX²~´õ=Ãþ‹p¬œ‡ÿ¯“Mè3` ­ã¸ÐR“* ¸wEG¾wè«ßIü¶‡¢éQ%ò2;úܵŽ4Øn}vǃïpÀ~P[[%áö]@«WöžÊž)‰ÌÊœ#ê¯ÀAI‰Ì׳|eŽu´ïÌ¡8W³-X«®s ï?{ýÌ8ÓRçš´sÒáþ¾¤ ÚìÞ>@›ú}›÷“u¸¿%åXÉÆYO l˜ýœG, ˆX@eÍd² ³8OÛ“hUÖ…Öç°|¾Ûn%sY™Î—Õ÷TnQŽE%Å~¥G 8º6`s<õ§|œdŽæœrJÇÝ))ÈG8¿JÇŸ'Ÿƒ÷+çÖ“Ô¿¾ ?t`Œ t³Û-ò¾>ûA;’wÞã6‡Ò½ÞX^ì÷ìz\PŒÕëBß'ñ½Àß„GŸó]iýµåOJlÿ1È>ëÇvâºÊ õ¨T"˵æïSmǾüu°}èaÏæ"Œ×™ÌÇÙ¾€ÝËÅvÖíÉZß“ãW¿¶Xf[22‰<ç eÌ©~ÚýnÃ~|6‡Ø.`~7ÅäÔÖ{κL”ªF·2§XÏ–äܺ3…C| ¬|9ðQ,:gV„T¶×î¨ðóš9¥‚=—¿ãnûðö»BÂÔüS-»À4²¹ç¾jo•ƒP÷S—a†÷ž‡9¹º 0<—XÏeZ>æÃ\gó|ص,‘Ntõú1�Rÿ,€ ·Œ.”qÏ%F;à§ €ì_të/±œös<føA«8V®2ɼk•TÊщfã�s!Œâøžé×k¸ÐÁ¤|Tª.sE1ØÆˆÃyAÍsyUÔÙúžÔ2~<@ï[t`bD;:ÎêHönãr‰³¾þüèáT„¢ãr2¸„Å€¯)vù*ýuD†J‰ÉqêƒeWÚk¸r¢d"gZÜQ_dø�� �IDATí4‘sCùë¡Ãí Xþ{³u_2ÓÏKó컀±ïتzÿîúü.‰'ÛŽ&+_=ïW1d÷/Öc Î ›ç½&å0¡¯'æ²Ñ÷)g>kæ ž×j•ÄëE®_$PÆÁñ}›”ä o·‘q‘½Ÿ»ýÄûmõ; l˜ÌÁÔ_K ö¤Úl}ø¸u¡íPR„q–Ö…:ózõ™¿5žp½�¦Þl5;³[òÖ®[¥uMÍÛ_Êßâ‘!Éê×{—«˜Évà µÕ÷rrÉ^û°ÀbÝwÇ´V ™ŽwÆËZLbqݯ¦Tâ0’‰³Ýï–×dûʶ3êxV_ÅT˜Rokåøê�x=?ŽŸÅü׿om.ºû²o½yÛÌ5ulä¨`·ÃŽ{Å€ªÌ?ñš¡ò(#Œ·³°Ló€S¨Å™ ‘1†ãApC øô Ç~ò‰~;kwxé7M#0h^7_îG|î¢gÇ{ynÀ¬}¾\µî‡} Š?/á ÷]’rh7±•s8»Ì03l.«™• „ù®Ð îõ§©þßËQ6ÁîK¯îÔCÕ‡]æ×bÈõ^ÚŽN~ÿjÏ®4`pµÚ“ß'(A¹tîö¯‡b`jãã̪/®Œµ$ ãªb~QCiCX)‰GÐ0wþW©O ëéß#Uœ€ÕÌ)øÓ–§¤çv˜%’‹Á:È~~-ÿçíÙº½Ô‡Ü±¾KÔTëËr©¬—àx:Ãþï6žsìúÕÇ#g:RFÖaÎ'lˆbŽ9ÆaÃýëЯXoí°ðŽ<ÿ¡{-:\3F[Vö6ld»_GG¬„çÀ–/§QÞaºÙœ/Øs¿r´³~Ô†‘òÑaÈç¯uÆ(C l®gn­Œ±p!åô>¼”cš;ÐÐ,à•IXĈg.·¦W‹ù7ϳL’€xŸeøû—›ÒY{UÎ{þ´G65Þ1É"kÙsÓq3ì2±8 µWž_û’‹op>¾ü\ÌO1"ঀ_쟣 ÏNâs~!Û;÷ãYìgŒ._ϳ{n.#4X_÷Œ&»®ú¡û~«ÈÕv?y©× d) ÞÞ'ž©…ï•~às0Ç÷ðÆ‹€pƃb‚Åzð~ò¶3KfÏmÅüyTÿ*·äÒèJêï$ËûSRe7àÃ×+á˜ý~ñÇÂñßåÃqz¿_õwÐ.P>w”3†Ã8öûmý[!OçðÜÑçðS*ñ‹Añäï {ÿäVë»—½ç¯fl¯çμè…ÜgÈ@Ãetì1ó5 j×0-ÐÅrG}‡õ¿ï{Ïi”†ëÙM–ý,ç*Ê{47ÚÞùÈübXŠýƒ¬{€¥/=PÌr匳k‡,3Ì¿ô?ŒMÆÔ›kñ =OØÓ Y[Kr>¶«fjUþŽŽÍv>îøF Pœ{mêº}`‚g=*mº�\G‡{—!6Äzµ}wÞПéÝÛÕŸñ\Zuyþ>¨¥Õ8œçòÚez= ÈFFÚÞ<Ï_íé–Ócέòy¿à}®¥(UýÕ~üÝ»÷å±ïý{t%Ñ(óKíOÎâ|gð2Ì2W¿y~#‡nO™j?äsù ”¹åb)éĿǦ!ó¬È-6]‘)ö/±}ÏÔcVG–v? šŠÜõ9Ħu_ˆý'~àåãØ ýHå£Ó«ý;ŒÙt(s(ñöu'h1¡;Ëv#P—M|­ƒQÇë©r¸øö¢caI>úþCI{_ëËžŽÛoÉvÛ/XÞìw^Ϙ›êwôÊsú{MFçaq‡·=~:¶3÷˜g‚T¹¦*Gv¬é«;ߟw5ý0íhL‡±ßG>'LüÝ¢ôc‡‰†€ÉÉ�of]ÛEÞ_ƒl¿&åØ~±Kß¿\ªTV(¦¯_¼^5Ž^Šrv÷sÇg|kä И«É¿'u=4cçMí¨ÆÝ.0“™b’²çŸî8žœ‡r©«% YDµfø®í¸îqíHîeµTn‡áÄr~Þ¿€ºÞwÜ*Pe1¼¸U¹”—Bô »¦ÇYÿ\s ÄãóÄi§ôüÓ×|±~ΤŽÅùûÅ-ÛžDbÿ ˆ¯ëùþc¦rÎŽRZâ3 0šÏžá ñ u¯Ï ]âÙ2àå~ÿ™+l2À>³Ø­ö`{³qF1KOÅ÷Z×TŽ,&AæÇ(­÷6rß¹Db=?:*áí  üéïîc@²î‡ž£ºòt%_ ÿÇw3Åêœañú ð®Û{…ùEÌiwoÿª—}ÞÔóiÍ?·(Ũ’š• =ÃzÞcá|d‚=½Èý¹ß'Þ/:g]Éï?ÛÞ£9ž´íØóªì±~{ÐÖ>ƒ3ßÿ<âó±ò*‰7,'ïW}~H¼Ërø›YçÐÂò0‡T—ÉÕ˜”û_U»k`‡—£žÕÏȼҀâž"[%UXµO1ïªëWžïá¾PÏÏÿ¶ucÎ6[­òS@k¸n€µVý öñ70¿¾ªÿôï±�°ƒÌ1ÄÖe¾bBJño ¬Y&˜=>“Tö/µãã?c`?aíè&Júdý!ØC„ë£jÇ43-Q±Û]„$DGÂw äÈà¥õ¥¬|ä¿(]޹ÊÁ«{£ŽõÂëpx”òšõ®ìà,þê1"Ý3ÎÔy%ûç:¯WîÀTŽQt”בž ØP9U¸t"þȤX­E�ì d ±O»Ý®˜ag³ÿmhFHÇ”D?N9Ê/ð»`ng9å¬4YÆãR8Ê"óm˜z^% ·Êe÷ÛI8 -Ãû‰ÝW‘içÆëàÏ«bÚ!ƒdÀyldH0 | °q)æPÉ'ì—«è_ x‹@}.!õ½¹””táH¶Ïçú|)Æ^Ï_)åçpÿå Õ{Œ0f§ d¨”¹C'&tÚsJÖ”ÃZÌö¤*� Ç·ð:g¹Tƪ ¸Ì0¹ù€še W6ÇáÐ¥æ³sëw¼ÝmÍÓëj;­Rûëaxﯫ课))º\²zÏLcŽBËQû'¥ÑæöŒ1i×Óy`3'H(~a~üº}ôsä²uv_{À]å ;Ñó¦i ÇÁõ‹¾‘í°´|”ù�H´:� ëÛ±(y<t*+Zä÷p&‚Ê ö]Œ5lïQ&W,Wm}ÀÖ>÷ë|üb8Å‘Ò3¿¦Ô¥/Ç2Äæöüû‹kóy[�Û’fTÏÝ6WÖZ35´ë|^s³çØÜT“FæÅ±ñ cþwñ@9»Îpë5óåΈÛcMëçÎë|cýÆÈóù•oÀ ë3Eýó©êÑÍ…ëŸ3æ*ffry�âyð/Ö.óï(@ «ª¼=Y3¬·ÿ½hß»ø½40ÈÓ>³Ç=ÉM<oÝÇ Ð<Ñãu¹jöE¤ÛÙÏ–÷[ñ;*€i,� ™YC¬1àD¯y½äº´¤ün;ÒóÔù?Æøø¨ž…̰¯‹X†Ø?Ÿ@×ꆿçþÉ9Ç“Ì�ca»=CJ¯‡Ò‰÷e¼={˜×bË>œõt7¿ÁUüÅ.à3ävßÞq¨úýßc ‹ÃHi›ˆš‰„õé3¦˜ âÙëž;v£'ÔŽ‘Š‘2Åa 4öŽõEböáÀJ^ÇE:½CQ=§=G4s`¾Áv&Ù…Ì!ýz»„lþ{"€5°˜“f|îcå.;./0À$íñ 8Ë%ÓvsìTŽá³pìâþÈ�š5ãÏ ‘1†ŒÆØc GIÇ˜ÛÆJ¢YFÒ)×2•x»Êá†õ㽬ô$ÿý1¥$ÏÐŽ,N 9»ÿ4è¥Î´„æ ×a¹ÙïÞwŸ‹ñ.'¦'+/¶.?ÞØö9¶€9J¤®_S1]/a\UAÅØõ-9»qÓþàdY{2±Ù{³gÊaYåŽ<=ïcøûÏßßÃ-ëëFëHÿ\Ërpt‘¿¯x5ð‹×Ï~Ÿ¸ç=£wã{×çd;ÎÈç%Яnû1÷ô¾©Ü¿uްÞ<èXx;‚ßß ži Lç¼Îü„9 ßüöxŸäï ÆúÑû÷IˆÝ s‚YG¼ tëÀ­çÿPļ"æJ²û#à/Uî¼î½<Z¦Ø#ã @dý•]Û÷ö]Ô×yÛ—ñP%ÅÔ{ÜT»ýõºí‹ç+Š$Ø}8¾·˜Áçôžß¾<Ü©çë‹í±Œ´X<ÎK#N{†ö¬õød¾}n7ç?½àÌe‹Æç-WQÏ“|®ìswä¹¶@aHÈ[Üü~•›ëÈ•ïöÒ:ªkï›Û£!¡B#ýñ‘1V]_kþü:'JÛùz"£ç½,­{Ÿí2Ȫëvëy-Ž›ý R»R€y ÈÎüïÑ•U€m”Bä÷%^g1Új ÷ö›êÿ£ý¨¶»ý„1õìWLª?ØñcH�m–÷‡(s‚mYÄ5ÎwçýcFAâÐ1Âpû� ìØ¿.ãrŠ)›¹Ä>~??™c~ü'2ÅTÎ1iêø ¬‚£ƒK¯T‡%|ævUn~¥Þ0Õ•´¢ÿ€ÖVn»/ÜØ/•4 F–bDfÞoeäå—£h9¸òHñsûºhžYë7·WÒdJÂ.sÏëXG’øGÆJ(ì�†Öñ=ŒŠ!æÛ—ç6¹ŽŠ‘t¡iº¦]ÅþxE`G9ü8Sì ÷QÜÿꎋ’Œ÷µU:Ú-sŒý.LRMg1÷YÎ`a£JÎØ¨rÓD†2rG¾6.qÆ%Sçñ = Ç+·Ïïó‹+ŸÛwuùzüóË#ê+Fé‰�tcð÷ gb!%-cÎß®‹|Ž8�ÚÏý‡VÕ¬ƒªb$1 ì û+žÚd|éúE&¨j×<"wˆžÅ}s'ŽaO]¿ûqqÝæë=åg€r˜rÀÇQ®Qš8Zù~-qZ½'gûX`Ê<ÿ4.tˆïÑ@ƒ÷qxÂ<pU ±¼ü Höãcâï02´Uóïžèãw@k¾­MŠ!Æ• *÷SøÊ·Æ\Rüz»¦˜…10©AgÿEë0Eæ÷FÌ…´€ Ìa@^¯ “Òˆ`/Ÿ€Ùíãòå ¯Æ¡ŒYaïg>Ž@hÎŽæûs2^*æw�!ƒä«_Ì2{ŸÇíkþf·Û€¢‡¼ÀÔ“zL²M[ס–×{ÿ:¾½êw:긯»ÜñËî?ˆ¿>ïÈ|š÷5Ž#Õó៫XÏ, •D€ÖåÀ}ùZ÷Ç-`ìõëJÞ^Ì1ÁÞb.1×O¾}‹a˘uY¿åå_]¹Ó¡½ @E¦þ>{ }Ç>Úž§nÿùÚL=^pà3•lñëTŒ™þï]ÝU;T=»Œ¦=ës93O@`éÔôzÊÈú®€+€iÀ:—ø|.gÖ¼_÷znUù•Q *9¥ +©Ä47S£¸þ`å0wÞ1ãkî¦9Ã*ûÎ_—ùÚ°ö'H'þýôoýÒŠ[öK¬ÿü”XTXƒ8vv ›(ˆÇíÝÀlj±¹ÄÈËWα‰ê-NPøqýø/ÌÉp‚–D`ìXäŸr Y‡žwLi æÈu³ó™£I§sµ(ÃÈvËŒB‰9VßJÚ‰;þ”äÍÝNá8ßßÖa9ÌqÖËó¨[ÿèì2£|¿rcÐùv8?¯ßì·‹¹»ß*ûÊWî7&Њ@›e´· í?ÖhôõË,c’0G¬h•ô*:‚PäbŽÎô¾ÐÀBì7Þ1û# àý¶®Ç™B*Ð�ŸÕ.=þåR*ø»ðúWp>ê<ÅïeõËì2.ò<8€ ²Qž_Œþ¹Š÷»ÿ]9‰ Œ±k÷ÛÈ™Fñ8Hq÷‡–§ÕÒt½Àˆú¾ƒ®¾’e&M9ëË™€¹B�sG¼‘ýñzõvf �ÔóÛÌòyR/R¯ Ýß xÕÆç;ðS}†Çöí¶ËÏ×c/æn}Ë¥{O#¾”e9hÞFÍäa-z…u<J½Ç:@ù—4âW®0ÓdHUŠ ÈL¹ÿßaU»ãˆå¾%ÛW}à ë9 Ë@»…~×f‰.£ÄŽGœ‰zL9~?W#]þÄ(IC›«Jµ°sL247>‚îK·ióÏiey?bÿi�f݇Ð2àìηë|€€ò’°œÌTû<°û({/[/›¯¼‰Ä·Ï¨qƒ”3°¹üÈž;ûœC®±ô~É¿ƒ¿‹Åë3MÚ¹ƒ¿’b«ë¹—Õï;ž·^½òóâïQåbâýÒªâvdzáuª Œz‡í pÝI:PK4F†[pñ~Ô¶7C«r¬év`92ݺ–KQ¾û»Ÿ5`ÈË«$+•©Üi`#Œ¬`jäðJ,s~ ´}ÀÖ5Êtû1þyúÓU,àj2ÇTn1¬Þd†¹åXÀ×W'z€ío�Êþã€Ùó @æ–ö•cì3§Ø”NÔðßa§rùØö.Á²2-™˜ißgðНù¡VI)¹j\gƒŒQ1Ê:×U9†j‹|¢È˜€Êû©cð‡L/ˈbŽyë0?}90ÏÛŽÉ#žY?Øòbü‡Ïå†÷ˬ|Žc©ÙU¿²~Ö î·£Át¬³~cÛ_Éù«5`Qý~™už¾°­¥Jñ~õåÖÌ8e€r]ßšñTõs”]%ðTsŠ—×utv½Î˜[u/­åÛˆÀˆ=`¶�«×¡ŸÃ3ÜWÆ'–“3¾”¤_>¾X&SÅØBf¾_”ôTÎôZõì0EY�ÈÜú¹ÞÐY'�F=ß<`$2ilŒüóZ1ÚíñšÉÉïåhæO^W`G[ïC=J!ò+oö„êó”í¹ãX;z‘í(%ÿðJ»sIfµü®ù(“¼; =£Ef{ çu~Þ«çýlÙqéöäÇ»éhÇœax½¬?îãô CfZ¼o2‡|ß‹Œþε9˜*`$ä‹�³—Vmxë[WÚOõ·ôîFŠóòºv÷7ýÜKº^ Ø_³çŸIæó¬œƒksÚ½Ž8¾Œ°Î%Gm޵P‹f_ËAzsûW9ºGý~g(‰è¤ýu®aéÇ)?ÎÎr3`¸óÇ'Ì;¶ß?ûm‡£Ê¯€ºáÚ±÷Üõ'áªñ¡žGpJÔ)ÉAÌÕô\ êºU¿ìæXâû»Rø¼Ë™VG#¡S¿ªÐÑ`tnµQœ_%íÉC°"óªÊÕ¥�K_®ÞŸ·§Ê¨Ù.`Ú5Åãå*f¤z.E;ws~—;ŸäC FZ>–Cr~=$©˜\ï¶Ý䳇¶¹bä2ClšdйbO?ï ²¯s~msŒlŸ�Ø¿>¯È–£šKE›¶† õ!És†u¸xoz:¬€,ÿp íÇã󸱵^õ¶àZ| _‹‰)3üðSõñÒ_Xº—<ê U�;n^:e™Rt`‹vDI6A¾ß~¾}1E˜#ŽhŒ92Iª*‡J<^ÿ.³ÞЙa1WU÷C÷¿‰uh ZîZSŽëG2 džÏ`öW±ž]‡åN²Ûc»Ž[v_iÚ¥õ<g×ÉA �TèÇû—æsÛß Wì� ì÷f€•®O^n„Eý¯wê÷Ñ$v%MÊÆ«Y£n¿ÍqÆš/qü²ãš=ž‡cÔ÷ãÇs€X¶séÇQdB®ñ8æÆbíE9«Ÿ²l\@G8{o2à/G*`û;g¶Ç÷8߯ì|¨ð‘1=Fì{Ýì>Þwóúùä•^1c:shÔ¹|”]Òõïs·Tìµ}×rÆb”´ï‡Ö‘,cã4vo |eäªcÜ¥_ÇøÊ!öB˜aØÎÜbàá½~^±ãj�)>_é3µ,pÇêɘ1h«Wúx!åÝM1Üc@#ÿ>ØüôÌ´ã~Öj=Z”¦ë”×w¤sG)>?»õ®ê¥s¥å~� YàÎÁ=c’yx¿ç�­Š`\Œñ¹ë0MÃfJ#®žôóí—Ï%J$Þ²çÜ1Ã|;ñþˆ¹þfÿ©ñag¾Õ¾ž“”Ùw|®»÷‰кOÆ Y{\%×’_ÕL®ýЛgif×.ð°ã~È>ÐZÝ/½œR¸«Êéùµ”ãU”Ók‡ÎÕÕ»>–£ë³WÞ®¡tg´.`æ{þznò~Q¿›>ÏÝ? À¸šÀÉ5FÏ7¹Áþhß•<l1Á¾!ÙcŒãÅûøÏã™K ˜cöâŒ1FöÏæP€lý òR¾˜b?ýÛ1þ$m=9–äûË­UŽòÓob@­5ÿr*ŽïšvÐÁÃ>ÞÎb÷‹zQûšŸd‹*à,öc.µ£úÍ÷×5|°×÷KÇA­RÓ¢¤c<OEØW d`y‡©Ï„"'‰ŽŒ¨#k}°f¨È8X¿J¯Eé9Åð’`5ð9ÙtæM¬[ ¯b^\Ç…þ®×2¿Ž9Ëú’C93ý¾ß&Ó%“Td¥Wn04TT@G¼©õÉìyÛ<m‡ Ǥ諸*²2k7˧®£�§¬}— ¡Ø®Àu€T@WçmøfêÏŽWÛ9Ð~‘Ï»_ç9ذ}סO<ðàå+ ß¾M`uú¾S–ßÿ‘áÆÚ—åàñãëZ·Àý)f»õÝ=ÏUjÞàÇÙ+À*°‘Ϧt=2Ã�~}œWÄ÷b÷z™Uf øÒ ªÞŒQÇsæõ絫%ïðÈžÃâZÝ7¥Dó>”æÅç5ï¯ÈüÀHÿ˜ûŠ1“²þÀy*›ÿÉ~úïóÏ\a·™3 €0{|@âë·˜`B‡µŽü®ƶŸ-ÓÃ÷ÄZòùµâ3ˆ}_òyé´8ÞÚy÷)Ì$÷ý|ÿí:èŽåôÒRŒ×ôüÇéSò`W·Üµ~½*)±üý|+Ë›v Ï…/l}»óoþÞ>}ÝçoÍó2{þlás8€“AõöÙ‚7³ÝÞ1o+l,�l®d¿WVé×&k/ÐOI¾ `]Ûc€ö{û9¨¸“þÉxÔ¿–î›KBèðW×=‰rðæ×Ñú�2… ;Áþ`¯¦|¦Vz9«Ï,<¦%¶/•™X=ý‡U{»�cÕÞSqV]÷]^·Ë�lIs*ÖˆL,*)XÙÆžþÏ –H"þQ”«l2ËÒdI»ýÿ|pæÖ?“!öôÉÐZ@Ù\÷€Ù*Ë£ÀÚ€ûd„EЕ7™aÌlù ÀÝ_a‹îvm:Œ+†Ïq¼úØVYÇñ‘µ»AVErõkªZËsŽÅa䱈têá+æÀâ¦û™KB°ßKîùzŽ�Š’RŠ’zÖQ‡¸¨¥í_ý`¯%Xö¥ Å>¤™Ö¿w^¾ú¥á–y¿gŽìŒÁ—1(T¿`¤±¯çÊ}“9Fq”c9ÃíW¹´#kóp4±a}ïW¹8�Û3/–«Œõo@¹rY«±|Û›¯°žµÛ¥û#·Ë¨óÊÙ„×c€ö³•Öd€ÐN.-¶ž1-QIžÉv5Ùãσ3Y=ùø wÕC C•ÃÆ[[>2ŸW`”Q¹½âõ‡;ÏÖS1yÕ!­DßžÆjŒQÌæÎ8>H¹ÜÃ×dœÆ™ö‹Ù{¯ËL·À`,×[|?í9†1ÐÌæz²óö·7nåŠx¡’Àµíˆè1 â|Øx·~¼[>âWŸÃúþ¬CæüV~¥ã@˜jt:…þê³Êìýe™ ¸"([½‚ŠÕ¸˜ÚGwœŒö–žwý—3r9üóë]]ù�`ϳÒoÞâÌÆ)•‹h—qy ïK°^Åq™õîGåÌŸC5ÎÔßÓù¸v<@µ×Îã9ȼeÒtžQÄûµf„áu"à5ÍŽ 7`Yæâ,σ|y–IgUHöçèüwZÌ6aó8þ‹¼Ø-ÿ L°×(™èê3>WØ8l¤¼Ý¼½ËÓÂê•¶öß (ܶö>*AŠ@Tàéæ<ëJÐõsƒáyU½Uý=·ÎßcšU̱Jjï]̯ºZJï{¬<kã¿×²®„a€Õ@[¨ì2½f{°«ú¯×Oýó»õM™Y„v(W—aŒay)Ðv€é¥€5UïtÿS•?'“k®#5%Ï[ÀYzù?"0öôo×Mðú“XFqq˜}1Å1VH4¢ñ‰ðÕD&³ý•†¨ŽÇ-1âõTçí8,T%óöKÁö"f:ò÷ /¨Óxö;*ÀS÷s—ó2m1wPúJ1ÃÐ}xýe½«È ›ŽS눎=-Ùeëoë­ú?ˆTùè89A?j€0þnȤòÛ3§$öòöTÏ«r¢Û2æ3ÏFèQ¿®%4óþÇûï}x�ëú?fb\ïÞ,УÌw ³ZÁMÊ;@ª˜ˆ™# 8<¾b¼Á×lôBÀÑSPÙzÚú©zôù—P>–ƒýž·Ý3\GC¤ù¸ªr>ùrâø˜eloÛaÇUß·¤Ü~ûò~¬s`qÉÇhÂïó˜Ëª–äTí¨€°P›Ì;ÏÜÕRû�×p”Å&cŠ…�� �IDAT¾&ÇÅ~©}ìïÐ…™ÃO×øÈçønäm~íâ’â¿Ûúý€à^¹×ížß©Ív>yß®p*F3ë G€×±f;ßwÖÒ÷9æüšŒ°'>S¹=Ëñ+›/Ÿ¾éJ2íTö³eÆ``ΤÛÈÙØO;9qª@ß*Ï8Ôß*Ä|GÖ»#L]÷Ól×PÚo1à Dµê¹Ôý:ïÏ×Á:\g¿q`x½ÙÞ†g¾1�» "³nµW.tÈV}nÀ�‹9¨ºXÈ«¾W†(Ï·û¿ž¯Ùë)æÐûð9מG=ïÃzøuÏ„ì>Ï\ ¤`txóaÈ{ü ®<“9`û}O:r(|´}¼þ•Þs�ªö˜cGÛ©:/•×— <Æpì•h½ÜXõõ¾G2ò¸¤b‹%í8£ ™Š»çcýv¥ ¿%‡×4”QÀ¬›ÛŒl§åÆ›æÌyc ˆ-Øýð t}2Áfΰ ’‹ª›Íe=ð¤%,íè|ýÍ�° ”¹mÿi¼Ì˜=*¥Øý ßÒª#ªrôð^‰Hùå­<~|÷{L1Å”äângçµ’¨+Ç^t%£cÓ^϶¯rdâõª¥? __v¿ C#ám½Ñ!–ýÕ„›÷Çå« ø²@ÝU”·�¥ø¼‘ëV¹»²~Ç~ÍŸ»1Çb&Ý%‰ÎÅý’mÜÆ2¹ƒAç¼´ÅÜ‹Ì3X®ý¸Îê› ™!S ·W­E¦Ò)ßö‚ˆèÙ9/[·Û£àPž#m]ß;.V1?e¯o-axi83JTžåóÇsß*02¢,#×±õ;²ñ&cäTã w¸ê\zj<°û¯0zÇ[¦2Öâø¥rÅôe `÷ãÿµY~òeÌ)æ0º’ãßD9ø^ç€iO¤–fdÖèÔ‘ùåKZõèÏœwìE,k‰ñ¾´ö½þ¿X; ‡ë÷3¿t á}‰Ê{ý„–åòÏÍt,{fÖPpíô“¼f9Ó¡l¯ŸÇÙzÙ?®ö,cÌgP™ô×Öu”äÜ‹)ËEÞ+=n¸~@ÉÄØ<cãuÙ{íˆu%¿‹‘R1Zs«Ï8óË ÜT)ºí®«ÆóÈøäÀ-ÞOpéëÜï{ž3 Óëküáý´žSU6¿±À‹ÀXΰñ¹ç»”'®¢œSù|ªr­MÉC&µgŸ@àûíë®^‹ËGýV ë‚•<EÀ`Ÿa´ÇüÙе*÷Ó»˜™"£©/}y¬»�’2ÍÌ{,——>^õ_u2¹üqša§�#u=þþÒ@(¯_Üï­~ž»€šê—ïž¡+C  2¾�Ðp…€–ÌTýŒ”"e´]?ÜAÿ&‡˜jöd‚M lgM&ÖÖLsþ?æÞ&½q]I†kbQ7Õ“>õ ê®à.¯WpjRu'½)?¦<ò7 ##2”êô›ËüÁŒŒHë–sc’‰Äµ6ÖÏ¿˜sì~ž#ÒêCõèmšiýoòˆcgT£Î$师İæˆYû¡w<Ù¸jgÒöl°ßŸ‘¤l ?@8âŽPmÖ±_ä¢Ö¡ã.ûµõÀvØrçöÚeÎØI»ªŽÙÌ¡«Œ9 <0w–Ž�U»>ØúŽQÍè‹eÝfÆj\Ÿ!íÕ¥­,‚3Řc™gŒÉæUl¯çze€b[(Ï÷êÙœ #ãh[ÿÎ@úh*—sÃÞnåÍ×?c^ÙÚzÀiUˆ«š;m˜"¦ˆÊ 7÷ï l}Mc­·;‹èF¦P-P!“˜ÏgŒâù-sÆ—wµL@ WÌVŽY¤lákj•ÃK´ªzh Ï†àóVa2°íÌq̶ÛóÚû bÑü)~Ÿp`Iª¿0Ǩ0ñãlƒíö=‚Œqß¾¹ýkÂ|¬~jþ¤ìîÌl‰¯©˜w(ˆõJQ¡6RGOqÔúéhû«Gù³)ìzN56PŽý0):àä™ êç©ÆçÞíK´ëÅT8€ç…?‡Ê‘õÄ~éËûÍ1½µ½8Ò-ŒŽë�2ræ;¹4ôß“(_3ÍüóeÙz-jóhÕ^(]D‰U GåFó¶ÆäÈ츴¡­‡çµXæSÕúqósÌÛ]cûv¾ý30åýËöc9ýªýgy<¯e¤eL¸ÈÞ G-S í䯉©ü8Ê,ÛyÔ�Jí8lÇ_ý<+CG¶4Úmý1óÏ…ò”Å ©O±<ÖgPòé¶×Éì}ë·ÊC†QÔy¦7ï¸Wý”iã¨rø~€—3„ªþ>žÛªÊÜYÍù•åV«%㺮†¬)ã3ÕÕ\n¯² ÆËÁõyn6<_m½ßþ¬€;~Ÿ¿ºñmíy×CåÚªæ S’‹(½¨r’©ò2©Ã_ÉrVOc$çXkíˆCëþk*Ì%vÂ~¡„bÑ~ÝsˆªOíï—)EsþY2±ï?w,×XbüCÖçÜXןGÓÃ6~kFÚjΕ;ájY¤Í³´Ç±¿61€?:œe�H¿ƒ1[k „6nb}dŠ)6—£ÇÈÐ÷ÏìXõ¹a¸D¶“ýV¤³Í@¯7FÄ{fB–hCf€ePxGe|}¸ƒ(úÐG Ö‹Žà*ǪgFøHpd ²~9€<3Œpš‘gëÉcÉ×+ËDâÌ$¬ÇyÚßÖÇ3ê*€î´û|+g–„äÏéGè0c9±ÔóÝÌþgZîY¶ÿy€àZîÐòõV�§·xÈî‹~Þñ^ôÀ àT­Õ¥—ç÷H$%ÃL_ ×ýÆÇw[ý~ëïAÌyÈs"àÃmk@yΨ›MçPûÇ]â€5ïªÄ=2 “ØäôLÊÙóþ›8ž1ÕŽ8¼F»xu�lƒãFNY% Wñ~nªG%Õ¸­ÏkŽÏœã̰,Å÷£õÇqnE™bv 2FÍ{‹ˆëvåXG‰4Îp`ó x\…œ8†�Ø—Oçœ:˾#wâ@é�•m§wX³~ÆvW–yæÈ¨\_ŽÊµÆSüw­Î™bŒx¦”‚¶ó~bûE "n°R˹ÙòðµZî‰Î„X?åÜÌl>ðÞ˜äÝ.®»æzΰ°«œOÕ{ô[/·3Å6xNxÀÎì°}ƒõóó໘ìå˜åž# »}Í÷1«/ Ì€¹ê¿è9œ¥m?Øçáh¥\÷6]'nöúÖ,4ürûkGŠ1þcˆ! òšl÷ë‘Q† *k¯Ëó¯,À§&‰÷šÎd6Ø?³¸ÑåÆýåç€PÜßK>¢ñ°@÷û*Ë™¦LåìúLßÇÎ÷,)ä¼<dÀ)†[üþÔ×c5Wæk­yFa`Ñã²ó+æ×Ë•½,ǘÙÿ[#Æ¥‡tb/îÊôÂÜaƒa¦$ 6•gÖçÖsõóý­˜e·ýþËW«G¦Ä€8ú´#¥fúö·€ñÁoÍ' ÿg¤Q°_ª’'=ÒÖO¤Ÿ+ã¼ÿ¼ãeûå¦"¯myÜaAݲû%±gûǯçÖ\9Ò Á{Q=ð“EÎV'Þ™#tv(nØØˆÙöoÎÎÎ!ÍÄ3c‹ÛGê(žÆÊ4Ñ0ó#Ö¯û}|ôIÌ£ë¯ÛŒKeR¥-)OíÇú^ŠUš9€íd×ñ#8J!“;Ä5s‹;¶�¤Ö£äf£Ï‡/¿ž“™[l¿½y¦+l1 `v¤]×+�¶ÝŸûv–û÷›·«ño>_l3Sï.±Õë‰íµ÷íï}ß.ËÆ@‘¨^ªþ«¶>È™MÅÌÛÝûMÝOÐd˯2‚ØlÎŽÇçûó¦Þ'}¿ØT@ˆí¯¹^Uæ 7>/ÛÝrÜC»œ×qÓYœ_ß_:ÇÚJ½ºØêóVünˆz¯âv®œu^æ’ˆŠaˆÆ¤çßÖìx€9y暨ûçEqÀ7Sî‹ tš™S³à¸Ó´_ä—ç½×w§õgWïhÈøB€O ï°Œ’i³1&Q|SÀ—÷lnžÕM}¿Ä¦™#kŽ\ æÀâ*³Â–wTËS�Ûå°ƒ(ddy{K–»ÍÏÓ\¿^þ;,³þ<‘þÌ>fÀ¹Ÿ×çë¶ßÆ‹|ä}k ÈëßÍïåÖ®qG©ùãd_�X½ÌãÖÛþª� d±qëǬçÓ¹„cDãuZei=n¯i$`û£ã< ¦Ø£Œ-n𬕯e�€*ð†L9­ÎˆbæâhŸ*+î¿м¦ï)eË\ùR9ž‘˜ˆ1à£ÄU¦âZ;T}ëŒ9,WSTjíE«_¡aî-d\¹À0¶dS.2ZŸviö­Ì�Y¤™&×XÏA61É\gÎ9ɰ¼_cì—džý Ì´xýûÏL².•81Çž y&…g:ÌÛëå]m[óÉî©re­ŠØdÓb? RŠÖ.níh¶û?jñ‹C3ïøÑ³U>¨IèÏÂs,èþ< ‡P`’JÝ¡¥�]ÅÂrõuUŽDŒÐÑ:ÚQíïL"«%ëk:È�D‡¯b´ˆ;f½“Ì™•çžÁõQ¿ ãºgd#s­Dc¾“eLi÷ÙÍ:P<ƒ/bJÍõŽ"“5°‰¦%ÿÔþ5�KmgQïy_)fL&)hûï\n?ÖËî—Kâñó}Ëœ}{4Nªœ8 öë¦s_åR…™´Sm<ÓýbR%ëdD]ۉ̡ „ :.Å—3¿V€>5?×?—°C¦ì*3a66®3@t~[Ó€ гù¦oUN0Ûì¾^‰ônn¾em0½Ôö&ޝA:ë¹kô|æ™–•¬FXÛ~~v Þ7˜l–Ìæß§‘ã´ÛÌlšŠ°±¹y”ÔtƤŸ—[kC2ñÆø:uæ×—}O^n9Åf§‚*Ž~üõ×Yç"ŠŒå`CÀk®¿·5‡Ý 2 ‘µßØùŠÿ>ÿ(•ƒíÇúûrûÕÚí¥ùþZ’Q16±¿j¯ÿÅýbýÔznúü¾¾ÈXì¸óó3ºþ>’…üùö£Ù¼$rf@Íå–AåÛÏÛÙ9„¯€Ñå¶|º•£Ÿ¤Bý l\Ë4ÝÍø5®‡ok•ûÐ¿Ïæz*‰¿Ï‡ßxYÈÈ1ÓŒ˜ÃYyVÚ£�ªº`ß?cäq�¢ÊhÒûÇíË®—o¯µÖÞ“ 8{-hÂþUÇ¿Âuô–õÕ”ç7¾~°¨˜k:Ç^Ö˜œU{MÊñ�³µ¬¿_ÓçÌž÷(“îqÃ\^Ý2X+®?”&ZXÿnÈ4£€J öe`MÀÕàºI*ºê Ô¢îÌ-fªO€2¬ïÍþÅO`d/ÿŸ�Úr©eè𾚈̘AÜꟿªQF3¥äõÇ’3#<Pvµ“Ûέ:±Êêïùu\zÆGDÕ,‹ÏЯu|i¦ÄÕ2 >{\L�çÍêë‡ÂQÏ&[³Ì›­)æYsëUdmö!Su<p€ûa®ŸF+¸5ÎXQLž¹ÿѱ¦�uÍ6;tÑa”ÌÁÄ¿3¨x®JÚM1ß´D“g¨ØëGú+ÉÀqžÅpýäšQhÛáÛÇ™bØ#©5PP:Q¼žþ=0ß¿ŒÑ‡Ç# ÙÌ~WcãÒõþò€ exæúsùLŠ´o¯2™b‡Èz@�ï_ÅøüŽT[Îx~˜>‹ûæC:”²ñYõ“ÚŸøö=¸OŽ{5ŽeÏãú²q’1ۤßÿ¾¬÷×ÕÊ‘”³ póì©ã[-³i{> ì(S>Ìr©Æý·:_öóÍøƒ¿Ú/Ny™7ZiiÝO±]ȯr¤Úçe“ãK·ÙÑ^U€ØÜñzÙœ7È f¥ÅòñOÍW¯ï³ôõe”BDGö\ÿKãó8•ÃlÎí3“-Ó™ÊÁë¯s àõö÷QóŒ-%釶 y©¶Ú—ö ¾,˜ªŠÉ†Ì°G%£z;=€ÍMeÃ,C´×Ó˺|h2!ÙzfÀÃþý=—Ïrq©vÛí1òwn6n½ IDšÌþŽ~³�"+’ªÜì8…@ňÌï“Ó¥¶^>'X ×kÃ;Á2µÞo¯ð‹ÛÕʉó~>Ù­ƒh=nϬ HÅæèølµ7ѧ/>Ó~Pí©j?evTž›5©Æ* ™•£ë[ë<—Ø1¦™Îé¦�C»œçðËl€Ê^ÈÜ2R†(­X(?«_57Y–£¬µ€cVéj�ì»ßß.#sLI3úå”Àìû`†%Ò‰3Ù!¦"»"MdkÜá³ FNîF˜VqðG#N³¸€¼üìC8޼­Nª‘3£¾<Ç„ÿ,PL1•£âO™FШJd)©2ëÀ³C^˜ƒ ïGãMCÈ;ªcI,n»ø€fýT•æBãí±ç÷¯ÁÑj¯ƒr<[Æ{9ख़H|}“ë±¾èàe®*ñFÑ}ØË÷ ¶ºÿæ˜0gúí_ÇÙ±Î�ÞmÁñgd (¦™Äª–lbÏÀì\ŽD>\ýš)ÿÃx^œkV¤0ɻַ‚Cm¾/ð~f@n (-:R2€Uí÷ËgÓ¯lbL£]–‡¹?äxœ9’Øþì¼–y믛Äçöàþó²5d~"PŽÀØGx=Õgû|¬¨¶>j¹*RYe¶3;¨vñî×v¦ÎF·55¿×óþGÃŽ/kËEüÍ9öŠûqÝ­%4¯ã£ $©I‡fvš�βŽÓJKÕxŽGS¦î—h×M2ñ‚û½ Å œÐñžX€Ë>oƒ‘[ur@`�ZJKc½½}ym^mï¯Mú7Øwæ[;Æ`ÉʵýÐ÷SL«Ø¡¬bu& wXfRŽë [¬7–‹íÙÂñ!cPÎ�¯µŒqæÄµ÷qÆi^­oö]z2ë_M‰×íï·e¤wæ2À¾ØõÇ£Ø.ÐþU¦ÓgÚ?{8ÿªç¬Çñ-™ÎGQX;Ñ­ë;h½ž x±ËÝ<`Ö`;·hæÏ± d¬2åíùs`ìØÌ-—H¬Mk34uÞœ9–íg÷÷À_\ïO±¾–¥b5¦ÖgÔ—?ç¯Éöõ™† ÙȽV*—�R¿’í˜"…𚤠1§˜:Ök € Ö«eV2ñkHþ¼­ûyß™Kö­Øúõõwg‚©ãóLí×»2ÃF3Tî°¿¡¼¾ü¯¾üòï–G&åæÃ”TE$áó(þ­*vM—žÙeIq?tˆ«uXhÍ‘£&ä [Äœö ¨\nôLtô|v<呹±£{8Ü1r¼Ý—Ù}Î�Õúh`Ltä¢dq?Øönä<™”mGnoâ×^üÀ·Òsx}°à P™¬ìzp .<¿ÏY6¯ÚY?2`A}€e¿ì<(‘ˆÌ</$>'ŠÞ?¨£€ˆÊ‡'Þ·9¾µùyéÆðè>ïÇõç|Ì2 ²Áv?½ÌŠ÷Ɵ׹ª¿U»¤£3ØŸ¿ç?ÒãùóƒÛ} ÃÕ, ‰ã~ôyˆÀ9:€íó{ãrÞž£Ì´xÔEý÷l®ƒ–<»ñÄö+»>×lÑuçûúU�éHR™’*õë,yˆL¹gÛÌDñã¤Êô<ò9F8o<A{µ„÷Zްìs½5ñ~4/œÿËê¥Ì—‡9q�Sý¾ä† ¾î ìÀX.˜L©ùB%¨\³Dâûô{zÀ¾/;N"ãÕ% „Ù€<üú—Í+Pjnäp²õ@JÊy‡ÿµ´0� RæT€ßŠÕsu‡yí‰>ÎŒQfGÔg•¯¿§ñ|k#™‚S€ÞG`T�.Ö?þ>בíÇr¶Byý¹ðýè×#£ ­2¯ê9µ^Û寠ò-°í;±rMŽ0dˆ1Àp.Ÿ{öÍÌúy˜Ä*ï¬åŽun€SÌÌÇCZ¸q&Þ1GènÈ<ùë5ƒ'â?%@1^Ž1ÆŽKÆ€H{ÒþUæY}¿ àÉf˜¶ßªL7_J8býð˜µûÙÏÕ¾´^3ùù™1ÎV;\~0¦Ï³µæöêRˆ”QÕ°`aΰÖ$@ö,¦WUb1<p¸<3Ä~À¯°°ù¸zùS(»J*~@å%i®2•kì»—pÖ™aÿ‚vpiÅ¡Yn_ó‹©*ñƒ „f~%×V–1šÔ²rP´´<_\¯uÏE¶Ê{ÞHö÷Þɇâc¯ÁÙ±>3¨lmÏKÿÌ’eM8æ91¯gç˜Kv½r¬"3â ë•ÙFÄ{æU,%Uq”cÿD�Q´ŒíŸì×M–g¥G},¸‘ç‹ržQ634˜TÞQ[‰Ÿ÷¯—3`Ë€¤¨SRI ‹ÚetKÀÎ|ÔÍõêoÁ¤âèÞÅò\æHœËaÌ*0úþŒ®cne¦žËÙr@0·è>òÏŸ'ô@„ˆ¥r£D&óõÐýí™h¶ÿ²\dÚTÀgŽ€ ÆÜ˜ÇE6ÞÍ�2ìTÿØv«\¨ž‰Ë�elŸzNÇ8¤CF=‘Qm÷Ëç“s?ídùŸ0Ìm»ÁˆËy�תõy$¿NÉqÙ<¾ŸZ1þ›…YεøhV—Þå~j>«Õ€6=¯¯CÙ}¯�û·ÖL°¾<;¸gï[»`¸Ï-ûqÒ2¯öi}ÿ«””!S ÏÇêw‘w<ûQ–jéK/ ÍÆü¸{LyÅZÚñèäÚ}Ì‘å˯ÚZ„úº”£mç ÚÔ1ïëU àõœ¥FY½V™G'�¤P›ûÆ}ÁP£ÞÈ Ìýù¹þl¶ýŸ÷õƒ Æ{¦g–;ðEbúþ´@%Ï6Ú½»ëÍÇg©ÁwsžÎhBÿ¨ge¼«ŒC+¶š3ˆ…èØós©ÄÕû™- È�(»<l(¬2‘²ñõÑО¬žµí°¤«îŸíWõGâsSm?¾>‹ó,/ZíO¾œ¿÷޽‡•ÔäkÚïÍìçŸ“ÇæÞâç8ßÞZ�UÆkÀÌê@Z–« `ÈËö'aSMgf™ÔÏØ·Öàõ lèÂí!ö]0¼î¸Ý‹Êñ%ÏvÓ/,Ö{)EÅ`~5ñé¦Akòμ©I­âÏÙkůç ]û®…3V-KZÎUj¢ð8ÕœF6ï¢ß@ù>í¿ Í™ã:rfÏx­*ökµÿDzuLk�÷ã¨'g„©.(Q•Et{� ëÅeÛÝêËQ»";Ê4ãÀb0x@¯;r9#älÖ+©JææþŸ1/XÒ®/õW-�¡…÷!2˜èÁó°û­rýú~Lày°^;,G’’oä|ÝfàK§5û~àã‰oÔ¶¦{Ùó®4@(`´®–¹ùÜkŒÉê÷ç’tÍí@F#J“áó;_Ÿ€ì¨í~áuaýšÞGx]-`í%>é&M“Ø.Ï,Xm_•7—?3R9à ï/Ù}æãš‘ÑÓèòñÏ6ÏH±†ó¤fößÅ~«VÏ-‹ó„¥rVbGÝ7jÏcñØÇ-ÊyÌ€%&µÉÆ@¼{Ð:àg‡¼b*ôål¾0×#{¿8ÆW—F¼3+n¹Â¢ûhežàßÓQˆ™TkÁzÛ϶¿|N«nãü±#|”1zró90çÖ«€‰ÌT}G»•„à±/€ãíçŒ,Ö%Õúç8³œ]³t¦:Ï Þ÷_ùΟd–å©3,�<ÿÚznæ·€Íçe¹¨l}.‚Iybå}‰v½èç\õ›eŠŽñyûçve¼Õ�‹¹?ª™lҹŽ2’úú5ù5ÁåGýWU†Î«\ŸYMœù³¼6ÎÆ€ÌŸ²:°„ÇÕ�Ãã3¸¸¿^Óqß–³ž«ê(0U áŠï—uÉR^N~6Øëùˆ‡—??¯b^àë¿·6�*” œ,ƈÑõô¢²_ÅrÌþ ¶š­µÖÚ·—ïíçË¿[ûúu¾~ †XUú]]âðºß9ö ¥ïgù[•KëñKr ­è÷W@Nhºm¥ ~kñ‡Æ0.…´ ¦Îø0{LÒfýuRÓLÎˉ×ûíë¹Z›¯‡e¡ÎqIÅÌâ–ûiEy®‡Èbé&½ž;Jmÿ´t¹ 1f«G76œW#[m¿|ÈelGä�Éá-Sl[ó@Ö?j÷ãå¨çCçò™q\Úðg¯¯Ê)Åeöx(*Àª)Éׇñqc6ázè²v±û#»ß+@_´ÿÜOÑû€;8ýyÕý�:«@ƒbàeûG@`å¼Öt®Æ«uGñÎë²ððãÄù¸3 Ï¥ q?í ®öï* mñqvÿ1÷îÌlÄ�‹ñ–<C¿tS ¶šl6~«qËŸGK?¿Óý:öC`”1ÃU}ŽÄþ¥{ Û`þ’ Õj[–cÃÏóªóèµù6Κ£@ŒŠ©~C ñOa³´æõ—#~þžK�3æÄ|»£ÕnG…”Ûé¸ÏDæõQ€‰ªÿ{k.wؽþ+ÌýýÎíÚ'ºí÷­ü^c ¨b@ÂØoãÍåëë—d»_ÿ‘¼§ìwñ.¾G²ódŒÃœÉÄ-ÏY›¾¼lûªíôøø\1/çG¬w³^Ÿ§ÂÃûkUêðÒø¸4Ïï[ï/™ýFúºià/úÒˆWûœr‚ufe½‡¦té‘P�� �IDATò^ ¿0‡ØË`tí²Ýó¸PÍuU‘`TýšÙÚüž–þüñ}Ï€ÊÖæëÃîйgø4îŸç…pÏõZwôoáz<ÞŽýTeJµ¤œÌª÷Q•ɦö³÷M Q�Öcæ{¸]õ“b@f¹ÃêfûëS>ÿ;Ý_Õóq«‹«ãU5ùУZf{˜  -“,,åæj‘†?J8R›Ú¡r¡-I*~ûºF/ßÛ—·örct}ýºe×’æt� ¡k�ð�Ùmí¿X³’Š_‡¹ÇPBqj.,»œb·ò”VµŒ»ˆ‰Z…Q›g¤0ŽçJ-úÇò(´µfþq_üzrj-ýÇ×Çö¬ÜcQKçõ { 8‰¦!LrJ·;¦’Ôí PwU¯L:c›9(·éyÃþ°‰L2é#u°b½ð“1“0K¸¸°þ8&˜Xä{ƒeÆñ@À‡q¬GýˆÀA Œh‡sÖŸ‘dœ¿O?äuÌ€›–¬G[e²DÀÔ§úG}ÈW%ôjíñ¹“²öµd¿y»ù{cfrµ6¿¯@f÷ëÇ @c¾OU®¨½Ù}[�œàó’òU†cød÷9Jn�p¡£]h°q¶p´æó*� ß×+À€eÔ"€Kõúϰџ†ËJü¦½ðâÀÌÇŸ;_DS¹ÀŽÛÚ<qO~ó#cÛ’ìg ± Sßj~SÏ­V}´f{¼r”ǹÔð¹PÏÕþõ¿úöÛ¯bT]nŒ±öU¯ÔÆÝ°A Ç5?‚¿ïGj€Þï]ÚП™ ¶Ü¶s„E9ÔÙ÷¼gc«ã€‚¸ÑÆõÍ nn\mþÍðÈü:ÄåÆýø»jÈüb ÐJÀ…ºo²\o E˜•6lAy|Þàx6.œäq»;Od¯ÐÕ[È™`9G°`Á|èë8lçþãˆUXB[áI½5ÏLɘ*™]’ßUûLÖWó—{Ü<“n^ŸY.ñWøx—÷S­|-Y—ãï'f²zÅí¨2T}VžU©AÏt«øqyñqê9®×§ïŸ®Ùöªa;†¢­˜Äç©Þ·véÃn4××$I¨¬š¬ÊØú%~©Ôco`ÃÜghQ±8ý¼c?Zkíå{ûyÌ®ûüÒÌ1 XýòÛo{ý«3Æ®û\cªüõî#õid=ÿ0ñ‘o¸<OxPÓšíß-š¸#£b »Öñ¶ÉÒšå¸r60û$ÜM¢$oð·fÜT²Òã’k-ß¡w˜(ïpܾ8�gŽ?]÷ûÝ`?”üŠr‘Í€ˆrØ¡ƒÔ3$të«€‚8æß™¡ÐÛe%¼lÿtǨ—TìÏïp|3†{ŠªÅÕý³ýæí3l®¯ê7�~fG¾uÔZFö"Ãjè,€ [±Dãì°ftÌ!ŠŒ—F÷SŽ´sÉÑ5—¯Þ À²÷onG*~ß¡Ãïq¶«ß/hÄœvÞ!Û4oPŽ[–ñi…;�»˜«jŒ¯üú±Èu.u‡õˆ™‰Œy÷hà@æ˜a€›~ÇöÞö׎,‡Vÿå�¬¿Þop< ¨ÈÞ¢>™ßþ&öM1 ãy\<*Ægè«›=ØZ†{ß²¥óÆÇÌ»ì<¯žs#–‚^exÕgÅkÄxä ¼çÜ©€�ÅÌ´–1†æý,£B‹`€ŽZ¬o<ß¼÷Âv Öo°½Ãø´ßžkÛ.ü˜ËãïOT±zŒúFl•À•“øõõÒͳüóu†å£©Ö.òI?Æó¼f2{>ô=—{™®û3Ï7Ú9Î33?/‰££™E3m»Õ~o«ûuìÏûÏ—c» ”ÞÓyZ@÷y¼æ\aîOאָ‹Ð^níúÊjï)Pã˜íßÜl½;°°ß$m¹ÝriµØ4 14u¬sOÓÉmo°¾f H¨÷—Ê1Æ÷SíV�ÓŸä²×ÎWc>õUÉØ³§ TéþŽ©Wqü§«OÆ\Ë$ Ÿs3 '²ªçÿL·gýÍ׫R—«¹ãz?Øß–.¯ÝçžöKlÏŽS–•k€®žãL™’HT�_g˜Û}kí Í’‰!Öwš™b/ßóœbj}g~]s~ æïþžkl0ÈJ¹Å¦Ë ¤¡^8QÉ"µìq™_ýÅÆsAŒ³ñýÆv”®«dúñDÀ8&ƒ“õᴚ늛ŠÃQ‘ÆÏŽ×ѤMìÇ—£ ZÅ1ª$HÔ‡¨ßO1)4°Ðç��e‘¡³£Ò31ìúÈaˆÌ"î@ø�‡„Püylû6R>ö#öïs¦n±cY÷òæý™c­8ÇYFš–4Sý3‡Ò³ÈØØšÍ7$5CÅžçìú ³øc�WÄ0›¿UÆW¯7Þ·ª¾ØŸ¼=Šy¤�ž³s¼1›)^? ¤³ç2 \Øzø\h*7gèlÓýe™±4˜s¸Nׇ3æwæP‰ +ïYŵ@$J4³žI®±ëëëÏÙ‡—3‡³Ú£Ï8–"'2ú"f¨í4dúzõúãuÌVL»+ªó7>OôG?æ�QŒ°SóÀèu}?.“|®õÏh¼ß.\³Y9àåézbû<Ð`MnÌL -¥™ Àh®i`3¯ÊÏQÊ^Äx?1ƪŒ/ xÙçf�Íc=Ö{eüÇ�NTZ�M1ÂrOÿ•Sæó¨ùAX7æ‘^º[ÕªÂPÉ¿ëjÌUŽ>_,5ŽçûÕëåaý,t*;ìjçcŒ6õóãããf¦Y Ð�*ûtÃç£5{Çíç³€Ûæîÿjà"2¥ÞMËu¯àk þúÏ@æ|ÿ2`½áë‡ÌËlb�Y•qÌÚ§ßGk¡09“¨† ð'øèó­�pU¥3ñçšã½*ÑxtoŠ‘”1Ä8�¢€ÙÜj 2¿¿ª7^o[Ïjùú~å×{±¶š MÝG¸ËïÕÜ—kLmoU¦åQFXï[¿O¹} ÈO�­€IV•@ÌÎkÊ r›Q#Ì/À©ö�î9àç¼ðE€¤`vÿ½WN�VˆêGý+ÎÖ³!¡–ûÝa}}—j4’9 dMMl#Íð*Sàj8ÑݾÌwXûc0ãxÎLÊñò.Þløñ¥f9­TÒt|aùjjúr(Û—·¬Kv<â(ÓÀ”¯-2*ìo»/¿‰õÖ<#€/ç^t„g†Œ!Û ÷›b5S.:âÏàˆEfK,µµvœ²§q5‚O_1cMç0ccdæy©#+eÙm¾Îó}¶C=bLZ/Ø^?®Îëý8ÝÂû'âl¿©þôÏbÔÍýÁ‘œád:ò@ûÝÜ󤘣œIãsnjǶe&âúv»^£^o;O-°†LF p©ëX]^¿#ÇÜ.mˆ¦€U¡Y t<o^J”©cõ|ª~œ—ÙçOÄ åûzq¦ÚŽçï5|î·¤½Ï¯EÀÅ÷Ëu/ï ¿þV?×Låüª2Ât9*pç±yò‘=ž{¾Ì@m·{ wMr™^ÊmÛ™"^qµåöx|›ç¹3·¾²Œ£Þý¸™ùuy9ßçï­µÓËÙ/›÷\ëkËŒéÄÇ%/…ÈÚ‹Ži¿¼ß˜7–ÉãmƒóZå”Hº.,¯¦³ü·2êD×w¸¥Wã[X^u½·þz ÃÕòí÷¢g4"3ìÑ‘†+êèz;¯‡ü÷ñ;,w{kü>ïÏKa×csëçqà´Oݧ¼ãÊ©í¤<Ã�‹€·ª] ‘$ÀÇõgç̈á�$¥ùÀŒªÃ|-—’fÜ`n0•+Œ×W[\¿\êËY¾T`¹ÚQŸ•wŒISôùjçÕ@šµWYnmÜÓ ¶ àËÚ[³ç`x\ì÷¬wþü5iÎx{”1¢«å¯2ÕX¤Ì¬É¡U’L$Ì®%©Ä xSûÿJŽk+ÇuCIÈo­9©Ã·m?æõ/ßï ²ëºïwàì'�a†Y6ÿšõ÷j@ޱ;`Õ×w†Ø`Š©ò¯Œâ¼(¥ˆÝ>;üv;¦!ΨþkÒF^Ã?"ƒlÍÔ° ’§{«Q}³ó¯Pµ´_Î"Œíò³­úš¬F^W"”+÷ ¬4ÎÌ:;àÀ:èÏéùC Úæ@dŽÏ^ï @=LICæõŠþàV &ÅÜ›ýdá ð\m—²ÕˆìY2N×O]¸l=�6[óýÌ.{IVRo¾N–Y8ž¬Í@c¢h³íAIÊ@Ï,5ˆ�ÞÜ£~6wÕÈ õaúuw€ öƒÏ­Å5^ª“KÞÍÇÍ×m‡òÚtÿÛû#Ð}³ñÙÙ")»È2@­z3öYÀ€¤ès˜1€½Ô(šbüq‰ZfŠÂÎËêÏÞKlù­Åãm´y'Û™4¬bØÎ¿ŒI;·óˆ1))”àP¼†Ï¨Gd8¹�€Ÿ‡Õs^Ù~y®í¬'Ó›3lZóÌÛˆ©ƒÇeŽoÍëÛØéŽÑZ¿Ìï…L´K"š_rü œ:�6Õß�d·ã.DR‘Ï^z<Wµùðvï'Å›×ÏÒeïÍ*›Ì=¥0TNá¹Ê*�HmþΙaÏ0Ô"ðtôyÔ€|Æ4áÛ RR”Gs…©z ðD@ï³Køn-<¶Ë>¿±ÞèzËÜŠh5 …3úXN­Ìæçô³ùó÷õÙ8T½ÜÚûu±¿ÄæÀ·[û ïíWõáÀþvkŸuÏ¿+ï…nz\â÷©r(Ws‚éíö‰Íæ/Îs:€øz¯Ìéûy‰ºŒ1´æQÔ¹ÈÀô¨­fÊà‰ÀR­žê¾PíÍ¥•U™b›ø= =7�Ì—‹ýž1#ããÑr‰Ê P‹—ózÄå¯çN¬J&þjæàÊLýŠöS9¼šÎ]¦Ž«yÙy{½E ±;°Õ™`7€éçMB±çC‰Å1#,é–i¹càúÕ¥‘)†Œ:YΌ͎ØXBQS*ç‰MÁŠ”±Ôw´øi¦Šx}NÒqZücÎ'¾y$ñÚ€š Ûžq¡>¬øúqÝ8³¬ú!ñ¸Ô"ï¿-q•mä?´Ê„>+~سÒçˆãÙ1ï™8 kM9=°¦ÚQq@c{Ø4Q•£$°âÈ;”öóŒ”þcRŒØ¯s=s,(@ÑKºùõÊj€ŸÞKêycãã^(ÆÜÀröÆ<xF} ´Ò{>ß/[`iä^›×xŸKÒ^¿œQùÞø8É=ö~Þ%ÓŸžkp“ï¯빤æ²cã?cn0Þ c M*ŽJÛ?¹dÖ*3“gûÕãå¬dè(ç£4ŽúöÔ€+%Ý™¹ çýC¶îPÖŽë^¿ˆé«úuî¿Ù6ø¡ß/à]²ò{ª�‘ëÞ;]¯fVºµfó§á:'ÇgOI†çý®îØ8bv;pEk¦¤®=cúzvØ1g>Z›Ý|||‹Ÿl=?Fé>ë˜Åó°³(‰2:.ñ@ö}†íÏÆõàË¿·|N¤*³mþí™È rýÐüwï ÃL9lCFŽ4Øßǘœs}ÞÅúëoõ9Œ™Z¹ÔYÍYu˜«úåçµûŸÊŽOn'Ñ/Lò±`<V—i¬^‚¬¤ê|3fS&q8Ô(=Ùs™±ûJFÏ¿¯ÍJ%úú\ÒyæTÞ ô×KXï´ž,Þ ”³ÀÈ�¼ãE¨ÛúÕŸKTÆŒ›*¬º=¾VýG¸ëÀHüÜ{)¼C¬Î0Zc²(fXøLæ]æžóõ©†ìgõ­z®2fÚ³�,ÐêjíÊöSçÏrÜ¡å÷ QdÇ+é øÊ�и9�x軂0­Œô`Û«”C,`rýb¿}ÿ…œaGdÆî9ÄZsL1ÝyÿseˆÍ�Y›€°n=÷—B„å_bù~n�Øw/™x=gãŒt›io‰‹b*âÂNfË>(ú GÔ¬Z»θcö¨ù×&JépMü£L±£Š°sä?¯µºdÏ–ÿ¬z"#Ï:¦ü0ˆ@ÚºeÒ/ö|Öd„.aäÍ{v\•VaJôã0Þë1$lº˜1?×å5Ç«*U„¸g0á~–ñ3Ÿ0IªUúCõKKÊ‹÷ÇœW>——RS¹¼c9èg©Ì®8þùz,ßÖ›å8jmH²yiD”öôçm<?£_ÃþFàš/k©IÎ<Ë~äÒw^z)“Þ«Jʬ2À•Ö*ÎQe{–!X Tàç«ÖÏK2`Çã™Iõ—Ú?V3 Ÿg^Ñšº}.IxP}Å`nnÞ`÷ó6¾žËdò ‡,Ç.+Æ^Ía®>w«Àì°Z$©š—= ËÃÌÎ¥ýg;:ÞÍŽÉ.Èî”ÌbÛ; 4ÏC²ú½µæ%ÑÕ¾r ÆJžùõ™ÄÿüóŽŽüý¶ßëû~^¢ÿ½YÀÀÚøëqiø;~�Ér,±ïÙû)©s/-{¦ãîF¾ŽØ ؼ5&a·6¾éÔöwM‹AÛñÀJîà>‰õ«õ˜ŸóGêÇÚgŽÆ=R#€</W¾×£yÇxnøu½¸ç'þ®ùLÖ¿ÂöWÉÁ5=¨˜_È {™¬,�3־ʸ`Û»ßÚ…—ö·ÂŒã㟲c !´:@vº­µ¿ë¤*p‚Ëü=;�´ÌÖ—U¦Ô긛IÍ­…Œ¡4Þëâ¸5€Æµ�Šõí1SOI<f@É«\¿C²š+Ϧ€èŒ‘W½ž–©âƒkŒÏŠé˜µgõºÛã�¨¯?–[’@ìÖVA.1µlŽ/¬/•×’`d}XÖÃ0Ä€Ùtµ6˜bªœ—ïB2±i ìåßÍä»d7Àë°u¦2Äúú±Ë7ç=2]å =À²ÈCöÚÄ—Ì"‡8Jr±Èý_µÎ\Âeͤ«-Ç{eëÕð©¯RìP¹À~*Éûó%«‘¼_²‰‘fäÔ"R³«8˜-ª*W�8^º­2qV�W×¾‰í™CÝÚGâhV¿gñËmo\âÏ>}½—c@å\î dx¦Ißëå·W„÷âzU^¸Ùú~÷Ø/j3`�×g HŠ”„§’î´’mÞk™‰í¾]I~¸ûÝ>W*�!ÎÕ”Iée�°ï7ì]U‹�ùy|‰î£LúÔ39¼¤˜|ý”„­½^xÿëÜ*`‚É㺩öÚróyÏ%½×c�QI“òœuŠq7úÃîÇ l?ÇöC;˜ ,¯ÉC‡wË€¯“`x]&jTžîŸêúšciwÛ·¤”GÅŒáˆë?èóÂÆÌ*ÊLíÈøºÆ·#õÄœ^=çJö囄":tOÍ;xM¹A?õzÎó.ÿþ÷¬Àá;ì§X¿˜±7zøîw¬Ý~¿ Èæµ[u`¤íõ<Æ`<ÆYmÑIC ÔÌÇ?K*ñHn°·B9¾>ÊQÈ:@‡@>×­eã_/o�‰–ù¥ëUÚu¿\n‚ãŠY&ÕI|G SÏã´þk~ø÷>2©,ðxjúü¬Ÿp<öÓîóç[aƪeý^¯IŒÕs…qnÚ€Á.æ·n\RÒÕyF ´p»_®2_ž3¯TõQŒ&=«ç¯õg½ŠßÕö)ûLïçµõÙ}P—ŒÌ€-U¯ ðTRŠ|¿H\»¼”æ.ÖÛúi ?WJúë]ÏHMW_ÿ{”¢ä(Kâøêz%¹˜å û­ï9°} èûÖ~×¥ ;#¬c3Àôr«ö”Ùø5reL4û3ºP:±oŒ°ÛÑŽAfÛ‡ÒŠ“)&HìÐôbô!il¯F4e’ëYxî dP=úzòýÆ™Lu„<?C¥Þ«„âÈáÌì":Íü6±¼nÊE`L”>ÚeO½µRVKg €n3@°K gù·«e†ñ÷•ÞQìY›e-ý@Âv+éA¬ÖKEô¾C¹ìü˜CƒíUºž™Ä‰ê'u|KökÅõª½ŠÌïÎÄjÓöìƒû¸Òa_ejVû§ pfçY•4Äã³zdŒO^+IˆRŒ(©‰6Æ¡ªãÚ3@p‰™OÇûïcõÜGíôõÖëÕýoËSÀÁÙÝïèñ~‡©¶‹ó_yÉéÚŒ™úÈPòó„5«:†‡{Èöïñ\8ªbûV(o#vèêý»~¾Ìή”>¾ vwò@¸ÜPÁb¶ÓÃý¸Ñ÷6SבãÝI<v`ìÆ$;½Ø€7Užê'lG_î̯Ñ[›ÙÎÚ“­G††м4wxóïO%õµ;«ÿµvÏ Ä%²v¡”dÙȧ€ÿý޷ןŸÎµÞ¼Ïaøj :ÛÎãŒ1u^¼?9“q>çz¡dæ<Ž©€µ¹üahbÀò{€™f¬ÅÖs‡½¶|½CÏ¿›ž§wŠÉö.cJb²÷Û ÀÏ×3æ|¹œ©‡åcû»£ùcÑç|¯†¼*FGlí<u|yôy׎ðU)f5CB& Z•‰Ó’ã«þ¾5L5ç[ÝjõP@ˆª—¿nk÷]ÚжÃ3¶bÖ³ ½ÊúÕ¾gtN;~~-é¸öÝ”—œ1†¦¯cÙøz/'“­È„œr‰e¹ÀÔö*€Õ*ûM9Ä2F[©]U ±ß @"•½c·ÅŸ­™b˜{ìž[¬oŸf¤\¾, u/ÿ2�Ù]:ñ^‹¿; &ôÞZÛ¾ÐÁ›iÕcd¦™}5¯ån?\Ø.³xâe%*vÁ8ÙÈ7[Îl}:\P^ «¼4ßOÝ2‡g†e‘ÌêC+¿ÎÕ]E0×Ê?z\doŽòÏÏ‘1;|ÓÅ;>ÕuƤ]ã©Î’„1¬"³åÃ9¢#‡‘¾<³ˆ5È ýRŒç¥þPÒšÈ dÖ«€; ÊË�»*À³ eÀV5¢?³Œ1µÊ ªJ‡°*ÃÊhU‘¦›Á�F–óÌÖoŒOØL½Lºï–íñ~Û~Í`¬Üß0Û¹ßÎú)?O\!#¬ÑýÙyã÷„í·Œû¸E¡!l/[£MΛì‘ëï{n~ƒó Z•B«IºªVûÖ­J˜ô½-àå•âRŸoæ½éÛ›a•÷Έp·#¥–S’’ã÷½Ùï¨àËÆÝ¹Þ(•HÛóˆ./0ž|å&1àÓï+U¸ß€?¼_XûØ8©|¼©2Wz€&_NÁouþs5>^ïâ{sÝ6ã¸@XU õY�NÍáž¹Ïó@Øšcïò¤‘hð;z> pøû¹O Ñ¹¦²€A&-Ê$J›9~/ûiPq?æå+ìÀXß~Šæk_—éw2’3Ì3NÑ,cvrW¾3ÙöÞžfúu¿·ÿæë?ó&õÍ8¤X{‚ú=jk�EV2Rª!Ί “G·ƒOë ˜*³+Þ_1€F=9 çËççÉû›KçaùŠi”IV%)_]ûU=9# @Ýï â}©Úµj hRLÌø8µ=¿cæ^UšR•—1‡}oÍ�HTrpbŒ5¶½[Ï9¦˜gY=¦ó2<ïToÓN&™xený%þ¾R¿ýÉÃë,ß°™AÖ ×Ø×/-¡hÎçpÉ‘SÌà‰p»aûËY:ö˜dšXŒ)á¸ß…L”³‰Êõ¸akRths‡Ï,±øË;Ÿ‚[4£I• rg­OìPk‚y‡v‚ògˆ­:ÌTn1ïX«N(ó^qD«RÇ25c=w«È}\~PÇunÈš¥Q´g¦­xØvñ\7¾¿Ôñ^­MýÈ"}Yÿk†gRl©D™ê.åǬ"ÍÆÜóõaûqà±.i’1u2àI}øg€T•±WX¯2ÀV˜Iøœ ¡t§ÚOåXöáÊ‹$õf)RUo¼_øyG¹Y(©Â¹^ªÞ;©ç @«€lÖnÕÎy^¡Ž×æÇ+Uø!Ú¿§óûÂ÷Ou}^"3Î< 0[ÓöÛŸìRKo(„ˆÇÜ£XïTŸÖg¼~]j³Ñºi÷3— V—–D¦³Yríê Ý @–}çÌ÷'ÿó÷z2š¤[›¤1W<Þ¨�€E¹ÁXÿa`Ôv>q¾Ðb1 ˜T™e¦èP@ \zIÆù¼½½Õú")òËH«ßüx-_ËÃêËÊ­Fªrí“„ ¹ª©ýO®ü¾þÀµ·1Ê¿ÂëÇvØ{ ~úsQÇúyÆù¶¥ùÚp^nëýwÆ.ÐþKkø"í ãë×ü|0 OõïŠBQ¼…ÐrܸM[Ì0ÒL‘3ìÿ­ûjÐ9P‘•ÏÛæüSÇžÇx´ðeey=W=€¼}šùÏ<3_äàþñý€çû”ýž™ÒV™–\âV_ߌ±¨˜t ÌLçF«I;®—oÛùšŒ‡ù8¤Êåëo61°º)IÄŒ¡Eë€S�hu)C ¨U°©þF™l^2ñ¯sK_Ý~k ìök�°¾ßË÷!•xoÄ¿@6eRB‘Ökjæ5çØ-gØ÷#Ì]FÌ-@Z%Ùr·(’ÚGÜfÔã1q&,,R§Æ ãëõc8rÍŽ&–3ãó Û_ñ¼Ë‰wm RÃnî`ÑÀ 7»½;‚.Âašk¨?ÇF{С†ëñ»~oúƒûÏšPìÙ}ä)Þ¿µrÇï‡ìˆbÄÇ(¹ÝÕŒYâ'Í©9z0é¹—DäL<åhW�ÙÙÖ±„ 1ôÇúÿ'õ’�� �IDATù| hdŸß÷w10ÂK|ÆfñûEç®âסÆD‹Ž¯Ýy;¬©\7Öfg2úþÄçðjç[9VZlœ¥ GùÖÁÙ™£æ¾aÏ—LÄý`X¶Ï¥û¸D’~Ù¨>ßwê>Ãò¯ýå™\kR±¼ßæç¿3gÐñz]VÀÿZ?T™a*‡TnÂßÃþsíÏDêw; òºθ®Ym^yæ[íŸxžSãß7 �ò¦×¯ÊuǮΠ¶¸ï¿(à\˜„ó®›Äáùuû~; Æ—w ÷v®Šôz7ØnǹM:¢Õwž•j³R•s=£Ûö»RfàŒ_s9§V›¿ŒrÏtÅ”®ëã\­™¡4Zž3¨Z^¼½~žcÀ§.'>2cýŽÌ¤þ/î<X]io-PŠü ŒÀ­psËü|d¹£>ÈüRí´í:ÁöÔ÷2o9Ùý #ì2ºáõéãÓæÆC°Ÿ±=̼ÃÛO0êObù(à”šöü¬ñ¬>*wXžË‰ õóo¥õ¸=Ë=•çЪIØå § HŒ=c¿,47î××tÆx̲TY?åÒ€Y M®Ïë£ê¡�$Ÿk+3:«@]õ»›®9CR§%—öŸ�+¤¨ôá\…9»ˆe9ÆW²@ꑞ?kÇ7„MË šd ­ø×ÏŒ¯¯_WÀ¬K'N¿mþUÇG˦~*—د›„¢”hḭ̀—³tÎ÷H™™|‚è¥EØÄ~P]íñU<ÇhŸNÊ}Äò8]> laÏçç;º_Î,RŒn™tšØ=(Ë>à0É>­¯FJoaéõzT¶2g·˜A°•#Õ=0¤ö‹™;ö|ÕiFGŒ1ÜŽL³7q<—n«J,å9‰¬ïÌ+õè™]³ƒeoVJnýE ³Hs¿þÃ1Wl­ÆáŒD”ºôL,3t8°‰Œ&æ°Ãû û ¢¸*Â_ÌuÜ€hú¹yoXÑŸ{(¥‡Çû~gõC@xw@©ÏíÇçJâ/“níáãMœC -rûq||ÐåFåévy€ÏöÓ9_Ã2–6S÷ãºU"ÙuðÀ}ývX¯\j¦ ~¿Øc}üþþ9ˆ×£eÒÈ™­êd9Ú67¯ÉdÊòyøª4íl€`î¡ðŒŽîpåKÞB`꫈wÊ�† ’J€ˆ¬Oóˆëû§Ï“} ¹”¿s3l®g='aþ;³Â¤gË<ðåÃý6ó›÷çšu lÕ!ÌM}wå9òÔùly»Í9 ¯¤!ž'—tÔýÈ,UŽ=nÎýõNßåýë3å~ßÛòOS¹óxr fšñy¯%£d¢ßÿ"˶ ÀÄ CiÄ r ®[ gǹO·ýj9 R³K:ÓmÅí¼^Þ¡Cq`‚}_“åªäó£Ì *àïû­*”1Ê>¡¼L’0Ï=×g=w–S¼0ø(`–µ_1"×�SŸL•´=ŠFþxdŽÙåŒq· $56õ}ñgë!l®ªfYéÄÕdmÞ?c¢UÛñ­M¹ÀB†ÖoD‰ßŸpäÏu—ND ­ïûËœb*×™YWŒÒŠ·­·_Ì56YIÍŽBEÁlj˜ÜÓ¿Öl„RkL°×€ÿ8>;9rï åpà€ÍjBÖ¾l½N ]X4°eN~Ú¥r–µÒúºÅý¸TÅå­ ìÑUf‘¦óÝa·+ɬ3”¯¥Å¸É¤å¬Y ŽØ.½ß›HT?övÌÏuæ ª90¡@gê`™PÌìoðº³~ý¨¤Pµâ ì¡$Û&˜‰þ~ÄÜkôCy‡ö7Q®Ìf °× • 8ôý¬€ !ÔËc×ck#çÍ ØF@V»7Ÿ0­ÄïNÖÏçõ¶õÛàøðÂøØ‘˜½=Ó ¯¸öõ÷Æ™”k¿ž‰×·k�·™ýT¿è@ƒÎt³ç±÷‰b`9j\UÌŽgÎ[*ÕWœ-“>¼À<E3À2Iéµù z?gý´¥ý¢Þœ})¸êç«¶¯º&UŒG¥Òðû"ê‰lœêß5l<š—CiZÌí,˜aíåLËAÉì¾Ì�tÆÄšŸë.ˆÌ°ªÂˆ좀ǹ_{=˜âåV@›tx@‘¸`À¤²} Z5Yr©H´­\ßþ˜J)€Ô¿Û9ãkffÍËuéÅZ½Ïþæ׋I]ÆÒ…ºßÞ¶ÏËlý�Š;3Ÿ«ÝklÜx…ö}ÞjÖsƒ½’œ`ª¾dB&Ø ¸-3€…¹â¢û)ök)i8”=2ïõéÏÇcãu€Ž?a?ïÜ>åLÞöƒ—¨¬1 4p–õ+ªªÌ¬zî'¤yf 2þÀP;ž/ÏéTõs=OC .7nß÷s°ß?“÷ëk¹ÿ«÷C<r@wHGr&YÌæûÅíZµOÑŽ#XbTâ!¦Öd™b)YµÜ ]¸^oÖkCòð‡˜p¹HyûùòïÁ›Î{=æ×5YÏ)Ƙcigܤ)°ç˜b7iÅÖ`bÖ5å¿>Ò¦VXŽ"Ñíg(Ç¥\'2v¢Qñò\K: P݉ƒË­ØNþkmÎ}Õ·®"ù5ÀìÑ×SÆp¨çv°À®ï¦�²ç÷½)©K „©#ŸcUw˜v´ùÜlÿÖ2)ÄÌŽŒì(æo_¯e 8;B Ï>d8Ä;¬ji-9VÕÜo˜™Ï7�”Á\B‡¼eàY†Òã"]xy ÊÞ0B ÌKHZÆ×hŸ-/ÎɳàbÞ/ŽgÀk�L(‘‡Œ´Ñ¿^ú¯ó|}ì·OÏ¿oÎÐïÃËW–Ùuvå+C†™m§—òTÏ2+Û´¼:Úê¸Pý>çÀ(ZöþÃ~ЀHÌõ9À¢~cíX1x ÉguDõ}¹qZ³<÷Wg~Õæ-—T)`4{o×Ý®ÕP»_6ŸTóÑ£óÄõ«XUbàó‡HŠ[^ÜQ<ú5 äc–âÄGߎïÀפäÑÚ”+¬·ïëC>×óø¿’ƒ™Ï»_gÆ<·ðÕ;!Gíw-g‡òÖ� ƬfJ)¸ÿ.‹X�SlÊ%Û²ï¿5»¤Ç?6^¯VGs‚­¶×"Ǻ ˆÎ ¥ý`“͇�¬Ì2¨F½-P„LÏUf¥Í6KY©ï™`~Ò™a&—î÷ÓèOX]¹N¼\th×ßxGͽ=ؾû¿«Žï ˆ®K£öz °Ó-{€àåæLž*�wÔÏS´„af¼Šy“]o�a¹qÿ)€î3õè¨úg~Pµž¥y»±5©F,G·Gõ£=ŸoÿÚû^=ßúþ·åæýV«ÏkrÝ=Xe–Æ¿@*1Â2@k•éõ+Z^`–õv©ö–�¾oÓÿ!öÓ0¾:3쯼0*e8Wêìy"`íåû`)¦”Ë»é IÅ+0vË%véÀ×yFè|eiÖ‘Ý—#©-Ô²fZÏ¡Ó'D§)¢*b–UŒI/¡mîGEÿiE¿G_²G<šs,>›T%øÐˆÀ2ÌÎfùÏç"CÇwé_u]²ó<£Öz9cDí¨Ñ²™4”eº´¦"û4C‰K}iI¿¨?gàb>Ÿ’PS ³F–‘A¤5\RûůWËsDÌËHá¹.ØyØõÛÓëï¹ý;1Lº•9Uû" ºå[F”Šl|¼>úyü€úZÀDcWIjI˸| ä¾'ÇÍýÀž;¶}ô+—¼ôýh—×â¹YýÏâ>òÏ­í??."Ónn/2+{»Ó>2«î¯"¡í/`8A[<ö&¼$¿Ãªóµ,§ª½ï·"`Vï•U&ˆºZzDÍx`‚>>¶HZû]l·ŠYÿµûúH-›¤½}WÝ�°„±�Áù»¨·ß•¬Ç@„¹=´?ÜsÀ º> ÂïC\úò°?3†ÚÕ8ãÎÎXÛÊ÷wÍ©ÄÎhÛ_/ë’ôª|%)º‹õ¶=uãí9ý¡ñË ˆóÜwQ;3¦¢]ÞèzÌI‹Îõj-Ð|.´¾\™'̹°ÞÚ�º>§åLJñýö;í÷ãØ{Ž'ûšÇ >>Øë¦�°è<+LΕ7;+×ÏW8 ¿*ªœåâûU=(×ýþT ²�jýй‰#èuÙcm²:ÀÕÖ£~;Õyb £*9ù|Ù²úëû/»®¸_vãþyuý»&™¨ë¯_ ˆEæV,X—šäíÊ€½œ1¦ú×ßpqˆ˜è@~”ÁVe€}¯GXj¿%ÀŒ�\«’ŠKíùÖ<0õ$ Àé·ÿU ® ëåÓŽ¹ÇÆ: ¡”biý÷¯¿¿þ§M©[äái’àí‹;Z³8Š™1Æ4¬[ÃŒÄänœÀEcTu±ßÛgÛ ‚Õ¤à±ÕâX®«Œ)Æ×ÏÄ‘e€êO $Ö$Õö,9tµ\lŸ_®F(ð+§r¦l²¼ºƒ}€dµŒ[N'å ž›O›w¬#3%ú@óŒš ØÖíaã:èçþ©JFF†ºÞÀá´Ó•Õ'î¯ê8¥¯O&9W­ ÈÉ€ dDeLÈ^oÕoÜq6öC@$7Î(ÌrÖ) Í:#»ÂRŒ%ªT)@k#ÇÍçaÓú¸_ô}GÈçÂn÷�˜íwÝû}3S½ä)J{Ö5Úâñ #ÂùûÆKíÅL"|ŸÍùµjYä÷xÿcàšŸp樲Œ‘ªúK[üÁîv6QJõz=fø^~S,ºß™$`_Ï–œ»Å¿Sì¼M1ÐÛêú¯é }o­^l c8­HÊâùQBX2j€Šý"À5?UMuœÃë^9?+ŸxD<Ì#Leþûu»Õû1FˆþÞ©:xkç­3E²r¸Ã­ÇñY¿ùZ1B•Tií¾Ž™vÌ¿Á˜”Ñwl&Á¸Æ`«åÂBÉÄy9˜v`ë�À—ÊójËÓoš*“®&‰{µOq_¼>ðæ³–=ÿ«’~™e3¦]›í ë ¢Ûk� :ÐUî-혙SyŽ3l¯GÞ/Šù¦ÎŸ1}²óe̹급¹«jï‘,'—:î3í'Õ¾µ÷'„úz<:ÓŸóU‰ÎÌ3÷îËàªâ¬?üø ø<ž³MYœýj2° ðÔ™^à*0¿T=ª€\œÑíF2ñö{¨:@ÖZ�X@×´]I+fÀÕ¼<åk_ÿ3€±IRë™æ£L³û‹ìK;ÍÅ‹rTÖlŽxVRªÍl×bU $›XÅå!3À¯¿ÖVIˆcÕ™ÚñÍÏðÕx5}ñýTM>oTáðô.»üüH¦jdæýö}{Fݯø™cÿH9ë¯w.Uÿ¬Gé· àëãÜ,¸>ªßûÂñU¦Ðqé*¥CÃâˆÎjî¸(€æ˜#i”¯>\-0–Kü)Æ2ÿZ²_¸xÀ‡jÿÇaÇ&Ö?h@c¥ŒÒ|  a€1`ª?æ~ÌŸ;Å8̪ØÏYa q|Ф¶X�…GÃh b*§é.ÊÑãâ?ÅHºšˆÊ�yÅtåÏyÆ�SýRß×>t½ûa/µ¾}¶àÝÈ{·°q5 ôãúùÌ:ò?4G&H¦ˆ1·ËKåæýiêß:€v—JœÚƒŽìì½]9ÿ,ŽÌäÞ/”Ïk­5ú«€©nCñcîQ[¾ïq{¼ZŽ£|•[¿ç0W¨eîG×mñuÊoÇÆS PÍI¢ê×ñ¼ºüìzªþXëÝh[cÜ`û˜’ ;º"ŽäWrƒ©Àâ&–Õxº"ès]í•ìÿæzê¾þrù}‰çø¥>NÄR±+9ç"©Ä׳of$u¦ÜuùX�¶³.áÉÞš1µ*|íÇzªÏÛb~{\ÍHÁzט@™­ç˜ÊÎßË­iš ¶'û·pÿ:à„Œ¸êõÞD9µúázÝ>[n^~Ío— ØãçˤuŽÃj}vØKöWíˆ×+@:cÐópþqÃb€FÖg�×¯Ö 0ö+ÚOmÿÖ&&X_yŽ~ˆ95I*f@™<TŠ?€»I*šrf&™’X4å³î0/|”è@I—sÙ1ƒ‘‡óúÙñvÝn'8뎛ìµGÔDÖì’0a1tæÓÚúj«¹c HYnGc…×K[ͽÒ`}Ì^^Ο—ZÄþÉ�ÇÖ«lƒí¬Ôµ-Ý*€O¶~~ý2ÉÃ~ž±q_g*]í,~«Rq±Õ„dl»`ˆrŒT㪲çM1�™!#é=ÜŸKhFGbçÒ@9;@Å2 «R‚MlçQ¹¸Zñx&‰Ñ}R 舮sÇ!ðÅög÷9c Clv¬6(‡;ÔÏ¢<}ýbÉÆ ˜)ÆŸÝ3`»m¤\¾=îWµÝ×3·h~æ3zn žL}VmåùÁs?T2 Ä<ð¥0°RÎšÛæHÿð7ÎŽ ©­Ž3£Vgº<æëó]¦�1¨È¬èóþì ½г™ò ¬ÆA”<¢Dá˜^]¹£—{ûc�SÆtÂñwVàÀzÏÛ›Ù¾Kzè8x\näöiaùµ;yîŸÌ˜Tñ.²«mw@¼~[GüFóxgÒ`ÍÔxéÇÉ xäÒsM–‡íSÛíˆu*\p/ç¹Ùêí¨½ŸÕ›uüöT×~Èë‹õŽW¼žh©�°~bãÀ,¡ˆ-X`º]ä2JLÀ¾‹³(jZE’õæOÊa^eHàs9–IÂ=ÊÌÐõ;™å#¹Ø¸Y`$—¦kb¿Ý”£çåd9Ÿ>Óñ)B¬i@m-WšÎý…€šêÏM”—Yæù{ÐPR€—1ŒÔsÿ€ÔýU³ë¾šCﳩ/µ*“+–ŽôãZ|ÿºvÔ¤3_Óç7ëÌ1¨,¤ÔzÀJÒŽ='Ú ´ÖZkß&Àê‡bpÝì'lwÀ.«Üc ëÖ`óö¸<�ö³or’aùÆf`èrºä„ò "×…tb7Œ”ìû¡£|Ž·œ}B§]Ä\ÚÇ'‹e s²^õAÆ;Ö•#o 3Hkæ¸\ò©bÛ-5‹T5œ?«ÎÉb d±ô"FŒÿӹȲ­þnÞa»eœÍ¦r`5yÄsLED#Ãìúüãsbs5í’!xN>hÎE�ëÇs7õvÍ¿½¾™¤\|>»?2gu$^*Š�UŒ,Ï3`l}"ɨHRwo*§•Î!Ç>¼g Äw±?–‡w•HØ(ìË5:ÚìýÅ®›ê·*ºÁñ•û‡}ÆÌÀèìÐV@·-Kžæq¡JÒÜÈŒ8ã>‘þœr©ï—Öüx·‰ýŸL(iÃè|Þ¸£�+v¿ jîm²P€ØªÒZšyÀçJ QHø‡;úÙŸ‡RðЈ]\§qý”Dâ£Æs‡j]”–¬N(›ççjž6€°Œå¹!b A X²ãõêûþn_ô=vú²ãÞ}ù¶? ìk¤œù¼8/³ß_V¡`v0ÛœFZ"±×‡I6²çxfÀh lôp?¿:ïÌ,›¿ã26·Ü�·÷d9šŸÎߪæUn®*s+“(ÔýŽÛQ²0>onêɱRGë§òz?þfƒ¬ë߉ÙõýüF·{ã@<—^ôLÍ}y^9Ÿïõ¾ìCSúúwXߦãuýÍù^ØuµãÎx®Øw›b¨FåÆÊE${Ãå�^<@© m;’Œµüޝ3î2FÛ ÷ÌD*çÏ€0žF×�˜8ð÷*Ž÷çÙÃã²~¨K ³zN§]¯4§¸!sÉßïGÛóhˆÙcoþùÀq§ €Õ�Ú<Ä{µ¿Öúá3aÇס~ße¦¤W³PÒ�Xe¹Ç ó iA=Œ}›þÇ\^È‹¥‘KÌg˜s,( ™btŸ‘kìç Hs’Ž*—Ù½|d†ÑH¿ (ë@u4NpÊ¢#úµæ?LÙñØž,¢­h±ÈEV^nÖ€šü*¢Ø;Ç$óuÅ(ªj4Çn+L•Ê~~ýQF³v[æ�ÙŸfŽ­šžöí�sǦ·ã‘¨Ñ‡Œ¾î±ƒ ““ëœOSDÕ7ÏÍõåeŒ¤£Æ¥‰¼UÚµ‹ãðÖMEú# ´‰õª¼ ó-cÀ ƒÇ±ã£~4i�4 )/z"àp…T¹^Q¹p˜HEf¡µ3”ÿŒ„ü¹‰Ÿ³3}.qœéæ?¯ü8ôFŽÃã3C-7þa3ñz!p†½}} °éžx~K[ËÝ3 –ýöL’¹‰õ13¤2žÙõÕyT%Ù3m°¬�Ìç݇8ŸÍqq€Ü#f%õ¸ lÔpv”êùogJíá¸ÍŽk7ëˆ_0½I&¢ÄW” 9clÍ Þ­íæ=¨$6rÇW×YÌvi¹#ÓÎg»¤Ü`ÐTY¬©€‡ì»U1—×Ú=wò’2` LEçp˜³k=G·LÊtUQ•¯¿ãŽ9:=ƒç1iv£þŽæá33óÝ”·úüXóL¼<�–ïƒùE¥¯Ûw9O¿šî{û²�‚h;kï°ý΄‹÷³ö8³ê(¥Z£n<WØékGƨ«KÇ!@TG3Àä5Ùž9ð5�fÏïÏc™?Y=ÏÕ”I0ÆËÚøõÊÊÓL-þ¾@ÿB«JSæõ¯Y.1™mÏ<¥Ç�°*Ó­žÓ-î¯ú}¿°ßwªÞ `ú.ö3Ë/ÿ•2·Jå´f™]mË�º_ɲ±ˆyàÊå)ÅÀûy;þ‡ºýuÛï·Â(c�ÖË÷;àööûÑÚ`’Í9ÇÐ\ù h–L4À˜kÅÙþ~Õų•KªÙ_oá5,±x‚Š‹˜ B”£K+ÎëxÜŠU�ã÷Yâ:5Y»d¦ÜªÀIœ»ìû¯HW<×bª;:8=°ÉŸažŸßÛÆŠ²,n¾Ÿ/¿[µÔ¦e€¨çM1s@.Þ¿%Ç[«Hòpi={~ppä :€ÆžKPõã*’m£¾ùuUÒóù¢iâjn¨¬>ø±~Ê>ÛbïAÕ(µÇ¥ëj°Í@¡¼ÆsÁ׫ˆbš«€E¯—’¶â÷{õ½1÷g²e^Ÿo8~# Õ÷ÊTâÀ´ÕÀšnƒ °¯JöÜJU‰å¬ü¸u5÷ÊÊ,ŠKªë=¶®Í¯VMáõ~<*8[&‰ý5�žñT})Frf”yŒ pxw+ö€CØÿ’•ßx [¶�Ù?f©ÔqõÈI$ætãΪ|wÎŒ–ër—”Ó‹XN|ý¬”§ ØÚ¦÷ÖŠyæ"_ßÍdñ¸ ¾KNâ×1.Åí댰þ݉®tDßùY?wÛèý’Ý× ÕõžïË °›€³~žQ´ÁsºK (ªo7í<A=;0f¤¿.vY™É)¦Æ;�êKûËÊáûgûswå U˜†Ùx í(sFÕ—ù1ö®>ùµ€ ÌÁýyø¸ê8²&‡¦™Ù„’$ÌÚù(p×W1ÔPÊ2—–ŒM¡™?‘oG ?°©öÕû/ô µ˜™µ dbÎ/ ÷ë©Þ«ü÷µ|Õ¾°õø“•æ¯Åçu¹[’*lu Jíÿ+YË!À5åËÎK÷ûæÖ ‰Ã„©\bw»`n?ÊÈÊrýæ9¿:óëë—´~ ‰ÄŸ=×XjÙ‡TkW)ÅÖ¢y?;04H®±ªÆ½ú0åÝM¢HÏYÃ}Ð*ÉkM{ô/‹4;ÞŸ‡í+”ùóU ‹hýšEäØT©nq¹’V÷œ³L-ï»<¢™£Œ_ßm:‚e>âM–ÖJ[žßú¹½v=2Ov)‘eê~zu†rªIëÏwÇ?š•šûHu£þk¹ ¬„œbj©óö£D–m2»ö­¡t£˜£K§€‹Š4à\¯ùw% àŽOŽWÁUfßÕ:Ãê#ÜÔ7ÏõÉ“¶Üa^jŽGâ£$XgnÅ@Ǩ¿—¼½ÞÞQY1_®]¿ÊãÑågØU ÃŽ÷ƒ ¤Žäö¾Ê¡òœq\;jí{ s~jÇk•)çB[ÃÌ߇5è ßÇãºodíóß¶zV‡Ò¤¸¾Ý·£E—VšZó ŒžFKÂmÎ1I·ûQ£”(`än_À '¹–Y¾ôã p0blp ,˜˜"Ç~sëž;z£þcŽë¨>sý-sOþ¼};J¤YCéαþ –y¿s‰{eŠ_9€F»P¢°Êàâ¦Æ]ÍÄŠËÑŠUãÜþØÈæÛÍË×íØ“yù°h3�WÛZû¢òæçßç�³ ÄJî³Hi糩œ`ý8AŒÒ�¦:#ì%çiG9 Àqiõþ33ŒÝ×JZ6²uiAµý(c¬&NZLÁóÕ¥uî&Õ^d2e�am\=*y©ëÍÇ5Íôꀓڿ:NÆ~9dÎ)IGϸÂëÄûùñÜuÙ}­ú­™_5W¹°rà±&¨™mX?¾¬ÏõÆýlÿûëW;~ãú¬3þŽ>¯¶ž™dé8o<•¬çìju¦Yv¾Cõ8P~˜›Ì�b*w˜ÉÍõ»)û �ØO#¡ø[`x~%Íx[ï˜kXÏù<˜k,loø4I{ÌëO¸ý&ù1K'ªÈF´ìƒµú¡…ø<Bq§å¬æ’ªLV4ìµû¤*¸fÚmƒ‘QúÅj�� �IDATæ1p²—_\µúäý‘•^eê(`Ì.ëün¯&™~–)ÆŸ_®k¾_­cIß'yDqÕ2f ;;ž±Œ!ÈbÁ2@ª=•»<‹Xæ¹’²ÈМ‘’9¶¸)fœÏ¡e÷÷T+Ñt5‘Ç(‚sLK}N.ª*¦eÖ°÷!ŽG³ÿ•Ï›Ó ÷G†c–{­Ê`Ì€³êûÅ;ÊçÈúÑ~tP*�ùLï¼YÜÞ/ÆQ®›'1°ÁŽÃÃԸΙ¿^QiÏXtޝn\¢ø”¾—Õ¸åå¦Z[…¯¢5µ3îÉÞxýÿL É(÷ój�Ål)¿H¢÷o�)Ã*’·¸?/lÎD­ˆ¡Røƒï {û!gXå;‚lðžðLs€àä胹d!»s{çœDƒÑ‚‰˜ Z¿™Ù}£îÝ_|ž¾¹y‚ÏUjsÖ¾«4óè(ƒ`Í" §÷€5>#A%•uI7[Îȉ…’¦ªÝk•B±#Îñ6–c¦&2ãøq+ȋχÊúx[{žûz”�|û:¦Wx‡|±ë4=w_�D¿MüÆý¹Ýû—œ/°¼Ý~g¦Øgr\f£öùÊËynà’­ÑlÏIýõ úœ ¥lÕßÄ×ëÜ^ÕúTb¥Ü?gJq)9ß¾ûcù–Y¥Œ¬ÈËêµ.¥Û§øÕÒxý¹¤å:ƒ,Þ/ ãói QæŽÖwUÒ·+ÔjßE ¨Dæ"îïC h S€Rx\gn‘\aª¸>ËA†¹Ã”å’‰7Éû¤ak-”PìÌ,Xî†Jb±…RŠ5g"×o€ýl­µ—ïp^ØßH)Vsg± ŸŠ^À¡‹‘“_þC¤Ávň#ñ³n[ŠÜaÀØÑ?ָ㦠ð싎 ÌòùÌ¡§J\xÌMkõ¯÷O&…g­.ýÔJå<ÏbÜxÍöÈsîXûñë‘]™ý {ôUJeÀˆ¿Ë3¬· %áд#—3uüx‡ÀÆ»Øßn÷ œ Ã×KçåRŽXOÎ|ÓLhùq=®ï�;ŠIt¦ý‡ï4?Ãúì õ·‹ýTÿx 6s ¯K HµÇùq™\}¤øù9@š1å˜Ã×+iOu߬]ç?e|¼Ì¥‰c€ ÷’gkÐÎóú¡Æîv ™`õÀ•ÕýlodnÿzÿäóÌëþ6±¼VϺeJ]2ŽÏ¶åñGKèeÒzØâ*Ó"“(cÈôíöïß/Ã�Áäs9ÃZ“ïqÖocÙß¹]úÐðñÀ¿=ÓöÊø8Œ’õ5‡Rÿ¾BÇ8~wåÒŒØ;<p‡Ý«\•vzïæwXÍá—154qÌ‘þè÷—nä#nÅõӀžŽ•úë~Q Í î{€Çe�¾ÚŸ,?ÜØ<ý~?ïç¹@;½‡¤ï§ê?ïëb—_fÆÝÛ-gö'¸°} ÔŒ×,@{>¯Ï–3j+6`§l?¿ëŒœŒv1{5”JC`Â0™c;vÔ+à"—ÈSÌ’UÀ+8Ê.1ÀçÜ/«þÑÏ{«÷a–sÏ_¯ 0É®#ïŸü  Ê°Z5 ä¨ú©ë’MUå®°Úíè}òZ<z~Uÿdëóû™S�µ ˜õa`…Ò‡t½ÚË%ÀÛ÷ä·µ9Ä p䪟}½(ìöC�d÷ãû22 0×4#Må ›·w‰Å)ç­{ÌU û =”â]B> ™¤"J´yù%vÜyÉ®æþS”}Œ¤âR‹øáâ'¾83ílÙ‡dU§–ƒèO9üTdôÌ âÛ‘™;×ëÝ/¯2t:wÀù×Àö§ Ÿï8Aæ?ÎK;U'Çk\µ@MO7kÌ“ùxË`Bi·¾ÿÙŒCø|g­eõÇrP’ñj\‚NoŽ#¤ãÕ(zü¶9¤t}mΩñÀ~ÈóÏíÛЦÊQ�Wyˆçõ¹³tŽ/l_VýWgÄöãßi9ÞP’³5/±Æ$Hçý}n;<odÜVR™“R-1db©÷äøLVïÍøSš(†ï™uËñçÒñþý—ZJâ¸%ëõº°óê<f{eL±çšÀºáóÅ™œ³­IZ‡lM i–4WÀ—w8c‹£™É(åÛšÿþykæDž¿[.˜c¹K#â÷Qãlv^Öï8~ æºeÌm7@q�_µÈy€ÌÒ„³ÍŽgtL#àÆsþðï¨ù¾ÉŒ+ˆàûi,wéÞy¿Gh%Õç¥ûºÀ°Ÿpù’ÎpI ®ç Ããz<GJ_çÞꌔ²Ãö?÷»Â3˜úó‚LÉ­|_ÇõØÝóeûc»ŸûAÅÑ=X.Ê�M='e‚½™ `F?Ìn¤!»aÜ©Tóùêanó}{½”dhíþDÀ)wgYëþ¬'âh®¤Ï¢ƒÿS–“I­2ÎøuË€ìäõàíͨ ˆà Ýþ,Dýèø®®£ŒÔþ«L#Õ}þþÌÚcR€¯‹ë‡Åï}%!ù*ïÎD¬˜Š©6˜ˆŠ¡wÔ,€øZî÷Œ¹µj%iÂÌ L¯Õã)£­3˺}kÍåäJ©n(‘(~;Së‡a ùåŸT*±hÄ"Öl ûѲÐX¤\ÄDèZøî5Ú? o’"óΚÆ<_ŽÍí±Ç=ŽÌ?¸çH,ö¡‘ZÆ”ôÛš£}Õ<ƒèQ-øUjï^:jÝ]X”q‡ßÉEÆ7ºß?ŒaO(€s˜Ø££aå©UlÇö¾¸¿²Hðà­éþñÇqi?tÌxI@lÇØŸG¸c´:b¦Ø�WÈœBÀè ûki¾7zž³øVL9% ¨¥íö±¿*çî‡ÀTv¾8W¡/×:\SKôœ¡ßsIPe ¸ŒëÕÏq*eþefþ<Ú2Æd$iÔîçß3ƒ¡e—ç=ÚTŽ'wú;ŽF‰bêñOت”4æÜÌsyªelµºï¸e³Ý{±# güõ½-£o5àaÝ,ËÉsH6ùþѦrê{ÿŽ~Æùú¬Çù?J7Ø®¨%»`—[Žd÷}’ñèm…_¬/›gŒýÆýu¿6ùý4·×k …_×Ùá¯בeÀ{Ü ÈÚ3×#b8ÎïË£�Øè§íö›†=À»±ã'ƒ¡¶vÞܦqÇÎëÛ½‹ýò?zîÉý›ûå’¡]ús7þV&}Èüs;GÀÙ«Œs˜#¬3âÜ0³ah¼½±ãxþfËàÝßœéò Ç=žI™þb´Û¹Õë•y¤®Û«+Y=ÐáŽ@¹ä^uûZˆÃÑNx¼fl©Okçñç]“ôÌŒ‰£˜tY?~ôyñøg½·ìõB@S¬Ø^4kï}%9X¾3¦ã*�Ucþ­ÖïSöOÆìäõÃv~òù†¾&�éü*CÉBó»`ß‹ûu�+´3 ™eÈû2ÀÑýWa¿Ýò¾^I"SŒî÷ûÎ,sç1ÀØ_¸¿€MŒ±ëùº–¼¿-ÑAÔÌr –¯gÿ¸ff¿ (kÍjÐ÷ãÂrÅzÅœ˜ÿ8ÒhçSJ¯…þŒÈóU×íÃüªˆ|mk�Ð.רˆhu\uÏÚ‹6®MÞŽjòì<ÂÝšvr�n5‰íó€4Þï:Î4vÔ" –3±|}½­,çrU%ÖªãKÿE‰%Ýv?ëøÇqÏdš!ó!öûp¹´ø«–@ŒO`)f™Ê)Õë{¾3Ü쇱fRÍå``öO¯çNکΣpZu¤ñþQåÚþcï/df A^w1Ÿhk’„ƒ2*ï˜dÕQóÀ}—›·{ø”À뀙DÔyÑ‘œ¬úžÈ¯˜l÷œ�ú{ã¿M,çŒ/4'.O^úãÆ%´77>Ô%ºí8´f,§Î\î óçHÀ ›Eâ÷ gÝìKH$«õm|¿˜ï››ÍŽoìŸ(ôõõÀSîy{†E$&sŸA;gÀÇ "%äXûÙxƒ÷ —VËúüUcÇ1I¶ë}Ð±í¾ŸµøË$ÏŨl-@âñ@M~¾ Œ“õÜH5Ës™Õ#ò×$\Gý+R®‹Ò‰µïÛ¯ã=ìŸ;UŽoèé�Ø{Ó̀ϩe…ñì+¦8Àhûsô»• TÉI^Û~ëÿ_Šiø˜]Š3”Ïi¿.7ó/_½/°}uþ¦˜j©™šŠl¿dñõ€ìøðåöúñze~]?ÝõÅòxúö•ò³ ìü•4ëŸÌ_§IY}ÔñÜ4ãÊÞ'Jµ~¿ár&©^-gÍ4CñYç­íŸ3´8æý@ރ׽*Y¨¶)Ã.‰ØËHZ‘lÏêo�¯3,´o­½ü@€‰šÈþrRŠ û9ÄnöCIb²ÌeL54‘cìç-wØÖZ{ù~+—å¬`RCZ„G>Í¿hækŠœlmhìß¿E\2éÅLËŸ}fnò±ÿî>(qBª><­Äb£¿-X~̈Òn\GW_[Õ…€«–Úò–Ÿ¹:¼Wã<rCÇw5×IÆ4¹šº¿þi„]^Ù-Ùß:÷ʼnƒbjøÈýñ‹9-ºeU;ú¡d#™Gíf޾/9´Ú›Äíı:;F½„$2Ãp}8òÛWGß8oÔ¿[ã�ÖÛ†ñçnO˜VÛÀëËœAÁ˜ö<vdî…ã°ð|\RØN°ë0rÿ\àkõƒNpp Ìáå^xdÚþÀ+3ïHô9®ËŠ!ôÛÏ¢œsx¼²cŸ÷XöËÒÙùs®7–ÐFɸ£�~lÑ<™God}ÔR&‘X‘ù30à»âåì�²ù¸Î“� ‘НÿXÙ‚;Ë2X‡’Å[¡\Ü^ù>áõÝ�Úáûp|1©¸þÝSw`«~ŒÇ™yqä}£¾Ï¨óíQ̨ØÖçññŒ�¥s©ÒUãRˆ'8ïªéïè–±ªÜaGç!Üo`ŸCÈ‘å€óÜ^1#£3Ñðî¿oÔ¯€ìïç­†Ÿw©ÄqÆþ”ÿ•· 4ÎhÃ� /AŠ€ìÀ80ô�F¬dMÃOxci5å0Ö ›ì‰ã#Ìó�ò^?[ߺ$ Ý_3ÊjõX­wu¿U¦`ÆûûçR†µûæYíñ÷ß³fº|¬1óªýº~fõ¨„‚®Ûki¦Õ7/^ËïËcÀÜgÚ/ü<€e9U¿)Fä0H^UÀ‰\¤\Ìö+ÚNêî÷ò_’y2ƾµÿ|¹\^™u©CT!`õ—“NÌÊÿy+çÇíøf~ÉyQê±××w n>ÿׯ{½ì JùÛ¥|ò H|±ŽÔ9Y´Dí~ÅX‘aÂ~¬mÚŽÒ,2ÐQŸ`DbÏ1®‘¯%µŽEg†Ãภ@á‘÷z`åƒG_×1ÌYp<‡ëO°ÝGH¢ƒ2¶?˜­}¢CyÞr= ¯?jq¹øaµCùh[ŸÈ<ñÿ¨c·r¾Çixùƒn´<,GŲýg@*’¼bå)ÆA^’’?‡;Y~oñûc ñíïãñ9út¿c»ßȲ²jøÁÿ«¶Ë;`íÃeOÞ«ŸA›(§¹q럵Kú{¦ûkIÐLòmm>Qƒ§VúqõNï× %/m •”ð?mÙ¸=Ö?–“­q?;®g‡ñ‘y†•B´N3àeÛímúÞ ’ð/Vê¿CN�€ÍŒ°•€A¯Pኜy…Œ­¸ýóóo¥Ü2 M ˆ +åf·#ÄêÏË·@%ú€•œùÎί¾ãÆzdî<Ç¡4Ì;ücC†VÿÝË©GK^>— æ%òvØ?ïg+À…=Os»[³÷'2~z¹, °|Ûn|±Ü~X?Unk—öÖ†Tb/ÿµpçWý>3môó&ü(ø‰Ž;œçr<à¢!Ü¿“Ù ö¿ˆõ«ßÍ9CLq(­bX»njf†Ìªn÷í=š‚#¶GsÁåž! LÕþºþdågåÅ@SŒUßýùÃߘ•µó5©ÆðªK3®½ç5@…õÃþ‰ÛåV¼</U·G“UÂBvøxèb«ß—(Ø¿WöG›�/ ´e9Á‚í�›�¼*“ s†Qàî[k(Aøõ3dеØú}“$$€äör€™)_å ûë.¡è€¶.­¨¤áüC¢qþЈpïæÚü£œ¢}©Èä‘›¬ï×™cÝúö®Õo&šÀ@Ëê5?¦ S¨ì×ÔÏ}ÈìËŽs%]íïÂ]’ 0žkÂ;Tt.‰GlÜg˜@`spì…’ùú£õüS¦WÃHü‹ŒÐ¿š–ø ÛCàOÛ.ÖàõWÌ ï€æŽK¼T=r‰ÆZýÓ’©Ñ‡mtŸHX.§Ì!yäyaL9 ¡áø™bÆ]4šD 7á¸lÛHPDIg9³ª¶"!úlc㽿«P–R Œ°åë�Œ¾×&¶þ³W–“2vÌV àйøø~˜»*¶ì­½ÞÏ*�‡Zy{ò>ù§]8xL@å’÷—•æ;M�w(ÖçÃý{£ì½£%½$"®ïß j?ÛN/ýˆÒkÕ÷-|°}ÛÄÄêÀ ÷·ÐáÌ€¯¹=s½m{=ÐÅ$Ëæ_,¥á°?CŒK'뜕VZåNF&znœ¶:ÃY´Fÿ\« .©—å [aèÙrøo.ixÌÆ÷ŒfJe¦€£yû0BaåþA†˜?O6¿ò~¬©ù`Û¯¿§»4â�W.Òï1í÷r{¾»T⋼íø6—ƒÇ­ËÖZäHÝoíÝîíÆý+×[KK+ :‚jVv.·úôßf~5-í¨ýj÷¬š¨Ôy¨'ÿ¸îŸ9ð«�_ï¥9ãp=GYÌ0çýSŒ=k9ÓH§Ðêúªë§î {°ßP•ÕG1$•Tæg‹¿“_ݯj§êÎäªú[ÀYÏ)WÛ/¿/W¯ïâ·µFsáúêùKõéÀ]/Ÿ0ÌèyÀ¯µÖÚ·öß/7æTgн\ZÿùúÙŽØ_z½®¼b—V´@Ù_�d  í.Å(�0'¨rÝÌ2*úDÅËLìîC.Îé2Lix«œd×VíÖ ä²™r”1ÉEt@v[qÄ⇾šàV™k×öûL–›’™™(!¶¥ Dþ)Ó¯M¹?®ÓÚDBqMy=¾+ω’9}Ž&vJ] "ov’@Ü?c0æ·¢#ÚFŽ«’wñâFàU´y ¶%ß; |T#RÙq5aÒܲéêêç+å‹g¬E¹\ØçF$…¥Æ‡ŠD+Ïýõ<à+³#±uÃçK=¿œ²‰w—=qõø“MÀtš’⎠œÀýW ð}cËÁåìn©Ýyï\°Górƒ™3Á”©ù�'Û?\²u˜f€EÒyh³c}fD0¦EkÖAÒ‡¼žÖ¢ù•§U®0j$·± ÄkvL1-%¨Öûn~û÷¨ï*ýdDÊÝTްPé×Mo°]}¯ÌÌÄÅó!¨‡L0¿ŸÏ½Y±K²ÙФ ù¹4`5Ô(fLeíÓ¦�½˜»~ùCïÅËòLÑ�âyg6v�çBú9ÌQزñŸ¿ÑÞh Ê¯ú_æã†ƒu<¡ï·¼›eìm�__¬ý0Fús§å_š—‚Å~ÎÌJBÚó¾:`q=`y¶:°|ŒI¥¼ë¹Äl*Æh†Q<ßÖ˪¼šUN9ÁÇÙÏ⸫úëùšö¯‡b½ŠãªÌ4ÏÄ©¶1C®|Úr•df“ËY=U?¬2ÛøU× —=@«€Ïµþ}MÞŸI¹ùs”ÍGâ~Ó¹õ2;ê¢õB�‰0¼¾‹ýx2ûR…h¿Øñm(ûÕºT}C©Æoí?6€°¯ÿi­ý÷ æþ€ÙoÁ û퀰{®±ÛòO³~ÚÞ% ì//•ˆçW�0Åpc?dgæEwÎ’P[ÛÊ¿Š#ø$ŽsÒ%kr3†.GÌ å�ûFJæhV’¦]÷¥íÞþ¨?ÖŠ<7ÌÜŸ#×ÄÙm¤%ŸmY$ø,ʤªœ-Üš­Ïê9üs Ma*÷˜ú½šr êé2w¨f9òþ)SÏåXÆý9dÇ{f—n{#°Öä2w4Å ¶•-™­�rÑYaeåvçZ<×ÕÞ û­ïüû.ö«8zŸÑOÏ6û>‹Þá€^¨ÆeV>¯¹t—ãÛÕ™ªíZ³£Žˆ“xŸñø¨´¡Ú¯ܬ2¿ªÛë½»PêqœïW¿Ï«µåŒü]ì‡æ?{µsEZ<sÔû3cíP.ŽÖ±›]§£Àóúð{'féÄÖÆ÷ÆÝ¾>çùX æÏÖ!ë=”fÏû= ˜`×3–$ôã¿*ß2ù{QÝ_º\%Åç6œ™×+–3%VgÖVçËùš9šy}Ö™`¼ý™4á*`¥ßƒ«€`í<Ìz ;´Í͇z;ƒ S Ì÷2Ÿx m÷ØÀƒÎØì ±ù9‹€°\2«7€°¾üW„Xg‚uXÿýÒGéù_/X U(Œý©l¾nƒñVWòXù¾ñ€ß.Ö+[½¯ë!,+Ûõ8h׃Y¢`kŽr´*Óeì¯ö«K(Ö,—¼Œë£Ñêý³&a¸¾½òÆËÑ9ã”§l5ðâYÙËjHìí¯y µÔb ðEà1Ž”ÕÞû9àvLz17S/dne¹ÁÓ ²¯ÿ­1µ&àLWáñO0ší[k7àèÎ@Ø´”b&±h\Ýï 0UW&wÀnåÝ×�f²ßî|J›ÞNävø°sÔ¶ÎLIn„¶PZ±—‡9È^r¦“ÊI`%°|D»ýÕTÒ °Å>*³Ç‰³�¼,@†öx¤tlúµË#ü}®‰Œ °Vóêk![·õdYíç(Ë>Œ3‡ªláOYv=q­’@S�g0Í,Øè·»û�ä@äxý×âîØy[9ºl Ð:âØŠÊ­¶çYýògÇ÷³ÏV$y”t  P’„g@X3ëÕò&ËïKÙó~ä‰yži`tõ_5.Wsy©À ìz Mk¹›V¯D‡œ¬nî®P¹ ív}þ¤©÷¼-§µ:c¨jÐBÀË;€Õ÷3?ΨzÜ ” T@ÜeÚ>×Ó1˜T`]Ë€$üŽð€j$´Òˆ(dÏI•é]‘Póõñ¡4b$ñ–9ªëóÂ,·®ÿþ`™­0!{?õ~±öI¯Sz|H¢¤wX_5¢T?Õ úøF÷÷ß'^¢“µ;?_¯s{ö\Çþ†Ë¤G#`ˆ‡ÕœlZbÔ>ÿ¯Í>'Ÿ­ÉqÄ–s‘ãÌT^È ã¦æ§�V6`àH®u;Žy`¿†–IÖîû¯Ø©|œ€bÓŽäX3`5€5Ûž1Zꌠ5`Få8ÊrER™•ý^ÿ^ñí9f(!—I:®æ`˘‡zÿ*ƒ­ŒRPcže’ƒc}0¤ê÷Ëkò…“3×4¥"Zþ”íååç ¸¬žM”Ó`{vÿ×�ðêóè¯o¼Ÿ6º}ÊÁuÔ:�ÖMVÕ_¦Ü…õÕí¥ý¿¹5ÿݱñûòïÖÚ#ãªg‰´â�À®öÛ3» ç˜Ë v³Ÿ Ãí¿ƒ¬—çíÛïdzH§±ž;pǰ²ƒã’SúçˆzEùWøø;¯WXŽ1Ö�@kþƒšžæÏíÐîQ@÷ öø ±‘—cn“ÿ¶ûzfõ¡8—U– Di÷³áùˆÃX¹»Ð!‹€ÅâŸ`ÜTÚ]u$æVü¬Õq^Š‹×G}^Š]HS €@óm1@àsÜÅ�ZUúÑ;ø9ð¦4eÕç"ïWü°ÿ'rN1[ýÿ³¶aWw£)&FÿkßÏÄŽ>?½ç9!{>2‡ÚnÍퟹþÙ8¦#pÏKåàûú’î§–­eLæU>~ß­Fx>¸Rý,<~4Îu4K»Ùzžoç÷ïw;o®¿ïy$;ÔŒ‰¾¬¬8€Îß9`NÙþõ!¿LŽa`zÍ9ˆPcÕ¾ªLJ¯¬1/ãüÔß÷èxÆIæ`îß9Q€ß©q& ´C ±^3”vW¹Á°>k×›õû´þÍì—G°óf�Æ�&:(›ÑǦÇe{µ}•!vœ fϧ˜`•\]C�aH°ê÷**T•S"Æ¢ðµƒÕ~§kfdE‘Ý?6§Þæü5iVîgxF<ËüêÀ—îÁÎËÎ÷f€±=¿XÊ´Y¨*ÎÛo¯«Ê63R¢ñå(ÃØâ‚“øå–{ÕúÚûW3ZÔqÇL1=#fm—L¹ä`ï‡CŽù€¹ÉÛ“ : ÿz|!ÀU“þ«×¯Øx G^n=×^Ö/ –3 Ó,À2».x^[^ÕÊ_µ÷‡’`Ì€è×ä:¿Ï«Gþ| Í$€2¶P 1³_IytýÄ[e€•¤±ü ¤û#E\¥ ÿs[Ä߆€YÏA&Ìç ³ ¯€Ù8%›‘NÖ²p¼e¤5`˜µ€ÙÆ?ŒºÙ½ى$J,²á7‹¬Œ4¯ñ÷>QBIÅéCØXÿ0Æ_’sLY& 9KK€pï>Ô}d框mÕ¤²uÃ$Ö@Æm _Þ!wÈ!"×sÀÉãÀXö‹÷WRKk¥Ìû}„ÇMr�� �IDATe9ÆôuE‡,Y5“üŒÊý¿’\ÔæÇ±ÿÙåØQ÷cæø÷¹‰ Ç÷Ïa˜@è×ïd‰­ÙÄ{ãOwÜyÛ£W¶°ýüs^ý@ª«Ÿ•Ù~›«7ªX‹ë·_»ýªÚgµœ[æàÈ�'5þe†Ì®‹[ŸZ™D"ä÷ÿ}4^V±Õû‰¯Çñz]R·Ö/UóåŸ(ù(×Z»«NQŽ^æ »Î'wYŽÍ鲋y°b.Çï±Ô&@ËœÙ& Ì´ƒ�cóoÅ¡H\_,ÏKÃZédÍ�£ò·ÿ‘91;¹tåk/ÝŒß#ì|+ó7î±ð9ÙÛ¾KôuQýÆöŸ1�ÔÚc#„/¬ÎÖ�¹Õ÷Péý,©©j¿ä2ó÷ÿ*8oÙs=3”³LÌÖvç÷๱,`1ÁÐ Æ™c§džìÂûÊû9øèZ‘`úy–ŠdÛ±žÖÖ,Yî0ß.Ϋ~'<�T •ŠÇ­ãÒ…Êaß—«Œ ôU®O·?2†•_¯�·š$žîOÎLýÕ‰ªgª§ö«v`޵¬ÿ«÷˧|Ÿd�ÒÇ«ö)«ù}òû7¶Wyž}©¬P«Œ2u¿¦õU÷G|ýrFg7’Â\[£KYx©r«’‰ª|<ÞœËïíPÒŽ Ö°[±¾Üs‰ÝsŠéÜb¡¤âo¿_&µx3)©x³˜3 �/Ë`›˜cÈS6ûá¦&:ÚÑÇ&t(%ÂΫÌPéo¼’)…̰—³œS#9zŽ5Ñí9Vbíj¤òk‡xü!{k',aŽñWe\Rq‡Ü.ŽûÓ¦ùgW¡¹*°Z_U¯ììýzd’Jü8•ƒ,?îj8÷÷c `]Ϲðÿ–±ˆp¾¿’Šy“ÈÜÉ&bã윤Ø)ï€ÚšƒG/kœ•ì9RÀ «­ÍÅ™¨9Ù7Q?Þ3y f4G+{;9cÏ]Œ(Å¥c’2Ï2%!s*.ûr2†,þªͬ÷ãY ÒÄvþž­ÂQêi;榎Ì Ö>°}½ãšåõ^3Fý~g„ñýW˜}Œ)¡‰úJ×®±ƒßcëA›�¯÷d?¦$ÑÍI!;®céÂù>Ü`¶'òQó{�æ\ÊÈ(aÌ [î&Ò½ß"&³ÙþÃï'>Nù÷¬ÝÎl•)ÆûeKÊ©½—Ô¼uU²pÇCž—Ó—«Ï XËúÃK#fß]¾Þ*gWôìm£Ç æšbÌåÌ-ÆU@- D>û±öÏL¢™ùõyË öZöøò§ßÍ\Û) ¨ûg´s+÷_ü>²6Eþyªøt¯sxgõDËÙ|šëã’uhWsbåýчÚLá5ég$V¿+,Àµž“)¾>Þÿö¸ÞnÕñq«¦«IúýãïuÏDë¿q;?/±ù~~tF{ìzkiÄŒi–í—µ»/g€nëùsXŸÿÚ~÷ Z^/ÍÜCÜ_Šano µ�x)¦W•¡Ö`?ZN°ÜZ3€X¦5ÿÓZûäû’HÇ[ÀK”ëaWûËK*šã<@Ö—±^?‘‰†å9Ë$E8ðBþÙÞ¨[ú!ð¨ªûkÊÞoË3€†23S ™dÐãÕy½Ê…ƒvŒèÄÈRÜOõ®$rp¿¼ÿc@c c±cn¹0ží­OO•C®:á]=ón}¾TÖÏ*·ŒN^­¿¸r¬Çœd–áY‚¨8¬ÿ´íŵµ µÚªs‰e¥sÀÅGìóåMnW’ €‰ïè ØA@fwëU»mÿévãóoÛ?Ÿå´ñR¹@Ä~ò¹p©�©]¥3¼õÈÙ*TÒ’ãÿo,šŽfèc ª* ».ÈÏçM8�S} ­_½UH¬Œzðq ËÛӖƵ]7•û‹·r,ó÷êJ}¢œ» ȵ@…­ÙE>ï›�L|�\_;jíb{5Œµ·J¡³ïÅŒ»¼Ä@2Ë%d뱇67£ýÛíWDà¼_)b4²Ñó8ÖžÊÂø=…÷ 2éæý«’nWSóѺ$"3ïðÝ �¦§ò8›zŸä°?žcŒ—¯¤ ½©ñÀ÷¨T¢fpUGf¾Ë¿q¤yÚá˜úü ‚9²®åÛçïÒ6êGˆ¾ËgÓ’r'3ÎÌûYéD }]î¿Øë ±Œ½øû[ñJÊ·÷g-úGjT(T¥Y}/å/ukŸâ·—uº¦¿Ï4ÎüxMŸ_ÅA[z H~…_ïø¯ŽOˆPüjyX<—Sõ~<Êüµý³~=ûñ|ÎïóZ�läõûïjn/}žÚýº |f_$9Ó±ÝÚ˵~­Ù¾^Xk¯ÉõðõÊBŸ©MÀ—±¯ÿµÀQ�Le’‡ e€³‰YÖ; ˜!s-“‚œêO>"™8€¬Û)8�öØï?#§2µhùÈÐú ˜dÁïÜh�ÆÀœ„"2ËÌò ˜`¤¡Ò‚>}åF¡Ù‘Š9ƺeÉ«™Ý?l•Tb/ç¶|º^§ ÃãQz‘Mx£ú+ã’&£‡øDÜ ü¼6‚ÎGŽúHÐèC|XÙ5¿ömî Û =L=—A–sãh[åpUׯ2Z*¥Dý€ Î@Ø%�š­_ËmÖÍàr‰Åœ‰önÿç­ œu«J|j&“=Þ:5Ð…Ç)fXäm°?™E{¸Ÿr¤"À㾘ó@oê7Õ_À³å¢Ã_—„ç·ýézqi èÓ÷ժ쟺ª¹3©W½ÿÕ¼#á Ûw•áó‘l·†�XæîSvô8_BU*×óçÓÆö,϶ÐP*ÏÇßw£^qÀÉ£ÀWkðÉáÚ!6z–KÜÚùã lÕæ‰œù°"<‡Òˆ­y:;_åxÖ¯ÙwGï'Ûûý³7 $nS¿FÊQ¿a “\÷RmÕy'ÿ~˘±¬¿Ë8€ÏÓ\»ªBH%GXÏ…urýë×:—âzÄe(:·ÙZ}²ãôyŸ;Âêr×"ï³@·97™RdÁå,YôF’È,ËÏ™l[êO˜—_o’†³£š3°œS´ýåæ ‰}½ÝÎsÈ»\·ë½¿ªíÇñug)±·f¼+̰1.Úçsáeæ™>v9â'àÿ•òö†ÀÅ*ó¤ xdççåj[ز\nþüê<Ù²jÖ#{?u�e‡rŽ…Tk€ÂÖÃ3.ù~ÊTŽ0ÓÏŸªÒ˜ð’õ‹8ù}uü:ðþ𒀪T}Ú­¼Ús ¥×]ªÜŒÙ™K|ÕšèÇS`ªS ©&ÊSF(Åè"’†%IÅì)àŽ´Ó”K±ÈÂý¦Übv{Î$3åF†­  l0¼ºTb¾î¹ÅDް;“Ìœ#ÐVÍéeÍNPfçuÙ3æóíâƒm^?$áÙ-·æ#G;@vAf‘LÌêÓÈzÉ@#Øô€Æ$].÷>TXI´Æ>ìT»Ïð3|’y<? ŸcY\»ß®¤˜V'@Õ(†H\ÊÑ8ÜìŸI/®cV’Q112ò €2ÿaÅϯåÿ÷€ÚÑû¥æ ¯?OŠA¥¤íÈôð�gšéö¡#}Ç©Ö×Qy‚•$ÔÒ‹¬Ösý³ýp»bƬ}˜üßò´¼å’JWÓá�ûeã̪e’†ÕõUIZ.9œ1“Zq\óø}‘AmÈðäGgOéa >Ùg:OËy’ñû­µu¦ :[«8¶v*>3;,ðe…Xeóü\Õwî¯]ìw_̧Íöž¸+7Àù"jEb¬ÇÛzq÷º<˜bÌñ=Ö{Àq%ÀOKžk…ˆLJL9¬çriÈ$ÍŽäž™’ü»è£ü¼T”Cò� Å€Òysÿàú&¶G=ÂêS 䪞Al÷£sÅÐÒŒìjÀ„o/ŽskR—üKoþ^F F ¬Œ+Zú’Cl¼`íŽÓÓ}yf‚}Þ÷¿ÜÊÁbwžw/‰øí~a~…('ü Þ3ÊÏõ/¶›rŒõ(Á·¥ïå'™{ ô긦}hk#€V<X3•[«.I–•ÇË÷Æ_n ¦„}yUÚ®*ñ·ë£r^åý°Ãñh«ÚX»ßkrœ?olê¾Óå!0» dñïæº4 -w]ª³ 4ÙòT®Á*€¥€GÍL­Žsü{/—Vµãµ¦ðWº¿PD$Åkmy}7°UëIë‹û‘aX¯ñF±ûÎ �ó{ÝsŒõÜc­µÁûØ”Ê%'�Œ2¼~ß™`?i®° ø‚ò@3ÿaÅ"zZ‹'<Þöàbûn#Ææn?¬'‹“㊠Ö×ppU“ÖÎÇÝ-ûÀ‡rçˆ[Œ¼}ožI¡úɯ÷>]ú¥e¢úU>zn€vû­$ûv6ÇÏ­¼öfüç̺ôÐÿÏÞÛ$É’ãHŒ܄û“w©YdvŠtÕ æ–U-ò¾ÌE_*ä™Ç*¾…ƒ€B�Í=«kF‹ð03ÿŒF#¡P`OPQ˜3,”¢1ÊÞÂò ÿe¢Ô’ÚYh ³»F_¯‹½Xeðª€9ŸÏùðúU€ñÿÀö,`Vå«~{ªøè-/OQ Ôí,cE=gÔ=«—£œµhûë¸4™ìÆü«bv­÷’Ïq¬Ç78Ïߌ †åi© 8ƒ¬7þûØå'¯÷ãh¥ßgzáuªó/rªÞkm°rNV9øx,Ô«\gT†@Qv\2Ma1£°%\4'>ï\¿s†º’µýC×ÓsÝ\¸0üòèðáßóéÒS¸~ï¸òÃz¢XW‰s?rÑPÍ»TŒç»å"@ÅÖéq_߈Ìcsñ¥\˜!S-ßïÅñ~ß§y×è¶7pßs`S2 =/_íî*îj@û‰É­ù=ÆZ»1Ÿ»Ì/L¿¾›¨Ø?·C¸ÈûóöVåEfQ·?º+ÄÙïœIÇÞ”Ü 7yÜj¦XÅæwz}=iS äúÙ1¿ ÌürC^öÞ`L1ÕnÕ\¢¡Ç§à=€롟S½òbÒW´ç&07‘îñ}(¯g°®T̸÷ÍôKøxØwñæóÛ½^‚ÝöeØÕ ™„ùcìWÍ0ê*WñË¿+5àT›¶æíRçc*í»DôRÅS㼚ºã{w_èåµHÿxLB¬ïu ʼš 1dhí2¿ÆÎÕ¡Ë ÉÜú壀2¼¾ ¨!Ї÷ÿòñÇ’2¶ºLŒ._þ÷ã·ª? Ãüñõë3Zßÿo`Ю;`Æ>ð6³0ÙY .Ñ Óérd˜ß1¸«•å"+w-ÃÎcýíFì¢îá–¾6–ÝÐ5ƒwk—@k‰±Ä²üÖÂôšöËÚ0®Ø|îÓ…öc»Û–÷:Ö ë—‚ÐWçŸ#•‚®{¯ðœëÏc×ÕZ7¿¼–Ýóµ"pÏ5XÜ\ª³rÉØµ˜é{®ÿýiÊY`÷±ñ‹ŒµøöfÅ4«ßã¿Zž lýÕãn×Ò\ÇìÂ_cpÀu-•ëÄn¬Änþ#“çSVtŸzå›>ä’×ì, õ<µKþÜÀÕ´Ž°Îˆùw ‚2Å¿<Ö±gHùõò-¹¯ªgU_fˆÖ6LëaS`ý|#1}Q”‹wU¯<Ÿõþ “‰1â2é<oT¼/&LþüíJY)¤Õxb þÌu:¶‡ÇFà+ôm>Ä CfRŒñóœyðñØ´¾ØÕ®�•ì)#“«kj¡ú…÷ó<_Ç4ËÈù~ØñéBáíéÆV‹.J«÷çedÞ©÷ò Ç=ÃÞ*ÕLÿž¸L4ïÛd€}€žg2Á^#H£þæ�½Áá�ÿŽdÏ÷ú¯ãl7´ÅÖõª’Þxî;¹‰W\ÿ>ge¿=&Æ.0¥ŽÃe×™÷Yß9{çû�F´òíh½ïµ¹ÎG‡¸òõÔó‹bhùújà±k²kjºËŒ:—bBgÂÍçÒ5\;ti@¯2PéºâžõéŽÇqêþ¾¤;Î.@E®Ïû÷) « ´Q&WÂkIU>cˆýcâ€*¼&Àö2¿¢ E« ™`sì?àüÀý&Ýç}L²ƒ.ì]Y.Z IJc„šnü±u=…Œ*”îÆ-[`.@è³ÝŸö¯å2ÈÈÆžZŽ‘Vßia;Ó1€Œ3ë¢(ŸäVìFåþùt Üy~@~Zx¢«ÄoŽ)v@Ë!YÏ‘}Çt)׋>ýU,5CìÜF¶»<»,Ù4¦D—Sü|¼}Ç£¸ÿ.q’+N• 7•o÷üÙtºÿ§Ë³6>ÿ^röù쎧³.TÔ8ê[¤vV9l½oè ± `U W5_øzÖ£Í+‚Ï\»Œ°ïŽõ}9ŠëXn/uUú¾Tó=aÈpÏ]+ßûëŸÌEÓ:^ë4nU]Ê2þ Íe€f™aY½+—áΰ¬,2áÖyÛž (PL VÿÈTZ.3¦dl„ç®Ä|{Ãå"Ÿs>³à:Ëaåç ãŸa_æ=Eøtgç¿ØŽ\â8èûpè”»èä32õÓ¹ÛþŠyS·ó¯Z'팉h]vZéÍ·1„À(òÙó„ãçeÔ‹Ôùk�Ûþ¾„ÍXa÷ß[`~ñš–ô'2ÃŒ\S=Žb&b»˜ëÅŽ‹È#MƒÇÞs25`½§ø1¢æo óÂÅ¥Úw}šw•+¾>c>_V ¥Å�ôÀŽj�ä,€¡úŠœôßùn=ß¿ž‡ª—Ë óS€LÕîªþ»�Ö£€±ßt¾]“<_gW8»Œ7ÞÎ3š6^_ÅäÒ÷Ïvœ>è~óåéñKÏׂ- ŒÈ©˜_Ýü#Œ0ÒTºV{~yùmÅÖúüýûc´™c_�$ÂûÑ…âðR ±u^cŒèJ12Äþþy>Ä ùe ½ÌWw×Ò4¿‚ãóìRèp€hHÀl§ž!H9`¢õb€±ïcŒ‹Ùð·ä#ºQ1,2@/sUãEC\ñ€––ºÿÆà�ÙŽ É%c€»0ÂûÑ•Í Iì]~OêíoïÃv éùBã*ç(á]yÔ±À¾ƒJQ]Íãª\/ÚcÏ%c÷ý©�µ]—:ñ¾³±“zå<šþÿvyVt™Œ]`¬²Ôxü Ç<_åÒ4ÆþâÀÔ~¿U.]œ1.ï¿<ßÊŽõ, 4Âýÿ*EeÞõu:ÄuÌÿùwòyLõ´¡Å�ÙýnœnˆªÊ° ]Pùëz¤!ÓËBøËê™Ïõ/_èR¼»N¹Â”)t÷búF×îöw¥ÃúBQ®G¸3¼3¿óyûz_il¯àfÛ9c÷Øü•§ŸÏOqÞ¿?kô)C=Ã@%õwîQÅæÇËEWƒ±'ªò<sH“¸C�î¹Ìá ´k 5.c¹hhÉDuÿð}m¼® # ›^yØÑí¯gì:ºFŒ€Å…i¬]oËâ 2î2á@Õ5üÎþØu Ìb1âwÍ*b'#ìþ»§XÇyo½×|M õÀ®býD…qÏkÌoî¸?ìy¨]=ö˜\‘É¢úµÓè~_Ãu^nûúé9ŸwÅÌ9']àOh¯ÐÝüûŒ+loï}ZL8>êöî1èvRqÜUŒ©¿ÊcÇ,Çÿö…3CÕx©biל• ÷j>­žcºîê2¬ÐD.tÁ˜¸:T®Ó_I>ÓÕc ¼ÍrL½Ràï—?†¤2 ,•?ªóŸL°ß)¶Žï€Ut½¨\7ây�ºþáŽ'£Œ¹VT”t´D <Û°¡e'.<º–n›¾ü½Å&Û¨ò`͘ŽKØ š´þdcO}îE º‚QñÙŒI–MÜ•ÁÇkcSYr±~³É*øyocüSgþþo4?´ØÄ¢;“ÊrÿJÆëý¸R8òßšËU}Ø+jzÞ®n»»Œ3¿Šµ£Ý]×iM×M‚ †××væ{¹…ëM�j]ÚN)×rUŒ4Ìgוä8™þ_ u]m>Ûååeó¼ªOépÏñ«U,¿o>gl]ä8Ã÷`Àê¿ÏU>^º. «åüÞ¬ï<Ê™6?ë¯Ëü{¤¾"ñü¹ïȾäã`õ7˜³x´¯Ÿ3¨‰†Fv½hrÖ•õ’+SpÒú0Ã3ö<÷\ íYósqˆ±¾:Òmg–Ÿz®CnÜáõÔº1cް˜gµ¢Ø×‡¹xÃ}Øž‹²õ~Y[‡e€Ù³Þ <¨ȾΚ"Ü¥bjiÆw¥]F�éÞgajŸÏÊW�GwÿÍŽ­pÃÚȈE( ˜î‰Ÿ×8ñ† ØO±¾ýPw�ì&ûm2ÀŒ°F?*ý@¾º…ßQ¼§ºÝ^_qý¼,¸«XïÊbòöýë$g†=>o 3e¸c¥�. ýüWTJrO»Të2Z8cí]´oÀõ}ås ©wy½bü¨öðü1ßÈ|캶̪Õϻ̩)ÝYUÏQc?¨÷gwÇØîÚ²~Ïø{_ݧ¶£™O®TãÇÃÉ~3ÀÐïc8`ª 4a̰®¤À™à`öD‰-W¿ p!øò›ÿ5RºRlI�Î& ²È£L±!\%�¾ÐÕâJ'l|q‹*´h´�º$ü.Ò š¿´¦ “ ”] „Tý8Ý%“m¬3ÆØÛX®¿Úib|Ëã—|ÿ*Ïw\AÚiõ—eÐÍ~ó‚±É¼Å+Û€ú…¾¶´C/àÔÆ<[8w3Ûþx^¹â›­D—J*¿s²gÅîTgýÂk=ÿ®Åês,VªeN8Û_¶œµèßW€fr­â8ÏÇåÊ_1qx¾}¯?—�ø š®ßOXŸžkI­˜úY\¯$¯¿RŒ=/Fœr¹ÉË«]*ýl¥ÓÏSCTlóq±„ç³Û/µ‹C^¿ªþʵn—75Dºqòúþùy=ÿOþL§û;ÒÜžÑιŽÈÕú;Á],ÇûâxÚUÔï®cîcY&OáÂÊœG úùý¿~1œ<ì0©tþì¹Oƒ®Š…dcøu¯€•Ìj½¿WW>î+B;¤Ù!Îs©¾c™ 7Îð˜ÀÊ/‡c8 P±b‘EJ|yó½Ècøâûô|Fè”ë)@­[“} \q«cú ¸þX½§T̰³Â�@;)WŸcDàª3o2pü}P€Ÿ¿ïFÞÛ=Œ¹!0Œ2&¡š?Ñ% us¼—¸\NfØê© hû.b†åz‘Þ8²Ï­šo²ïÉRìVÌŸs3ÌEŽ—ÓI3FòãZø£ÇÛ‘g­Ü¸ë½>�Ö7õ圫ïkÙî“èU¶¨ˆÚÕ”TýY_ÏWôõ{•3¥ †Î—¼Š‚Š…µÏxÂr÷|sh`±ê‡®Ë¾.³´Ÿ]FÛcë�£LIwþTÀ´šGε+>Ïcô™SJHL.<Ñó„ÁåŽ ãl«~/ÿk¯]6†2Å�û{Ý ùÈÀ¥âˆ1Æ&ƒLc�ûøcaÁ“o8¸¥Z¸ZטoåJ€Sþ=`ƒ;6>½÷iÍ™:¶|ì­^æ ÌË (”'À5c’aì1ÃC—3oöÊÏ·_þ<ÿæ eÜ(à†¥žp�ƒmÐsW2ç-žò˜.«¸Qç Ô£«êìòq÷¾Ú£Wl^Ã8÷ÌÅ�Øæ²Çõê.CºÄén,г�Û¾T@\ÅpÁû~¶Î«Øf�v)�5<¿jßhºÊ¥]­ì1õð‚õÄô•¬öóXT—M ­ú"ʧ¯˜\7 ¨ªò°¾¿t?uc}ñ~б¸ºï¿® ”t5Ïì»zÝ»®k rÂ0ßp SkÝÍ †røì¯›GíwØ2SŽMÀ3«gOþ“®÷”§»¶Œ¯š‰à$òÑ-äOì:¼g…YßÎó|Ë®Ïõì4ð�»á:¯Cl^¨’n,Õ~oàç]#²u–wÆûk–wƒßU_dÆ(æA4 ôéV½¬ DÜg1Ï Üõ"Æþª˜\h(öî÷ÀçÙù¢z_nåHîͼ»†"Kº+P/çÚÕÊÇIÅœ9'èRn=«]º\(w=ÔLIÏ$Â~Ë©]¦©Ïgûs†ßͤ¯ 2fØ0Ì0 €-ÆØ ÒÅ‘e\$º˜`¦<<¦âç%¯'Àý~&9Cx)¤mŒ0 b¬²sŒÝ|ýtçv ûŠc]Cvt{@Sr¯W¾â휱õZÎ7­Ë¸ HÙR{ÀçÞ¿:ÆQ>Žt=v¯WíÃØgy~¯Åýªž‘éÃû ¥ëú²ÞÑTý°+ùŽòuû;\¹†ì®;©yÎ ¾;Ÿ©Xc±œ_Ï#¾ÜjÞ‚úF2ÅFvLe(ŠA¦\.¦×™él2ݶ䗱b†ýãó×Wø¯ßç0Ä*ùmcŸ1Æþ@¦ØËßÑå!u©øÿ\æõèâà*,¨ô çŒWpè7‚g|¥+ ?.€}y‹QƘg,6Jwû}Ü2 1Ǽ‚Øc,ßïâ:[¨ÂÕ"Êd’cÐS¸qW ºe9Ç�IÜèt˜yÌ1%^ÁvŠýëW0ð=×zµC…ÊRÿ:”ÂÔŸ1ËT *¿.u®_Î.[ºj‘£øÝ­Ï¾ä1™ú.9�¢4©óœ‘£€¸X.—à‹±Î<€S}Ø?ŠI‡åE€Ì÷Ë~Ðjß_�†n¡~ª¿|~Ýr+Ÿ1ý.P;6ÓŸuqÈcv¡ì2UžÏß�� �IDAT´*&k5ëÅòpÞëBI{PÔAþÛ鉫Èﯛç°þ* O¢ú)2Q<ÓG¯^.Åõèí »ØS¦¡|ùðÇ ÐŒ1¬¾üy"ðSÅžÍÖ“_ëÛiଡ˜5ðb®ÄvÅ®“­¶cÌÚë–16Óg1ƒ*Wȱ1h”Kzß$°coƒ×§rEÉŸoÎ^�Øbˆ}OÒï”o¥ï±kÝm8Ò-¿Kì¬Ë麿Pç€Ó~¾þ8þîÈÙüò÷¾ˆÕûrÀ¼ëÑsáwˆ}ùÕ1-—žc15ÕüYoöú«éá;ðu.çùKÈŸÔÿ¥ yë—+Poa^äŒZÖß*VÛpùÌØ`ˆó† ½Xe±>õxñÒ[!)Åñ«Ô|ùó ðZûǸadhF[o^[÷=›¶×%u}Îî,zßìÏ ÔõΙfµËBÕþ}{oO+€lj¯¯®ÊYŸC9`§�+ÕÿØ®×߀|ž­Ûÿ^ê~ÏÇaÅpÔ1«t)ö*ô‘ýyljq‰ˆL1 $M&Ø<o˜WU9._"»çgùSÌf$&•à2Ñ##ìïpý1ùmý¾üï1Æ1vØýz<?b“Aæ§|¦¯€±ÈäÂvmÃ],"%Ým6&Wî3¿kqtˆÖªÍ]°\Ê xKÒZ”E±²v>ÇAA b‘Ùrès0Œ3Üà[…‡v•£-C/æûó_ roY˜1I9v.æWϲüúµñG Wtø3¤÷½±çB®’¾ìž Æ”÷ Ó5Ùk_¯Þ]µÈ(Ò=KRoŸÎŽƒ*¶Q8(†ãsAÚ¤Š†Ç8)`/Åvƒü*À¥Š¹u+)Šá¥ûIň˟ӭxÞØ_qTÏ4¯ÿ5÷i¦.?Þe|Mé2¿ªzô7È]ñ… `Ÿîhn¤þjÃ%ùû¤]ã¸ðãøLì«]Á°cD×]¨¾|) §Ô*™¡•ÍÝ®« i بS1u» \ëú{Êd|M¯ ¸ ÿJgîS¿J²Øaœ¿†cïÒmˆñ}ávÑõ MŸÅüšé«õò<Ïþ<voUn·ÿÖõõžÝÇÑÏÏßoÀ´û鯙ÎO‹bôa¿aÿøß®)COj€j7LHõ]$ÆýóN=j·?<# ûåV|YÙ{±ô*éíW±^QzzÅÔõ ¼Ë8£ê­Û5P÷ßåbžv ú!˜^†!–HìW¯Wñ¡0&[ç½ãžwzÿ»¼ÿùvûý.W÷¦ _&ïÒ¤îGórÆÜ—¿)hß5 Oÿæ¾ÞE×…}ÆÒsÚ©¾Cp¨�£\Ù:ü}9ÏLÜcT!У�JÍøº¦÷Ey ˜Œé@©òåõ€rußc²?ÎóçÑev Vkìºë¶½÷´fXR™@×F ¯"ümÅ$KÎ;@Ë�s´\�¦.}™ ²Ó®`5™h��6ÏO¦Xˆ%öÉ“6cë<Þ‡.ݱ úÊ�2¿ ¹†ëó¼²R»<VBáÂPs—‰k¹� ]­TJUÿÔ÷tóÉ�» [—q­˜n@Il3a;:Låfþzà”»ð¸ÁýËõÄp¿Sv‚€÷\=TÀöŸ®_éË…—Í7*ðx>K!ÙWizÅ„Ð�Y·äîn—‰Æ¯v]/Ž"]—!RIW}Ï? ¨vc-õ\ƒÖÌžœqÙðøu )ጷ~,1U¯^l­¾«@ÕŽoâ÷,3kiXIŸ/üœ|¦tÕ¢»Ëîºg[²ô˜§qž½ŠóG‘ïó`=`5–÷º¦»ïË5�iƒ¦ëÄ�«\!NÉbÜX‹xæù ¹eäb*­` (cC*MK€,¶Þ¶±ÀÞ†À,cI­ë™|çyÙþñ½æ]€®÷è*ÖËúM¨L (eíìÅHÓÌf ÈÍô9‘þSŒ®¹žµ÷_Ãz·›ß.ãÏk| °ÃÏwg´~,Ò½zwË{–Ô 6_¿n=tøý™äòç Þ{ý\Ȧgç}}cœe zA=Æó,Ëß3¸}¹ ôÀØêÉïÅ”3°4èÐí¼J½3üe¢æ¿ª\¬q½~Εa®*óõçsA&EW¾úéYÜQßÞ>CE6x½¨—r&TêLÝzvûm=90² <+6J]žkÂ} ™=ó¹ç@h·½*— kæÔ¬/Òt̯S ¦ãeJ=αò÷ Ïè< <Võ¬€=ßïèR1"#ðçÊO€#ú;� "±ÃZùUå XU.éñ¨]1ºë CÀË1Æ^~û:v@–q­¨;ç°B€ÊY“9ö•Ïd€-€ c‹Aná¼ÊÄ}vÁ]<Ê¥@îÊpIåâ£r5€’/0ù‹i_sÆpcŠÜPW@­Ÿ‰Aæ\É˜Ø 6ì/d”ÀŒ¦½ ­R¬hÀì èhæ]¿,…ëGCÀ—Ÿm|{ÀZ®¸?÷×2œýµ´Ï3(âgÓÈQv¹VÏWÍúÜâØÿVŠuÕ/@<×ʳõÍtõ}çOK*—{]@¦ÞºåTùux–aµ ªò÷bp­q¸ÇÀªŽwÕb»ãv·}ü¬y&‡Äcy»@>®G®­ûºùÿ« Bcgcï²{­ŠéÉcÙã®E¾Í/s%å4�R «ø%@ê¹nûOªþ6ý1Šu(®1¦í�&–­5Ì ûƒ—o­uü‰È ©˜n¸Y=äëÓQøNa[ÎÓŒ‡è’ëŠÞ<ÖÆäÉ�Å3ÀâªÅOxOçxZïñN~™ô*xœUÈ È§+»œãÝü+ñŠí¢P_çrý؆J4 dqþ`õçãäû﬜1â{¾Ç$Z†›Ü ·v‘Èò‡t3˜Àf:.ÙÞê˜6GQßœÏ*׈YþïC혞³C®.©:9sMëçÇkvfØãðW ÷% èÈwºðé1d^ƒ¢¾kòŠ÷ç;ˆWÙ®ç2yÞÅw$2õ°¿|z}ÌÇgŸqåËß5|-Óïºöýö*òíÆ–Š.÷XQésQïÑ{U>•p 롞wûkHíÍéýp§ð^½t?T. wc…1ÒØ]Ul/Ì÷G–OC0]Ê<c€¼¾úG~ÜókŠÂæñd€Ý'lÅûìºÀ$ó¿ˆ{á 7æ«~ž¯\r†Xï» î:&³t¬c M]6lþtAÑà-ÔŽv}(3Î�`tƒ>c °»!~²ú°iÄ[ŠòþŽŠšÈ¬,áðù`ZÁ c’1ÅËù Ö¾Ÿ–pv¥Ƙ è*êh+ܤ{®kFÕ”é÷iYh‘ƒÿÅô<¿>×KݯÎÎò‘‘Áy®:]—Á¶·=«Ë鎓]`oÀñ™òk9ëú1ÂŽ6L•·Ë�Ûë— 0PýÞµ§ëŽÏ³LIUn§?Ÿw]pT�Îs¾†š©Â[^oSg¾*¿Gû¥ ˆ¹Ç—¡ÇbNOñ®‡= }˜ã7w^Ö¸Hdj(t…ׇi‘^÷Æõ`¦ =̯MÇÖa]hpE²¸B Ìx øÎîŸ  |f¸ÕU@WL£Øûþ{.ßèo܇°òíú[Õ/3¸ºŒk³u,±Ìƒ†ŠåÔîÉà(˜È̬+×÷È@º…'žy¢öÊ«¾gÙZq_™ˆœ+G#ÍÈÛ/'cŒî”g=¼X#sŸ‡ És.ô°ž‘™Áªž•g™›s‘0t…xs÷­_'ÐÏÓuâd†}ØñÄ™VຠoÈa ºÀ8º†ÃWwž)8w�x5ž÷ ®°ôƒÕOݽ;¿aLWq\3•üsЮ 9€†@K›ì½˜o£kÅîWõ÷í¬Êѱ”T —P¢ûGÝÇåR±ª–£c•­÷–·¯·s¬€-Õñ<¿¼Ÿ�Úí—X~vco)éÆìŠL(t)Êûãy;y¬×¹ûû :Å Ýjb~ùQ\Ÿ‚�—Ò~oæ§ê¹l%éÒëÛ.`L±Œád ö ðöÇŠvÅ›Œ²ˆCûÌg‚–‘s¡uÊ·˜E ´ ÐÈ‚rWÌ$.K±e­Øé[f¢d̬à[Ý((ÜÆ‚”1ç)HbÙzX×;Êe¿ÿý•[6ï9¹º…c½!äØžïH\€FEAöÜà2Ö¹Â] ]WlÏ Ôð z  ð…ÑÊ­²¬8#»“ܲäíSgÝFõ }6*¾*GgÛñ¬e×ùíéY—góïÕW_çùí>‡gWg™¦*Ÿþýg¹l´«\åø_ëb9kY×u¡:¯]ÖþkźþNÎcý×±g@ÇõƒvíùžLp½hx–vkÌ)Wºîc�³Ä3|i-‘άߜÁa|¹ôâúW?àkŒ#Ì®·».óXz;®òõ³b‚\ƒbZÅþ©êÇ®³]~?rà „Ü /îcÖytÈ ­äŠþÉÈì¹HÖ1ýö�LÛ/¼Ý¼Î~±*…r-çLú %‹äÛ± Eï¿Wwü¨,@Ëõ?g‚¡Ú]¹1yÿàüÌ€ŽG\ì/ƒßÌ~¶ßãJè­ÈŸ¯Ÿ5ý:f=Æzô2†ˆÖs‰¸úù»øå€5g°öC^ŸŒ°ÙÞ© Æùr|õ öóŽô"ueùçå"ó¢Ï(R¦½rÂðRõâ€UáZÌäïß¿ê9½zݳfæ=›a¨ÚW™V+ú=¦mt•‡€Ï.�ÆËAy/�ÍìÄëªÔ¼¼Ê}Ù(Îw¯Ýè.°¨–Ø«c¯í™*cyCìqFdWc´[ÞsÖ;Àûò¿$p•2°Ì}Ý`»L¯ �«êÑe9Y€XŸéõ÷1(3,0¯�µÃ(›@–Ö\þLÆÆ›Œ²˜…z1F¶óÄ,øø]bðYîZ†o ¬0K%¬7“LA (T„OEýrm´>pT1‘ôkåš§ÅÌCfÙt¹ˆŒ2e Œ¾ÇG­àe 3 $2ÀígâóçlëCˆ¾þX)¸dã\)ê*EÄ÷ñt³UÜò>ZòޝëÏñ‘Nޝ÷B§Xí• ²Ý…¤´Î.dvê½òªÜv·g»Û€Ýeà³€­³ŒŸ«PÐí·U>G‘Ï.Àµ ö–»ÃCgÛýœmæ™–íºÞP¬¼œXÎÌŠ.X=¦˜b¨SÃ<OµjÏ]ûÚ÷Ñ2º¢x‰Úõé�Ö1ˆ²‚ f«àôÌ ¥ðÐç­¢ï L÷)ÌÕôì?åŠ×OA  ¥˜ilYÃsõ4À«ÿ çñ¸ã!à:z�Ëaö ÌeW4ÀÒ.Ì” ÜÇŒ±€(dŽYŽ7ÑU¸7\ù«8¶¾’‰WÈÊm­ý8ãLË«\ß*×ß\4³²»ÎÊçë.câ<c,·ôÇ}E_*€ ]#>«\^Ëü±ù×ÏÁ×;Û÷ã>Öz’•Ž×Är'ÀìóÕ+’·â—íÑSe.â¾´»¯&Ý nŸ¿þz&oŸ5™Œ¯ï‹ñõQ|?˜kGßïëX1jg?©ùH@[†]—)±˜s{RÅÂë»þ\õ`Ç•ËÄàâ€ç%wE%ôVò]kðQÅ.{-盳;Ðs »*c½z¨G]&Ì»<_EXïn»±gû­zßózïŽ×:Ýs•ºüÞ8y-ÞŸ¾ KÔ½òë÷}Ï—‹fþ!pŸ»ü¬bðõߣüøï6pUÝ×ÜõŽÇÔ5c£÷à2qT¿A2 \)—ŠÿÃÅÃc“AF…e¸Ê™]ŸÀ×oÀ›®@F¤Ãx ãk¡[mÌ+ßÕ•‹ëÚÆnXñþª}^®¢ž~A8qÚõ JöYQ�YË¥"ô7Ûp0�ìëþO9¥‚ƒ�fg]Údé¯ä?^Þ²Xã%å�ç¼¹v@E&gb^ä¢oÉùC¸¤»~Cן՞kÇGe_ÑŽ@*Šô¾XÒð¥YLßµ{VÏ=7·î2ñ,ÀÒmMhë©ú®'U?t—Í•š¼jw·ºí®àäª}Ýöª”õ{Ó•®åßs Ùºç,+¯Í7Ï–Ê•fÖŠ»ÂÜ»*<¤ëÂ%^aî]:˜g¿«è²i*6ÙúI3â8ãëßzüñ¢þ:®‹,sßb8 á’b~‘uážöîomª^£·Ÿè¾•ÁMgÆc†f³=L‘ÊcvU_2Î\CÆStú˜dþw^¯\_‡>Ê jÆ ;„‹Sì/%Ì5Ýý|wÑ›ßQ½¬ú©Ï4ËçmÅ:Ó'_q\Fµ}Žd†÷㽕îûq¼Fƒl×úåû=Ÿ_ŒåuÈù¨r™øöÙ^f€÷ÙG9ÿÙz1Å›e‚Y†Ø [ùÜÜ}Cäåèýì5ìçÑÕ¯5¼Åvª÷ܦ«\ÁÎrØu¦@}ƾ[Ïß]@ãY%ûØ`#\½¸ëû.±}Sº;¥==ýØH»®çz³]Ñ 5~™O�­ ï0¿+ÍëU³Ê€ûÑ—_ItQÚýîì2µT?â¸ªÖ ½ö×.A÷d× vqÙH¯4½j·Ê'ºÝumØÕ„(Ž¼Þ 0×®sPë -gC šç|þþž¥ãëz \t)À*ÚªØdÕùy¿jÏ/_@R¸2B¦ x½ü毛c ¨½Ôå­´–1öÛŠ5F%äb‹í[꾉_{}Œ|#º~׋Â\¬ êt±è¸u5¢rÊBÊ˪‡Šp¿ëJ¸±dŠ·4þ›Ån³.ÃðSr™ ²y~eÄ"x^W²ãº¥R°Ú#Hf “7’>sib-ÃQ–Kh‰ùœØ S~ EÑ7P˜ùþÇÈ SLÀ]Ÿì’JÉþ2ö(Îòkñm¾ŠóøßòÅrÕ‚à¬K„!î?»8¸º_ ÚµÛêæ§~»ÀXeGõ(�Øm_÷þª>o÷�åþÆi7ßž¥]Ô‡H‡W¯Ÿ¹ûüc-ª|òÚþ«E?…:¶‹ñu×Àñ)D—‡“1ö]\GÉb e±mT¬/žSnÉ8Cƒ-¿Q²®«õ –6™;óÊ 2»Œël&81†O,æjf•\³Ý¶ýÙº a´åú™÷ô¶/øêá]g¢¡_íú=£B1,ôºr½_ì¾U+îø€õŸ~÷Ñ—ápÑßî÷Á¿YÌ`{>*¾»r êqF—ÈXÉiÝue5Î.¡q½gaž1†|ù׿¸âï꺆8Oྚ{Æ©5b¬¬·äü{Èï¶óþ½(`}Ç8Я{æì5÷³~Àþ#*èk†BO"T°{²¯€eΚ}ü‘:¿W?ü­cìtMíxyu©ùk—AäE¹‚ÔõØË_çÛÛ Tãd*úk¦Ë_c ¸oè›ïàãóÅý¼åê°û¼Q"3è±y`WÞ‹óu{gÿvMuí/œw+æf×sÒ«¼®¤z¯+MQ¸Ç|ÓüÀ4Ï“ëýøL÷Þ'±¿ºÌ³ÝûŠM†�œeˆýÓÝQ»6œ€ÒßíïÇÞ¥âd†™ã!Ò¹|3׊ÞU"\œ�}_¿Óµ¢Ì>º|Û R›¹^6âÉÔ.ð–…Xd�a¾˜R¸p—¼¾vB°.Xh£ÂÎÆFª,0wc0æÓåƒ+ .ÂuâWÿ¡…0q­ƒÇ;̼CÛéÔCÝTOÕ¬c…LæáWkc陫ÐX^®(ÒL.bÊT\殫P¢,÷P¶+g9}E9kSaΠǨ]è¦âöTPÈYKâçBcg™Qêùì>ç³ÛƒÊnpÀ«ÚQ+ÔÝoÝñ:6Ó©ë»éü¯í¾§×sâï/ZËåñ€ô{­¬Zõ¸TL/åÊØ3=újMn(a¿]×i»1À:�X÷úÌ/djý}Ja¨�µ®aæwš·“áKŒKl[v]ÓÐéÅ3÷†1Œú>ø:± ¯3@¹ã½ýœ¬¨õ|© ¦âz®èx‰‡¬gõ¼ù{„ŒMÇÙbŒE&JÖ¯X*šc>g妰ƒžùððV|ÉØ{>0vÖ4fO4£­ë¢Ì‹ˆ]5ÆÀ˜ŒQ2ƒ»‹yÑÀt”*v–5|\ûºËÜ2§`Öq™ø é�Æ÷—Ïc÷äœkDt•¨Úßqáhûe–j 0¸D^Ã|ï²Õ_¶;å “¿š—êý–¯Ïã’sIoŸ5­cœå¢ˆ.ÐXaÝy¢ÛŸÈôàóM (ñvì+è»ýóXz¥è×ý£€ ½üW¿ô˜=g]Æöpà{_ü8Ùu X‰»@í(ÒW¾lºíõ¢óÇö z¿~Þ».ýùnìºØžŠ¡™÷OLŸÏO‘qöûc|üw;ÆÖ–¾Òðþg ‰yVÅû!ÎÏ~pbbûü½‹blE éâ7oØb’¡+EÇ,ûøCÇKë÷Uϼüï1Æoówæ'](*KÄŸ% cÅúÿ.Îçr„ *óMë³¼Ì% öþîBÒþ^Éýü·¿àëZdU̲a~mì1 ì€åðÀ˜dSXSÀÙÐ �[¶,Ã…4߈taâ|BÇPÜÐÇñcÕø溒üùV®®–k+¦@©™2h).\j\Ï”®½‘¾Î0ýùÏ[°úÕ3ÏŽæAu»@×Y §s 4}¶»0íÖk/Ÿƒü×9î™U}ú.ðvÛ· LUd£¸Þ…�«Tç,¸4ðìSÔoÉA™ïN+ÿ áŠï(*†¤êtñr,c¤óýcÓµˆ ư.¡¹aÔry¬ßkÓ);o ™f*¾žàŒ.4\±çßàûÕ“±t_ëX—}­G sìmÜ ¡v=(t]$ÚöÚÙäÞ¿×Ðþ.³ ¯gûåJ¹>»_W@¶â±Ê êçíþ§b*Þ½ôo4ž½†}›6.# …P5îI‡AÇê¡]$抩t©vìÕ ¿PʳDÜžc±®Ú5äy×ùsÃ}<ÆZŽ1u?ù|÷›yD™Òe.Ýó[ï½5¨µó�2«*Ã�^î ÒÍã\Çß®›ö¾Àüñ‚ý%*Àù~š?÷ÌÐó0ÇßcÈèý~&—ÐŽÞû¬Æi+l7¹ÀÐ^Í£uL)~­øVó§R¤#�uÖ`ŽïSúÀ¤ºûm×`÷ÏO €»x«%Wø+ ¦b0¾ý¯˜j]€¬`ö€¢³íÔùTãO÷D1_ûûõ|½¢]‹‘Ï(®Ïq٭糘‰³=ÿM¡'†•U†F]&®ÓóÐÂr¦ E,"­ØaÊ5ã/’)U3Ä*ù‡8žÌ0d˜9f˜u¡˜Ç«ÅÅ"›±Å0æØ�Wlq˜}Û^1ßÔÚ’Œ[$Ù…<Sp0Ë`nñ9hþöë?Òó+¨:¯ÿñ¥À…öd–Í»À¥êËú™õw軀¥1–s3€—³L~ùæ7‰ T$u683]ýÓ -î"7H|#„–„*f]ûcÿvÎsᮩŽÛ].Î_Ïô»‚âõŒÎPû×2Îå«tùWÕ2�™*ÑõâAÓ÷—@†L—G™@Ýr‡¸þ¬òwåS×ëY®v®Ýúw7ºU¿÷�ÜC¼)ÑÕ 2¸æy^ßõ>íiU/üO‹œ¼ �VÍ›¹+BmXÂçk&ÝuP%LˆßÓ)Ö…gôkKÀ7øõíˆë�ŒåeÿSŒÏyŸ]·t=$l1À_Ga쯯þCWØŸr!̱Jz _þ8 yŒ¨}|{V,ÓMå§cÉaÌ¢˜ªc›3¨c®Øú±hcL>_Kão]³”G6õ>í±¸RkÅvOÁu=¤ Öv]£ÇtÑÓ„=Ž.ψ±¿‘^€…ûíaåì÷âZÎ;™kBÖ»Ÿ‹žd4�¤æAuìå^S€OæWRod|9F˜ÂRfkŸÚ7Ìýo˜µœ™·§t1å"PÐÉ·]ðOZážqŒcº}�î -ƤÊÛñ¾½RV@Œn5¥+{û’.×ìT:~v÷qçÚÏWÀš¿þZüªù ºÚ«ä*ÒU”£ÈO=oU—n:Ýîî{âßËçYå7Z÷G—¤½qXÇø«˜W]}ÐY€yl¥{•ó$• „ÀÓf>ó¾*X X@í‡øÝSn ¬ýbþÿ'MŒ«ßÄõ¾8 ʸTüû û(ò­®Ì2“Þl‡p©q-]çì+Àð7¶ÞRÈZ\zÅÇUæÏ®l²ãºG º‹Ì±ðxŽeF¡¡rÓQÀ(¦Ó—Ƥs.gö·y¿+ÿ%Z²Ò)œT, ï²'*hÐuR*_þÞÂøòµ‘XåžUþUÂ-ýÑ…âÆÔ»&ØŽ‚ÑPv±ÿN¢—o\Ñ)µ2Ìx¹#¤C@¢»êú"Ï7ÒØÎ>W•?Äù£øÍãÊ%H•®jg~¿€ŽöóSõÈ]AÄï >OÅÄÊëkÍóÑËØœ©ÕgÞ©ûÿ½dõWnhÛãçË«¹00À+º<ü׊ŠÙ´\V©òߌé4FdŠeM™¡’­Îgì÷”â\ÊûÌúŠÆºþÍÄcŠdë [os¦ûÅÙ}©a;@Mí23Ž ÕÎùÜs†ÅìϫۧXÏ�è‰aÇ-Š_71‰Ó#ÅìÍ7r¾#�±Þ6v–Ä�� �IDATu ”K`Ôå/€Ýçó,A`-g„i&Ýsúi©éϹ6Š€4Fô앪¿rÆZôì|ÇÖ{c‘s¹ÒïÇn¹V!ý=ç™bSÜÈ|É<Ö|O°£è÷Ù/ ø:ŠïB¬ËûaÅJÒzu¬êi{ c†e€  銃|)Òñ«µ ¢Ý׳*�e@>Êå vMVIåÑ»n‹À ¯¯v5˜—[_çóãk»Ý= RßÇó9+ë=Ì]Üi€S _W÷cÖ qo÷{™Ï®«CÞOQ*&×®œ3ŽýÙˆ»ïÁkù^÷ô/ØïˆÎõVg]U¾‡~9›ïC3§RaÔe¡¹î~w¥ÁXS±Æ\=~ û$ä�Ù”Çd(£.�{ù­Î0e–­ü0a­eó}Áòm[ÁÒ‰}µsŸ¯Yˆó…íZ€3l9“ù _ÇQ¬|§£Ë?ÏŒZË;®kl>•e²•(l¦fZß” Ÿ¡]Ç´Ž_DlƒîVìx2ñ|?ê«X"¶½k#€¾ÝzÃü6jÄŽ…·h¬b… BÕ»Îb –o½|S±ÎFÈ'ôþ§ewùpç«ü°À†>p°Ë…SõÀ+à…ß”|¡U1ŠªVî/@wµž+«¸ÿÚ¬Gì‡jDÍüsFáÞ¶Pš];³'ÉÖÕüSÅöâý žÞúå _eÀ°$"t][+Aƒšì»®\Ñiƒ§e`Â\">âŠí¬ñÎcyE"ºDdR1©èºK¹˜Æ|ËjfXúÖe,†Vå²Ú·‹»ˆŒ Oÿ=@í5Nº.…c äž&V:î:3º¨ñãÜï.ãýší_¢Â×Ïœ±ÉbÅZC¹€/Ùíw¦ØÆýº²‹íª U¸t]F §§àF†Ö#± ³ü躈tê¾³¢câù癵ùsÂXɪŸâøï) Uloô cYzû;Ûã=v( L3ÚÀ–÷÷YE²u ù4<‚|Üøù)/ FO(W1ï¯XÙ¶}µ F%נǰ®5C)í‡/Áö^`gˆÍza=QTIš*;“×[‰ÿNMv»g×%]7ß³¾\,ƒ]f’dꜴp|ó¹ÕŽŠÑWµ»fªvÍt×V~u?õÚû<É瑚ٕ Èæåwc½i¦c.úy"ðºg� ß÷=W¡Ñµ,±©\Gòyç]Î7]¬­˜Z ù} HQˆÆeâv=¹?m¶Ç�}.€C 2.+™ÿ=/‡ß{Å#s,U¶{l½f<6ÑƘ‚/¤¸Âˆ-üì¸ tp_S*Wt0‹>´„«\6(@Ä÷lì¤ÚB9.à+‹¶ŽëHcb˜~˜L±i™üûÃ�gÔÕÏÌ]/ªú½ä±Rf~Z…–½·ƒG±ð÷¾æ—,W;ÖÕÖËnXçóïÅlˆçßFnaÖBóö/E ž·÷kE¸WèÒ•ã€ëK÷?ÁlèÊY>ϸªíGþŸ¿œé³bŸå@Id‚å*üuU•;Û½·¡˜é¯íôª½=ò÷Å+y¨üñ~~×ç@v÷ù3Ñu§j_Þ*Ý_y=º°ä_-ê;²¤riȳG“kŒèòLÇ Ãr”«CÅ�ûY4Lv÷ï7(ZŠèñu}Še¾¯ã«ÈG@L7#e´ríŒw·Îûø)×S®}/þ9Ý&£k2ÂÈzÈ®“nfÕ3Èʺ¬GÐ@‹“óþ+¬oÙü‘zeýÅ×Q¨Øî3˜pÜézýbîG@w®¿²uUÜßðØ_ȸ_ÇŸ_ë¡»(Wög×KžIUAø·æw%W'wêÇÏ×íà 1 `uëáô ìò¤/^å12d|=Î8éžåeûÖÿ|ß}À¼ïç{Å�îìoæw(Ÿ_Žæþ¼žOmù‘ f{îÞcÈóóÏzroÑ%¢*ÿc=—Ú“7TYLZxfý€ýï¯_¿\!"pØ•€}ŽÉ•Š‘T3Âøˆ¼}Åó3Êó˜ TùzÇ~ðÇŠÙ´ HŠø|ž©ûy—ÑÕcÔ¬Xg€Ñ5íëLž è(@TÝÏEÔõs©€³îxÊ¿C:Ö]/ß×0>÷\6.&Ý9`½®ï!îëêXIÝþËëÙÈÕ|£ú ÓU€c—©¦æ'Åèú~©�ìÇR®SRÅk•gÊ÷§®!÷*fØý<^xÜ`n‚ ±{ƒþŒ±‹ŒÊËo‘!ÖÈp#vë»Þ2Æi¹øí+Ý”Jä&¤G_ÿ¹«µ`_וå©Z¸©…£b¨±ã4p¸Âue‘k[‰£;@™Ú0ZÀ -šmz»áŸéœ¼|+ÚªžÞrÙ»LÔ–à\ôçYY&ä¨88¾6 ˜¿b2±ã .(&Z4c?"£Á+„—â'Wì`~•‹Å…{WºËëJºÛ ìäå>º,²L×û1gÄ·ê ¿ú}TíïUXÏŠÉû»"Œ.5}zêÖq uWÁßÔòóÿ§T‡<ÿ-½ÿ(aõù7šÏºÞà˜‹®Ç#†Œ¹l¿_‹)ruŠKÆLÂÆúu�¨•0Š]F}Åürò׳öþ}1Êg̯ÉÀùf ʬ\ÖÞÞ8cÛ|²>±w-¹–Ï“ªí¹ŒŒ•Ê!Ÿ÷oâ;]Š-à!ïY»p_Ä\SÇõM>uÊÍÍèÜ`{{ðËPÅÓÒs¨#ûp¼[>¶Ã?¹Ø®èx¿Åýo—i–tËã™Az¥¤B!ØþCé<ÿ>ª÷yÕ—õãª??c^M™�˜Uðÿ,Ihü¼Kÿ’ì˜O¾oÆyn¯€Æ¼_p)FºÚ«ûÙ×Ó‹Š5%Ÿï#ƒŸ×5ª\>ß)+kŸf*õÚ­òí2…b¬¥Ê¯GŸQ³W,O‘ÁrnG®Š.�±Ç\ÛeÎE¦f—¡Äçóš¥vÈÊ%2ðºÌ'Ì]åu Aº>P¸ÔL²®ðþE Y=ÇÚtû³Ûùxym®·ëóÝ~éÊ5»oˆ¢Œª)„Iæ�)åÂÐÜßä�#ÀVKf»+Ü/ɵÂïßàX¥¿Ëy¦ØßÅ1žÿGq<Æð€YêB¥¶œUŠ™Ÿ2½_Ðå–ÒÊB42™ê ¼¼EWaqµDÅ Ã ʵP®¸Ê…®µ|>ÆŠua}£+…éÊ]¹ðëmèQ16™aì90KÚACVÐU£µ˜võ›ÔŸ×®`È{ƒO÷ªßíýÇð޶ŸªùuoY­238´WL®z_ýÏú¹’®Ë,Ûn.|>è(ž¹ Fî:¬»ðZ\ß——Súês²F;g©ò"ìW2ÂÀ¦hõ²PU¨C€*æÃkû°¼£ÏžtÕÇÿzÙs½ªÇŸš?| ®®#+Çøì®ªù™Óõ|ó¨Ë]eøÃ\ GEyÝ.®8Åûâ—ùÍñ‘‹0ö¹U.ä*FUºž$1Á¾ÃùÉœ#Æœ²ý붮¬ œ¹Ŷ×ö—}qÝXÏD]€([Ç£ÄñU1Ïê/RÌÏõ•Š­õ˜!’gˆ]¿ Rs°pJž£h®úqO‘±¿þì)tÔù¿NÍû €9;NôüåÄýÈpÇñýe.UUù3y½w‡Ø¿j“(+ àÛêb}‰óŠ­ÇÜ?…ýiQþë˜ÀØ=Çè"1>±É û-5óõÇ-¤wõ ×}¢AfÅŒ<ÂüÕà¦BÒH¼)l+`LµÃ‹b ÞÚ+ÖÜD¬v…VÕ¨š1oô죂€ÎëÈÖ}Å7ŸG+fLåºM§«òQŸ÷>ã,Tª|*àm÷vRõûâŸãÙXd;¬ hbûQ^å÷™w]¨ÆØxgwj9Rm»²çb°û~* ÿl½û€¦—Wñ<Þáº~œYºËÔ¬æ?ìØ%@Tu] ¢Ð˜`*½:6@×ÈçG–?Öó'íþÁÒý2þ þMÿS\÷2¨ó®Ð5)@F˜bÿ£k¬)ˆàL²áÒEú1?&–iÄè믣ågdæÄ&SD—kÄêw!÷s…†DÆÐ@šuÕÇî»_ÍE,__å òS0ÆÅr£ÁKƒ>Wey=e಑Õ_Ï~@fW EQýž+ŽºÇJ±´‘0ðès])>³ Ù(=—• 0”¨Hö®…Y6[¥,©óÃßW«Y~×EÌ»ÿKål;Ïô5cŒ×èQF:VŒ6•Nµ§ÊÏWjÁgË_?Ž{�2ë_®àŸóßgŒ|_ñ½UóÈæ+™‡º®àºò(£+ûž3æ2]¸khT4kËÿy>ï®ØP.Vç:Ì2Áñ:Yæx§_À¢çѵódx‘tV¾úÍ0¾2ìã1B£ëh\ÿÙõú4°ZéÖ<ç×Ez†è2”zç=b /q\¢kęΎÌE82)ªzf®âõúbzàø&ÇkGa¯®K_ŠqTT º®D¦VW8 ‚ õ¾(ÉyÀŒ÷Æ2zž °Æ[ìª}¡u±¨ <±Ÿ˜‹Ò•/ïgí±…—‡õ¬Ž1”î³íûý¹ë:ž»þ»Ay—¯_€ÅXbo‘6]!~dõ¼KÜ÷Ùv.©ß×Þúå>ΖkÈ©hDEv¾Pöwz»L® íǦRrKŽìñc3‚®çT#ƒ†ïLúŠsd€(…8æ×u¡7DºÇ\ìÕ®³©—?^@Âc®wÛ¹SÏ ïíy"gJí¾Gï²y{û€•‡=`·;~u>ªüÜ4öì<¤‰ûùíÏ÷¯ù†çó.æ!UžfºªïJŒï×¥å"qh@ÊÅSÌ0t©ˆ€Ö<®\ÝXe¤~ŠéæÎÿ2~ýüocЦb(S�Øã±Æþ!~§ EÎZL²-a «øšõ\"Úb²b-ß“l ¿@öЫ�RrŒ·qMv¬Þh!¼gqª{Øoüñ®Åp`.YîÝ8¯WÔ|) ¦â\&Þ @†ýéú -³ ûˆÀkÇÕDwÙ–çVqd7 ¶¹_¾àˆ‚L²Ù?Þ%#2•«Ì7Sȵ‹í÷´œY†÷)ØU¤Á뫘A¼>Wȧf(U@Ûÿ]òïÚ®®][—¡´Ëdªìßÿýå9 É£Á÷óórÑ|¿ß§W.sã¬êó±×ý¼þÖ7‘y¶ë’OwDÍÏÊâ^êð‘§æû£¸žR#|„ÏuIöeÀÛ~)&eª‡câºÙ‡X¦_ýúyc‚­ö~¦7®¥+C$hö\@a]ÇúoÅ®TL«#¬‹»ÀJ$õ\xa\)Ã-u}0ұ鈴o¿vÏŒL°o'×O«Ÿ2YíUØÞ<?¾N­æ§*}åœø"Ö©Xåb°Zÿâqt¹è²Ïþbk&_Ttf€ÔùôÊ«úÂv6–hY}ÿ8Ê__ß³jà~Ý{z©˜p³~êøÝ�Yc,¦˜íI>ÜàúeŒÅøú€þ­˜b#{ÎvßžEªPu¿øïûRh#S`ÿ}Ș½ËŠjGV3CP4Ä>H.ðF呯ú¢càÌëÜÕœîì'̯bvq†Q­ˆ¯òÝÕTR1Wz÷w]¾nÏÿ ÜciÙ}îÝ|Ïåß½®ÆwÈP@Û.Sß_¹UL7µ¾x•ã!ï·÷ðþwû¿;ΰ>9 ªëÝ}?òüªXw5P]1@5Æž Â)„‰5Ï#£ ™f] ŽæOêùÐö&Ú€ëc ë21cóX¹NDQ@Ú]Së<06…_«b=ÝÒ­žf•"c”åÂ9ÈÔº§ãŒmñ\»úAE¶@²÷1ßá]E³˜]­9œ¢)Æà‰Å3—Ê ’ʲoöÇÆlù_Š;´´6.‡˜ Å(¬†a U@¶Ò»hò­gýó6:Ÿ›C–ÇÏð _å£ÿb®Ï RÅ8´5Å ˆÚ@gés b¥`¯g*™fŠM‹lßzîúìLåò±¿œÇ|«~¨]e÷G`öÿÉÿ“(Š9…×Gck º:õï¥uv?4=¶éÇð.Vc½×yÎL‰À8û~Q{*Ë.À`…1ºð:žÇï®7 ðëûÝ@àªbª«vWí·éC{$é2F&~ïðE™ì†ù5†_ŸX±1Q­KDëÚ:½èïØî÷’‘«¿–«ÃûU¿ŽXL¼µN|#é:Œƒ}•aMÝP[fWëuU¿7q{²¨€+?Ÿ°¯QÀïyCƒÈ úž¦ãçwÝý¢Ž%˜AÛ,&Ô]¢â92¨zõÕ}Î,S®Ÿ%«=ÈŒã绢Æ;ö£Väã÷À÷Ãeðý¤•®«>îr•3¯#ä]9å|bçSŒfÿìüø‹ °ïp}2Âæ¯êçlÆÞûC àLÔ~Ý?tÕ‡ ÊJ!ìEÕ—ýØx9£©Še{ /P¯þã×{² ÜE†X×µg^ì3}°½zïûÔØSà+�£ë°Ë$«™n]¦ow ´íLàX3ñü.s<¿þ¾y\õ‡î¿ç�@Õs캶|—ù`~ª}PÖÏ¿ûà¼P¹(¬ÆÃ ½¾¿]&X×ÄY `)@•0¿h>\ׇg¸ßÙ}¤~ª^´~S–ËÄùûëàd€å@Ùâüã@Ùãkd_òWù`WŠi{ܳ¸ÔÁã™ÂK©ÕŠ%íò§Ã0ZÇzä[¸!ï2´˜%2”òAüž¤Ç~<Êvíê%s¡ˆ.0”¥µÀ¬EöW~üäÏÇ(Äh¾ƒ+þ*"ùên¹§eÅ웢ŒUl¼9ÞxŒ3¥�Ñ®°”‹P­8òùõ¤Þ8T ¢o›ç§‚*õŸ[d¤TÌ–^½jEþ”ïô:Ößç¯�…JºÀÛñ$¦Ðÿ%5À¹#õ|æclõ·‘ªžßÜõ9O^ù\ðlûÇg=¿‡ô50|Æ5 c–[Qóm‡qcó߉éë{„ï&cöÛR™ ¿Œ \ÿuIs@•3ª0œùb€M ‹¸VT†PnÝóñ³P<Öë'[ÿc\a]†ë½Õƒ=ƒ¯ÈHèº4Äõ€]w£K³8ÞÎr¤ùze¶w­'}Ì ó�†ú¾"× °?ûÝÔõGƒ&¾¹´Y=†2 Ò�˜21CA %¼žï²ð_%jîì<Æx„Q‘¹ C»öϾ™‹LµÄú¨ý³¾noÅH®™£öwÆ›@ØŒöz´\}5ôÇõ2Å^s³ .ö;ó7¿ö³vÙvnüYWµw©�æ½ïDßÅ\#¹ÏtÝŒ©]<V€Â±u^]ßg í3Szó×`!¶k¯=5€‘»à¬Û׸üó׫ïö;¤×@OÞN%5À¸;/ì2Ms`õ]^ÃMÕóÀ<¥Àk�{Ï0¡»ÎØ·îËû©r…ˆ€\Ý® Po 2¦ó«‘OxU±È0]Å ›�×fú€ûE`SðúŸ2å?7s‹çcýŽ1–ØdŽy‰<z‚ʬQ‘mÞUˆb|hɾl¡oËeö@h)Ûqå¯_Æ#s‘ˆAŒ3wÕÆÂKü 0‹÷¥¨\Ç6ÝÒEà,Z”Û~¶¿X–,µQÂ}Â’ûf\¡bê;»]*™ëCÇ*ìÐU—²ˆÇþAŕ߀ªb½ dMëRÄõ0Ì–‹šõkŸƤ ý?ò p'ÆDÏÓ÷N=æUPy×H‘q6àlx»J�[š«~¹Bzå*’hüz^¾„»¢�Âÿ3D1ã±§\«ÓùríoöþÄñÚcJêúó˜W3ž-cbwüÔòóëýï¹xíKö=ê(ž²|³úôò‹† à¨îϘ5+um?seëˆÇj=ÖŠñMbxuê÷µÞ21Iݯë:Ñö/S,3Ù[·Å˜^ØCžÉ –¸¡ ® *¦•>VŠå¼ýÈàèo\3—›Ø_úþ~û|{ø<¼zuÆ,ükc‹fûÎð›éý:®kѽ 8E@§Rpå+„*¦Þã.Êxý0õlàm®·cý•¢hÏ2¿ªoÍØª¿ €¹ëŠ9æËñí´xoäøÌ›–1•_?k¾oŒ±vw¯Æ÷èÃŽ;Ô¿x½4憿£H§~úš¤Ûsí‹õó.Q5ãæ�×g„ÝDª[qýœè˜;£g—9µ›E=ÄùßUo•ï9©c©r*†ËÙþ©¾{ÈàÉ]óÕ1àÔ÷ ¾Fz]/=`ñú¡F+¦§w•¦¡ÇØÒ.«õË.SŽßצç‹=›»@qå’Qå×ä{ý¶ƒ°Þ©  d\n ΨëÄ™oh3òƒˆ¿gç•üB\$rù~£L€ ]+⯗?Äq÷|dŒ)—‰÷t1ntÅ’ ÑâÛ[k Œ1uŽñ­Tí¸ Q–l5eÜE‹v=ä]9òüU{¶ù>€©7 ÞåÄŠ-Æ€—+ÜϦŸŠA¦,U{Fãü- bï,¼ Ðee¬œבY–1ÙS´.žlÿeÌËèããŸ?§Ø¿×p~Ö 0ýFˆÓvÏê?óS1ó*űŠǤbt¥—¾0P–‹$æRÆ1ÖÈOP|r×sÈŠ�˜U,_“¬Ø®¤\ö®Ûð8D`H+л€·à?šé«z«~Úg2Æ3VÀÊö;QîÊ+ŸqÜYpÜp@íý£:-ÿSŒ¯1¢b \*‡ã!wMÁw9J€`¦SL€AÏÇX_ÊÀÆ ›WX¹Ì€Ä‰ù[€ÊÆúš†/4® ‡¹>`}`]!ŽA\&à–}Ïz€ ÿÎÏç²æåuì]4{€kõ_îRe@9ø˜!KÕ¾ÌÃ]Gp  °­= <÷ý±}mÕwꯥÇyFË9Å 3|Ê¥‚¾ór•Ú¹2DØ ¶›ZïJ¬of© È2Ï#¼?b¹™ ÕÊP±¢k¾l=¿öG:ï¨ãwóËÊý¬ñû×qLç[˜îK&�öó ;Ï™lÚ°û×~÷3ƒÄÎsÀ˜=Sl?`ÿy9Êç`ëS¿çGñë¥ÏÛ•Ô÷þ:†œªŸ¼ð~¯€±[©gà0Šôï#r`Юñ>UožNÕ¿v}yv~>Ç€Ñåæ ÊUbÕì× Øx ¿=`¹24“‰·£Žq…íÂYüýïÇÜRíè1®jÀ…÷Ï«8�âå¿&ë{Ö?5Ð:û­ÐWù½¿µà{£CÇðzÐqS\†á5ÆX.ñ¾F>S(�v6_"èѵcpûE^ùSüŽâ|ÆÔï Çç™a•P ,ÈíÄ&³œŠ HnQ>ÆR¸Ý7úË% S01ÂõNŒ¥È²÷W¾Îw-Ö<óFùJ÷õìÄHSíîXäŸíP–Úëø ¿˜«:>+ÕÆšöú]%@Í)ÖQãºÌdËyθã±Ì2â<·à¼J�m+Ëbå’äMä3†f–2`}Ý3ÅVç=èÈ# ŽÞ}•+%ì­d¼Ñûy;Mæ6¬!‚Rèb>Ö1P¾‰úù~; sÅ£`´Åý.@9h>Ñ›Ši™»ÔÄ¥æ=ôE&ÿ®y€ïW1îTLº]ÀP`c O{.C×w¥#´#½ïõ]ÎΕ"ÞY}f~ ˜¿»ÀDûã\1‡ -ì_ˆW<›/iî8ar#ÓcèJÙÂ|üÌuèñ`«bÀbÿtäÞ~ý¸æ£+ÌKW§¶1À†;FF‡_µ¨qe]ue®Þ ËÜ^UõEO Y{¼ü¤ë:4 Y}ßà|¸?#jÞ©c>uWä½qÑãSôóGƒÃŠñµÏÄà@NÆ´á÷÷ú©¼Ô:72rVùó’P]¦oròú[F›]Çgo]ÉYÎ=_®è²ß׊±jûãÕürý}\Ü}Œ†åÌž5Ïg2¼fŒ°[ÏÈ;Âs®"SJ„•xÆÛT4N˜W˜vb/ež8=ÜoÖÎÙW¸ÞÒ³€!@¶+ï à׌»ž‰ºÖ«cwa!°Òû>¼›q“KÇ4*+ûK¬e€ òÌiw–O÷ünû9�¦PßgÅ\«˜P9“*2ÃvS8®*À†ß?¥f>w|b½ŒõÍcuuþ÷vç€Už¿7]¦&ŽÃ]†þ<U¾J05*#,Q� ók�Q._£. `¦˜^.VX"4Ù/㬠cìÏO`ëÏ�x¡ü-=V̰ó@™Âæù¹PñêÒœÎ.–bÆ+\¯_̆oÁ¥ß0éÇèÇSõe ¦ùË,›pÃÏ|znÆ4ˆ±¼#ÌÆxR Ш”È”«È»&>ÿ»b`1ÌîÏ]ùä÷³zãõ®«!Zèý3Ù\Ñ…–äÈ(3@ÚŽâ+¶S.*2?:y¿[FߘRÖq©µ�Z¾PAòÑ¥¨W`Ìô—‘[’+KÉ®‚:~ß9`&ùK¸b®r¹Ç“‘�2¾œoâwÀý] m1í¼¾ÒE`í~Ìûó*�´u]1˜†«ïêq@þ#\Ï]JFá�–¾oiœQ÷a½y9Ú^ªŽUgëeÓq`Wõ÷ò{ÜSqEõ@K1L2ƒ­¸¼‹r¹ë§ <Ã'2{¯¡Ÿ˜ë[Õ^6Ûïú5¤_¹"�ÖéçŽúªÅðù¾ÛC\§ùÁw¥íš×äCëyº½“¿Žý:I3ôðºε¢˜3·|¿(�&*¤u ¹-TíÊûÉ_ï¸�ËÇ©Šö �� �IDAT!È]_Åw3ηjÞ~ŽTLý8Ÿ ì)t*†VËL—ËçOÅy<¦µŸ'/_¿Jåîõ›ŠÉËÖŸ|×Ì^6Îuì¶Ê�D?¼““1œªú*±.ù躑Ì9ÃÕ»XÅÜÛg ~_yƒvÅë^nc@,°ïëb‰ ËA>¿ßÈsè~ìõ×±ÖwF\Œ5™×÷/ž×1¹Ëþj¾èº~ÓŒ1åt5—}½–R<? üå±vj—oœ±Õe&ucmíÇ8RL(~…}ÆL˜Tù(€³ºOµOa9`ƒL°ð©€.¬w0RL¸Y?ÿÛjö�«ËGßW1{ŒÇÇ™ˆ³ž½÷JI5¯*&(Î]ÆWí²‘ÓÇc£¹üPe�$ó‹¸t×P�« U�–«'‰U6²ó¤~ôú/cŒÿêTÄ�_üw¹Rä.“¬bŒ¡Ü¯#0ö‡ø­2´Lâ.žá2 *^QÑ¹Ž½1*†ób_!—[šÆå•v‚Œ¯P˜.êVÐà1ìs¸~J”ëDeÁÇÛõ[<]Ö‚œ)d­‚ggGQö¾¿•°öÇ×úÍ\ŒX‹sº®Çè+n‘1Æ]kxÙ'üGKò»\¿�3µáå V¯È]A¯g?ú÷€m¨+ ËŽG¶ñg–£Ù<ô(3¥º/œ—Àug=¯Íã@€ƒ»ˆ(±öÌýØ–ÿŽ=À£HŠ‘µ~'³Øçãï·óoï*ÿ\ÌNn À_ÜTŒ9ì÷áêq@l¶,|KÓW±Íôy„îKÇÕ\Æìîô„rfÏv¾E€~|¥_ßiîjçAÿ½_éòêj>Ñ#†­c£;¼9†µ´ó¸exáýüœ á Æ5® ÇàßñŒé4F±ûFã|œwÞ2äp´Ì1X¾5U?ÛüÃ$sÁ—^{Pа­ hºÌý9?ûy¼çò–d0†)–yy®?"`>†]ÿ+Ó‡ÇdÛU$þ5.µøõ¢š¿/ïç>j׈½=¸Ï“~CÍü½µ®øº�ôî8÷̦ ×õ ¸ì~?T=àæ×2þ–ˆÀiߺæ¯c„‘z©ó£¸Úù×=‘a®Äï÷*†Ï+YwögÊÀ¨ÏÀÄúöbíô™`|ÅW1ÂöE *ÆŽ"y¿Tå*é]ÀMݧ€uÞß÷.óíI×…[¿?»±–Ôý]QÌ!¬¯€ªviSɼ}½ô*™ruY¹R¬`±ßx{ûùäíÑ�½òÝTgJö˜„5`zVX=˼RézŒ>  õÞK³/JÅĪ\ªØ\è".°|*WŠgcœUòËã?[)ÿl¥ãWÁëÇS×ïÒeŒÕ�ÙdŠñšÚí» ÐÒax-E'*¼…}gZØ(:ç-c±U š\‘5¥ŠåƘ7ö¼^˜«z(†Ñj»~Qñ7èq^Ÿ]….»þ6î±ÄÆðËaªˆ3ÇÖ2ý†.šŒBÎÕÃÄ26]£Þ•ë¥lãÉìÀP¡f¯+Y�¦·üÖ1âرô\W5b�1 ‹­7Ö\q­ý 8«c=4™Éõìü-:0äRTœaÔ²ëÞµ—b˜â<æ¯bhåÌ·°ùãxŸ?¸²õòý骙Ï5�ŽÊåãp÷×ýÂû;“]fêîý;ùvß÷Ï+E OwÝRDE—®Ó E[´¡å?WTa:åÒ6Þße†ÍTŠá¥¾«ö<¦­Õ†c g0‚ש‚Ó|GßÌý·—0#S¾bÈqÿ~W€ mÇÈ×cJÈšýy3Ö×¼8ðµ\#"k–­'•§åé V|Çï'¾ °õßg4¸ë‰r±¬ëË×Q*vâ&ù|k{.¦a¸·®éîr-î «óí¹RŠç}þ¸>«øû.1ÿœ‘6Dº³2ó‰®à°žñ9ñï@ÝÞpCÍÛÕs\ýãI{¤p»ö§WX÷ WíùèZ ¿?«G˜éÏû‹`$ý”½Ét—/Y¥oØÿŽe†5»@Dôà¡\é*©,\€ÐŠX„=kDwÅšqU‹*f×9À¬÷˜g0Ã**¶w5¼½ºœn?ðë}—Ú°­'•«½G,ö�’šyæëY´U>]€5S ÛY÷�<ÛžXžbTªù£ õþÕûQ¿?ù<„ïÍ{1ŸT€Y7fš€�J1Ë(ÐV¹RT±¿f›:þ~[rÞe"Jk¬Æ »#ClÊ>@6™bç?hvÃ;¥bšíËr¡8s}çï¿<vK´à­\¢ÅôY{2ßþ¸0EE]ÆÌÒõôf_Yþ¢+ ßÞU¯|îc[ÌóKA·,¥Q¡6Âø¬lYt`V7ˆ"]:¹r6Il2àœ`l³¦ …?ZžÛ·Ò[¢G&ËÛ°Ïkž×ï½Ú€ï*­eªÚ˜` “èjl*&¦"É+”P¡¶ëº=î(êíû“¥W®oìx~†AÁ£€H7/Êò~WÔý93-–:í¨RùõÈèúYÞ—1 ªò²vehe÷w¿Û™ë«L±¥¢ñ}XŠG¥èß©oÌ××ϺäL­ªõz*cìæ»i•°í†5$Â_+ŠùŒß×Õý®ßàûbР!‰0T±@N×p¤ËS˜ðÕõ6¤¬¯ís倡rIØÛØá÷ û+‹={¿î=dLtíÅÖmx¿˜‹Ñ¬ÿY»x=ð¾ÚP®Ël}t^#z€ˆóg¤Ö²4úr1Ÿ³ŠG¥àïÕgW#k•{¶?óú1f1«sY¸³®Ú>øø¬öåܰë™T¢àûê×µèÅ´±ïbeX:°ïƒ)äî®_ $úf®[—‰$ÿ6_ ì#>çÕ^Ü×ûv^aÿ3ພ'w ï”bú]÷éÕ{¥ { ØÚ¢’‹8ö3ßE0Æö÷að|Ï}(Ðóò®«¶J1»ð‹²§€_ùyºŠ±4ÂõŠys�ò ô4(fVîÊ2ÖK×å\̯„zz\U¾ž7žËPWïÅn¿<ÊTŠåîÓ3¶*†Xœr`LGÛ°ßo€uçµ]Cˆ™¦[ã<¸0 f\b~Ý^.´0ߣ! ׉´~}—‰»òkqýO €ý ~½,`ëŸâ<O¯³î†*g€¬ÅÚ àFüŒ ÂrŨBÑ1z¬%?SDøûkË}¦Xa ”l#]5i@’)ðélü*E„Æx»+*vøùƒ,Äø¥Ž™‘yìËì¢ÀZᢠÓ�ìSñ·ãþ ò¡í@šýL|‡ßy=s½Ä�·‘¤ÇöLP Ì0Ú^Ù’Cl¯ðÞå–¶Ñbµþ¸;ºpZó`÷}dý–•ƒ×•b„1FwdÏÒ”×ûq€¬’:ÿÇ™ú;ðˆ!E%™E¸bÌt¥cØ¡ =ºŒ-eA æ*ÌæËã cT¸ãwÂZ0OEœ-7ºŽŠó 2Y}}”KD”#á:¦bh ’ Mì¼ýåxC•%t<¿|ë]GFôç÷è2Ï¿|óßÕy}¬ï3 `ÌÜÊB¾»ÈÍÑ0ÄC~7ÿþö7Êù÷Ƨcï[ïU±Ôb¬[d@.…vlgý¼g�Ò5˜ë \çç1"m>Ï�¾PÖsñ1­¦Ü¤‚s�ÍŽ«Øqg]uÕùîJe˜©~=ÃN»*<'5ˆÇê=ŠLº7ql¿_(™&¯a?-Qž:‰1æ`,ÖŸOóú`¾~¹B\5¶Œ°÷¡ÞëK§=)ð…û[|Î|_Ïõ(;ëõF RˆvJÔ{Ö?rÙ Pò™ïY¼±w�T*€¯/Šá™g}†XO¡®™.¨h¯˜)½Du»‡«×{ò“\¡þè{ßÇŠÙ5eϵèy†X—¡Ù]<ú½U®#ϺêÞe ª÷™³Ú5#¯÷>#.ïÅ;#Ž—[±þý¯ßŸ]W¡Ýï˜ê/@MQ.)°Ôý…‚@‘-f™ÜM M¹VÄóŒ!ö_ÅqOj¦Ø??Ïÿ­È ²!޹(FÙ¾¨hùþ#22j×}AW@wQܵ¶ È+lœ1ÿ(z­\XÆ–b,KÙ£§ J>@™+8{>S8fLªJñÃðÈxóÄ6_è2ˆ»”Z½Ã�­¬þH¶`VÏ5Ê. @ü²W̲) 3 Gvßñ]ÌíºÖ²å²|óÏ–³ŠÊ£fVä Ðʲ®Îë IUß1ìÆ?O7EmÄX¬•®ÃHË:ª_Õ|Í�bVï1²ùþqÙUXªyªTòv\lªcÕîÎw‚=åbI q]1>´k;®8Y®‚øudg1¤¬%z´ÄÖ\Q‡®qÞ¬òá¢\ߢ0 Ì–ÇbOµÞt]hÎSü½àØÄþB± 1›ÿüÍÄQßÿÙxŒ–ýùsŒx¼î³kùÞ²cœç™b¼c(¥úGÏScƒ¢(Q@xe0– 2lïïƒ1¹˜ïjã¶ ´ªöñöô· ðTR,TÀIí⯧øêq}á.ñú³/U^ÜßVŠ~nðÅ\:âw¹³~cífß›XßkxÿÕ¸®˜¡³|ÿ]Gæ—¯§e¡ge`Çæ½÷¯ß œ_®+&ô�]c`ªÜ6oåÜàÓz°Àç=†Bõ¾×)1½•@£ö;Ùuý¾÷\ðõ£Ê‡ÇåóèâÎV@ØÙù Ç} £r8óE¦ï:üz¨z”² ô]Ðuc˜áõî{²gØŸŸü®[çÏ2¶ët=›çÅ%çïj4Ë©C�ëÖ«v]ZǃcùUL·w™NõÃ.Ó׳sMµ+Ï? æ¿·N¢�­c,À¨ H ÊÝ?€fòKc¡$À=6Ë!ÀÝvþãêP_cì1FÙ,o1È<03Å$ûçÈå~0<>ڰ¬²¿ÞÝpEé(2õç]+~ƒëµK®®b-™ÙB]¿Rd-Ú2=ެB2sÙ¦6jÌÇ»btáÆ -™âñ0�Ùww< 7oŠDfy_ {^•¢cµÝ lŒ])’X+]5݈)…æ”—Ú¥\Æ@Ú]v*YŠH¿¡³.¤p<ëœXÉÈØØ“Ûð ƒz~[ ´­,çí{¥æÍ¨ðŠ&•ì=Y¾£HÁgj»Ï­z*—i¬?:õÎÞ·Nÿåóó~¿øñæ%æ:—)Ä:ÀCÎP;Âx¶ ¯ |÷W?ã÷ÏÇÒ.RUL–5à1æ“JÌyI3ØøÂïº:œ×ÙêJ] Ôd›@.TàýÈè‚ïÆêº}æw#€Z%—1š³ûìý+ó*ò[£ÅÇôZ17Qpƒ±ÀÀ¤@×ï#”2W’yùG¾~rÚs2èØ[÷h ‹=÷+¤¯·ùÏu•x¡+TËÛuyuŽ!]?W+¸=ij’1„÷„»ú«™'3ýc®œ´!~î)¶Çàó –TõaÀi6/vÆÃ™õÇm(—Ñu¤ú^«ù;Û_[&ؾ°…¾?nb]sãÓ%¢9?c„M ŒºLÌ¿;=FÔebU¹JÌ þ´+Ä}À˜íOÖzRí³ö“ïò|WÔuû<ò-¨ jQ 0Å á.Æ*AWl:Æï·×"¦¯¥ëJ—+ö#ð¦�€î¼ZÅTÂã.“®ªÇ9&Ï|~µ‹B`¼ßïG™”Õ¸}V9˜ÿr…Z•çÇÖùÊeìëƒóJWÅ |—ã”»ð|Ï%Ö§Ë Ü}ü{TÅ]Wœûõz´?²c()Àì÷â>÷»ÁS1É\~X®)O•Ó:Ïbw�ldø;¯+éfxÿ¯Ÿ�Ö¯_�^=FØ!ý=ŸßŠdÆàÀcµaˆËW¯�ÃtcôcFXaŸ·»Bd*€b¬1´<ÅòÎ)t>÷ëqÃÇ, mÿrW6Üb/Zrú5Sœ"P†Ç¶2Kà ØÀvðû}}¯¦] ›÷Ù󻊶ŽB ÀÂ~º\„ß;e*H»|*"¿ž“¹N-÷M¹ÊRß]7Âú ‡Vñk¥D"é󯓨�P®;X㻵¨÷éŠ�[¯¨ˆðŒT¤­÷Q-Ð9P¦ÆcÜ&z@\ͳօœ•Láõ6ú–—ÝØ·fúŒq’Õ—YŒ2—?LaÑe\©ú|§çsf$RÙ8dŠ4f‰ça_íê-›¯a¿×](¯÷é ÊÇöócõ½P ‹ƒ~G0¿e€Ñ“l›mÛ³˜*ë˜3Ýk€‡*öðûA .Tþó~𝉭‰ß;^¾æã*Q)|sKúZ2Æ�žGÙ%Wwþ ù# Ê¿sÊuâU||9êýUÌal_\·Åw±r1׉Lá]Í«ÈlØqÑÍÅ»<\µõ1…×zâ'ܧ×;†(ñ{v…ßyþ9®…ªïúj¼!b¥ØÀóŠqU^Ïfˆß þýüS¨hf2–¯]è²~±ù3CDdrÕíDÃÿ=e†$(Ýý[^î;×>Þ¯#³º[CŠ×¯‚`=ƒ òÿølϬãKûÇÏ»õ8°Hg ¨f¿Î~±ÏÿuŒ0oçÚ @Ê÷U=@º¯H®j–Õ´ÞwôçþEÀG)xëC9³B+ð+FO7VO.¯²zõx/Ö5Ó£+=C:VØS( žï'Ÿ¿J¯€‰®+¹€ª€¹!îÏϯXr è9gнÏ8:ÀÆ~òéê÷F½Ê÷¢’½úÅã³ï¿¿ruýž-•iœcV)Àɧ€•ºÏ�kxŸrÍØrŘä{J~àú€°Åàâ�غŽ�2Êr™ùü ¿È Ó1ÆŞÿãëwÐûö-üz”]ícÚ_`ãsÖ²T+ª~~*¢~~cóüÖ•â¼ÿ',DyŒ©J: )è"Çž·×s…Òb¸dÀ޵ÌÏ,³v1k‡Y1ë9{š-à•%ÿ  R <W¾ð9Ã(ÃúÙcfé­Ò» 2É�@CFÚ—Bcµ ¼pËêÀ #1ÐrÅaI¶ûÙeOÉ+Ðk׋ÕF]gùÿ”ÂC¹R«ZÂ1;·¤E‹|Ûà À‰å,‹u‚ì=ÎGˆ›b¾ŽCZ¹‹À¾• ¹ÏÖ‹ÅBÈëË¿cµdT(…cT¨¢ "î9.ÉÙ—p^[4ãuÎp¼Šyèó?º˜.ÿ Øî¼w–™Úb²í΃–éuÇÈø²�ÍšZŠùŸr^Ÿ¿˜ !¨áÅ”ù±ÃÐõïÀýœ1Ë{ŠÆ%þ;_Ö,¦9ÿNṌqg†©ñŠ °AsÏ�Êé\³~öïªÏçÇàï­—ÈTV ]&àãj„õù¬ÍZ¯Ûë³WïG¡3Ìñº]ŠÁÔµ¨ï­ˆÔþ ã:BÍëê{Ðkw×Y% èZ1×x?캮Råâ>¿Ÿø·Â€çξ©{œ9àrv…}Èóofˆfç›Ìp*®C£áÀ.0Í{èRxoŸéO0A?Ô|ÇîSL\Õ#9fŸÏTØ{†’Ñdç=¦`ß›½\ÆcŠÕŠAp»K4ÈR×*¯ø®'K*m~~ŸQ±w] u¬¤.‹‹î·JÑÏ]Þ)¦ºž¬$¶{÷»³ �ì¾?œøÎ?Z?®óë2«uJUîÙ÷cWö™á¼>]f³•A[>¿–÷åÒŸ—Þº®N»‚å: É�Kcì‡8Nc‘mÄS®Sæ¦3±ÂNÅ4›ò˘€ÖÂ�Cfعën`(>-}Œy™L1¦0´¿CGÉhd>pË?d2<C˜Eöa6ÚL1Ž–Ýöþ®¥32Î2W™kBeQÆJzÂíºÔ±²å~#”1Å*A¨ßXFËÇçÜïÅ»6B…ät´Z‹®¸öeÕu|î”Ùç?]M}ýšþžÏƒŽ#d‚ l@~¢Õ(DQ¡úfó5å*AbV”º&Ûö³ ¡ž%r¦ c¢ÂU1Å2FæH«y˽TŠF³zLÙÙØs‡$6_®hE ö(°S16¬Â-}¹ùs·õçó7ºúá÷`´L¿›xž·¯tãë>ÿœ¢B3s…ûúå ]Tø)W #¤‹�gviÆ&¯_ F?D:ÛžŠ™:çÛkh0¡{É_ï( mþ®>ÈÀ"ó-=å¾è˜GÃØ]0Ÿ¹ô® ¡¼H>•tŸoEºl}³ž«Øó´óàÆÃлòµ×9?Η£ ¦~pÈûzŒ¦«ìgûÞ2`¡b®©õQ‡a>ÂýŒëŠÌ÷¶–Ã5Uü®(UìœT̰%Uyùþ¬bUå÷×ÿ¾ž—ð}Íתÿ÷Ëá†M}oÆðÌ\VçÌè]—zA&ºz_™aÊb|ùõ×׿½µ#;ÿ>T»oŸL§# { b›öªXal]˜Ïgh å˜ëÿj>½÷Ï}þ¶ŠS¾Þªß™‹ÚåàÞû¨]gÝèõÈüâo¦Ú§œe°¾ ÀAõwÍìá ³)U¬Ÿ]Æ’Nº®ûÎ2uVyç\©Åþèö—’ü»üZ(Þ_å}ª_í¿nåãn7öWÅxÔÏ©Ëĺ¦ùD9kBÝ“>�_u Èż|•ý¥Þ3UÞùTíÃ÷MÉ] ´;q½Ø«x¯´«Õ]�ûüNA׈¿é‡8Ÿ2¿HL1u¦S.†•è2±Æ~ýb”y&2¼ž%çû7zv2Æ´Ïôá®× ó ]–?Z®Ç˜"}©eJ‘r?Ž.X¸¨˜�0þÈ] ͸ÀW¾å t•éÉ•ËêgÓ÷6x±<TÀ² Ãt¥¸žßõó¯W c>Ÿ˜T@W–í;L•nÈ S ¥XŠÖ ¸Øº@¾¡¾/"†žÜR  #g”Uýv$çí}ö½þž¤gõxçw-[PËK¾Š÷3.¨2�ûŒå–›½§•¥¼=öŠ™<6ÆZ‰.§Pq«,óg~‡{f;‘ ¶æ%®˜CÀo)°žø|”b‘_QÑWo¤`¦ 5IRY4«ùp*~³‹¹:d:tÇ÷wÍóÕüËÞ×”ä½~¢ž»±º. gºƒìÃ3Öohø`Ž]ùÆp lÆÐ�é…ÌãªßÙý*}\,†ø]Žð<}¾w¹†uböÖŒãj=VH¡!Œ:¶åZC‚\ŽówIidÆ0Æ0¶c$׳~¬¿ÿs½ýíóyFç]Q†Sª{Ìœ®K•—® ¯šáw¶üœ1Ö¯§e@£ògd¿~ýï.jÞÌ N|yÚPÊîçTÌM,/ó°¢Ö£ßI~L±äã¸?ªæ?+–as¼f̯Í÷}ÄaYþŸé�{qý M¹‡‰ÈœýÀÖï̃Õ?öü+¬/û.µÎÊZ¿ó~x¶TÑ‘oŸGþøée®¢Âõú»–ª|§ ¢»b¸ì>oœè|¸ë¶XŸ#cõÞë¹Ç]Êa=y{÷ÅÐâzÎÒãìY.ðp|TåúòÞéÎ)ë—=fÒ>À¨®óïlèé^Wé{ïÃ;¤¯ÆMÍŒS�ð£L+.»Àw?¯TŒÌÚÅ«²~ÏÒU€S"¤ý.®ã±úm a®!#ÍÉ/2§?e,0ÏÃc¿†ëÏÏøZåüíóøŸiúê¼¢š?Ë7¼š•+,k‰–Õ÷¯ª]µñ>†�±ŽMö½y¯3Fl *Е~ÌŸÇ2š!ƒ.‚z�Âù¨þõ d,¦˜UœM€Ì*T9`ã7¢¬V‰öæØÖE¥e "Ãëò „]0ÙL±a@n†ià�5`œ…Ø2b|Ïôu{*"ß ³ý‡LÏ1*íº/æÌïW€›/·^`y A½‡UÌ¥)JÌÛmïSíVõæ÷Åòãg2P±<öœPcïã*æâ€û¢¢‰Üd}½b)*Š£¤^fLX=Çç¨æ{,G1%}nzÜeõê¸ëÙ{W%vžÈylÞ°†�lJ-Ëq>Ø[f¾tóíXó½§Ó°aþšû‡¹¿r*ËøÛÐß'l·êwÖß °â†*ø½†/ÌÀ%YΜ Ûe¿¿X24°ýp?û—ÍK†{™ëÊî:Œy(È„¿?üû]ÏzË%"Ÿj@:¸áEŒ±›+Rb¾¹T8èv¸kˆû+ÿûxL°žbc–ô€¸®(IÌ5c„ô]åÛ÷§ã2=cV£ËdëI…-ýù y¢ §‹ øêì_µbìB¯¿~åwùúÅ#ðeÊùœ·Sf˜nà…sÞ¿ŒÜuzóÏ9ºBóǯ…[Wtý®§ÒMé2Ltò™èÿ]“ì1aãð\{*Pw?ð˜Bz]�TÕ³ Ðäí~ÝØ/åõ9+@Ø…·ï´Ï­Cb}ÏŽ]f¶û,pwÎeeHÎŽ‡jVŒ°*ŸEé3ó0¿õýÈ﫞žÏë«Ò×R¹Nì½—PJ˜S)�e�§ ¨B íGv}DZÅHk‰Š•6å—~VŸ²�(ï*ñWH÷«ÎPøùPC`ìŸP¿µî[â_Œ®ø[ñ»/|BQùwÝÑ­ßx_¿,U}lƒ%k#ï€ßŠPt%ÃÂÊÇýºÎ,Ü”K1{>gžÄtÜâM)Âk òÊUg.Df+)B¿“û,6H>6?Û_VñV=gu¾£ ­ƒÃ(L'`^·�*Vo8pŸ«`XcéÒë„¡V¹ ³Â>—ìyXÀ °ì8Shä·²�� �IDATÄWQ¥øË‹^1»€^T_å{³ZÀ�¹} Ã÷°b˜F�¹&ØÏ>ÿø^òþT±§"“ë»ÈßŸŠ™¥å{q¬êï¥;/+—†U½®bÞäå^e><–\Ç#8ÏÈè:àצ뾿T€9»óÞgù@}˜!5LÀù:¸ºýü½À<Ö[Ä¥mdÐv$×s…¨´=`|Àw Yæý“¡7ç¿ø½º|Ty‘°ÛOÖPï×.f=3õæ›Êâ÷(æ¥àgë3岋Å4Û3`ú~ïÏoyVx3çÃk—qØß¿1ƌƴáÃ^lƒÎs°åéýTÏB:ær~߯÷ª>u¿hÆÕA÷eéõý|g½ù{c]¢³þ¿+ü»¿€—Õ?ÐVN±y̺Æ÷ Õ=ÃI+lÎ6È�³ù.¦TìùÆ|€€×<~Ñ Üèê|BÙ}£ )`e‡¡ÄŸ¿ï÷åJ2ZÈï|·vbØy9§HF×kûŠPn"0]&> œÇöMáïaŸáTåïû¥J7¥ÛP³Ï<êJ×e`%œ ™Hgóï2¼«Ð•kº (F—wª*FßYQ /,_õKu¾ÇèéÁȘªúI½·ÊÕ`W0/}—¤y¿¬÷¸ó|ªy]ל±ü|Ç_½1ýslSb˜_PE…�\(i̱r*VXUî/ç™\ðòÀ˜ÌVºÿ‚_<߬÷¯!…bŠ!PÖCª»€Ôó(üxkÖïyâ.µè·–‹¦®І(v«bTÙ…yn¹¬\‚D…KG‘ë¡,îbLáîSõˆ¥°óà>Æ«÷ì L®—P!¼,×¹ ¨ÄiÆÄà‚ýc’x‘L½Äâ†{  ±vKwÓæ7ÇY»ªöõã‡Ù—}F;xµ¼±¿oC«ËØüð}Œö²þ*ÇéáÆkU(Ç~D`ë ]C i ÆÐG[£€7¼]™‚)–§¯3W85€¸ró€;^?Ä8ÅØx^÷¯JÏ€ ö­¨ïÕïßÅuß[Ú0®ïE¾Ê0Áõ¼ÿªÝA sÖåCªs>£ ÙÏ|d,¸$£eæ†Ø^&½²ÔOËú»²ûQýË€íÅØ»Âqtu|Ž“Áíß‹«\gDË}÷œ†^ÏäŒHÍc†D1FÏA¿¿cÄ÷­š/í±eô øµï¿RtV ¥LØ÷Å®wýïìi8¶ÇW 𬿲öjA~]Eà9®k½?êZç@ƪ¬b‘ß·’TUÏ«v!¯WV÷÷¦ê¿ž(CDÜgÝdþúy²ù*‹ý•éﺧ"C02ç+ƒ?%¾~·Oàë. èY#’·ç"Ê]Ì0sžÆÃúÞïS®¦¹dÛ÷L1«¹Äõ-à2–ùz= {N_FwgâE),xѱÁz&ç=”JQŸïèú±x¼è˜7=‰Œ=—s ØmÇjO¶ò·éö�³ÒÉv®½µðþxð²ŒPv~ŸÑ‡ßGPÞ~Õî×Ñ,8C¿zÿúã­'¯Åñ”÷v¾8.€tHgLb_°2 ×N{ðùt*ìöcŽ©þp×pEbmmÉÇ—® SW… Q̶§Ê//¿>œw‘ˆ.…ãÄýçx†Ä˜cƒë”íY¢?î›óÛ³´Œ÷ゎ×÷ñÀHTlzÅÍoi~|1Æ–‚À¦Ó¿±ì<Z v\høôÚ23WÈêàòVt̼0h!õ;ç҉DZéÞ}_V77(Wh—U�’¿u…ðª}Øž‹iáRÄõû÷a\wAÿ£bö‹‘ÀWØÀƒë/«ØÅú¡(•*FO£¿:LF»|É„ëxˆt¬^g d�‚§t:Ï,۱˩Ì(~¼«…ÓÞ³œQ•n ®0¯GFر¾˜ëRì³y€-ƒ‘1ƒ2ûÃæ«„ñ˜+Ž‹*?[Ïù{-î¯òÉõ`ñuL«.=ºÒïEèãïË] B½‚hÆö îf\2«ÿ(Î÷ú_ŤãŠVWÚ0à*r‰éÑ€å.W±îP@òøê¿ùÛ5<Q¢,ús 6®òqŸÏ{*Vb‚±cþ~ýl­ŸVë½ç„%([óâf ¾¢ËP.?¯XÏRÈ)點¯CÓŠ+äð¥ÃÞw³fxñýÙ央(r<å q_²ïXæ1£zÏÕþŒåŸ½ß~ÞÑžVP±õXÌ6[L{¶ðé&�¦8³ÈC`ì&û­2xQO¼¾×4=–‘YÇûW_¿˜o³&˵¦ëyt©<ý,æ¤?~TaŒç56¥òAtùüû,ÓgèJ¹âVç¯ú¡ Dt]äU;‹||UõVR1Lºåtõ}šyÂÍÈÁ~Û©´(u]öûûµ˜¹g™v]fUÀîGú¹©~ªžo¬a~½víÊšgªöU.WóqߋйÆË©žûûÉõkvg??Ê tåàjÀùJZ. à–2ÆN�Y”¹FÚã�¹¤Úž/—‰~üs<ShSŒ®Ú¥âcò'0Ã4�¨&¼î¥ë _¥×.”]îRæ¿—Ÿ~”¼m£¥ûR˜OÆw{÷Û×}SA‘ÕK1©¢Åb3$ºàЙR3;³pT–Î6Ÿi‘g·QÕóÀóùFS˜sËKT0á:2ͬbÛö"®È@bL³N}ß’_týÂ\&2ÆÞ—«ÅéÒkæc¸Öåc>ØòXùc,LÁìÖóL=W墑ô»Rðq}÷óÍEwyÔŽ=kO•‚3E¦`ΖßYÀs¶ñgï•t¥7FT4Ïœ8pÝí?ïÒ Ëeï5+'43@b€ÍÆOÆ8´õB†"Ö»a¡ÊeÇ.?ò^; ËC†—a‚Ñù�Y¸ÂyÉÜgÓ}}wÑeí‹vçl¢^Ð?uLňêTÄñé×àÚ÷2Ž‘9Æf ?ž"3“3º8óÄjýÄûE+ú{–ú±¾jbÇŠéz}—·G=÷ù~Í÷ã'¬?½a×lOlÅ·~Çp§–®å·w•w‘ëÙžBì,ƒ)¦ÛU(&*´{¿Zºë¾ÜU/¾_‹õ;LÕûMÍ}†(ü ¨ó�}TT{› èÅýTõžgûœÉøŠûa?ï²ï¯ç®Œù¥¸‰—bݰZj®Ó˜aßáúøŒ!Víÿì÷w泘£«¶È¨ëò AÕÛÈ€TXæ1Ê*Ñã³Ò‡t]Zñã,Vœ—Š)v+êY W¬kÆÕU\çŠ[]^ÕÕ<ØcÜh@¥{UïJAïûµfzTLªž 7—Z±Žå"Ÿ€Uç?Û¥\-î®* Èÿî2_¿ÆÿQÜŸ÷çy¼Þj¼éqw¶ ÉŽ(€­7¾«ïFW4PêËÑ�'¯ÿk9Ž}ùñ~5OWýåë·äl ®³¬¨&ð¶À©üT½ ‡åÌú*¦Ü—ËÄ—__þ6ž)èšÌ°€ w^3Äz@Ù~̱)Ý2O*]œí3ËÊâŠoäž)Þbþç—ba˜ßÕ[ßBk˜Ë¡,æB¾ª--ðdó™––Õ‚-/ÑåÄpÇQ14Ï¿‘|pÃg}ò3ÅOÖÞ®bÖ‹×\Ñxˆ ðdVеU¨£k©J±µ»qòÀpsBÄSü}ƃIÏžÏ×óœ€Äʱ�[UïaîÿêÐÐE#*Ô+&ÚàïKè¯=¦'ŠŠY6ÌõG™Y°2�Wõ—°`=Fó<Ö×ÎW¶þ \µ1Y?uøÐSÁ¬ -lz¼Ï>÷Œ¹ÕY6g Ôk㾔ɵÛj|¦¯`iþ F˜˜n0¯á}’/«O°‹ÿÈ] Ûþ«úõl>wÑ.þýC�ËÕQÔ1€ä:ÐUªv]¬£œ™Y3§¸¡Ï]¬á”{þ!ǸÞTÀö³o×t±ècÞ’~Àö ÁÓ£@“¼åUû~Šq™¿ótp}¯ àÆgº™^í'ÔïsD§š™U1@S‹Ëù}*ÃÐ}¾`}j@‘ÑZÐ`ŒIÖ¾ ˆÁýŠQÅ®wòåû2°u\»²~°¿X[Ÿ¥ [3ê¹’¾‹¦ÚiŽ_>ç¿—‹?F1.•«ëÉÃq2÷Gø®c¿ñïîáò·×-CìÕ0Æ8µß %} ßÇ.©'}×m·ÖÙÛÃ@ÖË+p£"¸šÿÏšÌ)á;-4T�UÅ Ò±År敺Œ”î}Z_Ô‘šaU1çz€IºãEÕ·«×äåiæN¾ãÔã¥ËÀë]þz5OôÛ|œ¿㨊‰ÕÌÎàt vëÁ¥?žwE1C϶ïÊzüåõboÀªb–Íë?ÄqˆKï#@–Îh½+@î—1ḭ̂ ŒáïWFgc¡ ÃŒýçç/Æó¿:öX.¿Âo%ýàÍ(|"UA+KÅ}KÆêxÖcÏRñÑXTH{—1C�\Öå¢gb °eoãäïËfJrÅ›bŒáŸ÷?S`© H&Ì¢”·Í|Ñ *ر}è ]¤ÌóöwÞ×6£Ìæ¬Ô]KOuý{’.ºùPh+ËË/ Í0¿ìùaÒ½ ˜¡ë2!áýFæ†É®ïp~°c•/ÊGþ>w¶§vœ\EÌ£ @ªp™ ”¥ÿ^\Ï�Ì';¶€`8ÃúWÀ¤¬³ï îg€¬:ý•£ Xì�Y Åêûuy/X?3@,ÊØ2å¨vÏôl\Ü`¹%ŒRR£ùÃs¾S®ÑìuÊ�ýï÷[ó÷.¹AQ|ϵ 䩨³¿×1äwÎÖ׺®€½Œ±›õOÇ&3¤£0­ï½et ò]÷ŒÎ˜b]ȱ÷°³>Ù=ïå›8ö†$ë½ÿÖž÷»óº½?Pû drì*ÖžË$Òíxxãõ캊¯cõt1vô³÷Qþ9¯çª�°n»z®™kU<¯€ÞØ«»€”œo2›ÚÛúw˜¤ ¸ñéÞƒ‹Ã‹»þú Œqyá¿Ú0Âä?b“ Fc*¦íUö»ú~â<žß·ÊQ×ïý±“1ö6¼"°„upƨ<#ûŠÓ*zaoëúl(†|žS�ÃëÉþŠ’+Ü—«0^Ͱêv ¨yËÏŸçZÊÛc 6̯Š!T‰±] ÐÌw g™AÝzv™ƒUÿ¼é»@W@©t¯E>Ý|kñëŸ}׈p¼[Ýûs@÷]ŽÓn}+fh~]‰Î^Ë÷«ÛcŒ1>þ»¦”«Áê>„ ‘_šî( …å(Æ©×Çc ã2ååWïBñ ±ÆPØò 1d˜©t û³ø‚ÈŠZ_‹ÿ€V µ[që©-›zRYþj_Ûy}kñŠj tÙ^CæØÇ X«ÃU}@’ms j½ÀâÀʕփY v,™‚K)"Qñ9Dþ½öuóá÷-R×ÏãáŽg}­‹6ŸN»¨ê*^»Š«.pÁÝP®®Ûçt#.߆‰½c\žÙú0Æn3?—ÏlÄêl³îåOú3æÙa€€”ÙWÕ/a=Ùx»’t´}&½b6íg™t·‘‘iV÷#c¨}•§�£DѶp‡ïF7–Vƒéت?´ÝýxLbsQ€�Þ÷¯y€7¸æ÷¡Ã`¯æGü¾¨ë»ý˜}ç²qà¿«ëKaï›1îâ{¹bdzF—gBwÞG_¾f¦U¢ X”8�³H7BºÉœ@ ¾ÑÏ+Ÿ1:мÅÔÈÖY‘QÂÛ1çï¥*C«Ÿ0o}£ùîÌÇÏKX¯sfXí’oÏÒ×€ïFVô¼Ü¼^ P{~¬dìW0*O•Ô±¥{®%ëó«}»ã×Ï[Ñ0”3W9Ð÷x0/ªrüó£Þ°ï“V€^\úwS²gˆérÌ<ÿßyÀ#Œïoô{ŽLA{¬ &¬ìí}ìå"Ù÷Q3sS1S{r«¾€7—jÐGQ $ßÿªßU;Ï3(PÊL§\Âuë÷ 㡊÷Jæ7ÛŽ%Ê…]—±¦ú#wm© Mö\½ïÎ{±~ˆ. «r»ÂëûZä÷xÌ« À=—ÿ~,².s«çªo·ýuû” Áü¾°vɼ^úýR㘧«Îkƒ½~ІY=ÇÕ¿]&U @B KSȪꡘ`ƒ]O\0ªvL ÍÉ/ÚUâý|ÅÛdŠ `€­ëÿéŽÿ”.Õù\"ÀÇÞ-, ªß°êfnI§—S»/ÿ`âåÚïÏ?ËÕâ@X”Ÿô÷ Áν¢.*6Þh¾QÏ,غ>ê™ì(xãFåéVÚr"еž+ST*ËÖÎÊòZY4fýp ©w!¥\Jy—ŒW“îÎDñù¤d¼ž1 ù’õÃh^GÅf¦h1Ëæ0D¾,m!öÏ0ç³Ä) §«ÆO`é†1€f=f̳„3²ó¸Âz!00¯¿ÁýªœsÄ� îzÁ¬ûªßÐã>cx‚Á¦ÊUŒ-•%Êåh¦ØÅ÷¤êŽbú+¿—oiº/Qý¶Ñ/ŠIUIú~«]*ÆßKtÁæüãk¾@c 0�Ú-““õ—ý.L ì»H§ú[õó€‡åS=Ë ŸÇÈôZ_“ih±bå½Áù»àwI1,v¿ï9àªP·$ë­hæë>ƨèÄïÖß3 l0&!3ÔÉågëüjõÏpÝ¡þ½Œó]\Wþµ²lõCØ3¹TŠÙÈoPŠÃŠyÅÛ{ÆE_¯]ù~ïÞ“ƒÞwØ©€KŽâ:JïùW€sŸw•ï-ÌVþ}Cºì{>],Z èQž:c½ÉpŠíL¯»DèV}ïȼ÷rÉÓ}°qÄæå%*vÛÇ}QL´{) ú)zþê|¢¾¤óIÏz{A &*\{3ÁMhxº®_µäíz-­šùs–¡€ò˜!ö»Ž9ÕHCQ¥CÅyXyÀQ)ú3L1EjEûcL UбV1¼ÐúlÉû§8«qÖ]Æ”zïü¸¨û‡¿ÏÏbÖ­ùL˜Ÿ2pª€ÅÃ~à㱃P=׊¹U­W»ó Êî÷®bèUååé5së‡øM¨yL\3NæY‹ìä£Dt hÃv¹˜fS~ùøs2Á<#lÅ ]ðO{ý´kEd€Åû<ók¹ZTé÷D1ÅPŠ�×£¾O¹ÅÒ®ü³ÄÊ·ÿ̳¬êˆrM…×ï ­ŸŸ -oá»Ò+…Et…ãËýYÜÏ-ëm¢%|f©][8_ņfõ·Ôö )åI1á°Ÿ£«#Þ^]ÿÊÙ!Ê×¾œ­«ªpþ0­Å¿gÌãÔó6ò·x¨Øµ`ï( ­bÑ)Ð13dŠ Ë*ê/†1ÆóÛ®Ȳ±Ò†ùýÈTl%t§\IÀºx¦»û­¼(ƒíãg©`pL GE=ŸÏúøÜ“vŒ$ŸÐÿê>“®ËÀ¤ @Ó?©ÂÇÕˆ@|‚+A<¯€;LY¹c‘ÚÈð¢@ô ?ï¹$í¬æûéðûT]] ¶;ïñùwÊáÎáüœß=Óë0ÿñqsÀõ«~ßhz̧f|v nnƒwÕú¥Žíž_ìn˜ãËA‰™ :u}×°„??ŒõµÎ7çÙ*â>n¢¡Ô¼¯ ìî*Œm?ÞÊû¹ öZññ˜%iðhÏ]Éc Ñgí?b;èúk÷; BÆÎ=O©™`õzÈ\ òã¾oÞ<8™§‚ØêØÏ·óžøïX=þ2Ø”ÿŸº7f’$Yº…¢¡ª†À0{?CAxo÷š­í~òü ñý ¤‘‘îŽÙÝ}O@Dã?` 4SU4BUT„?ÇÝ#³zî‡ ]™‘‘‘™‘~üœ`€È ëk‚ ©D{¾i´ýÊåñÛ@êpJ÷ý„ÈâÀP˜ ”3z)Ø÷úØVç96Ðâ ó»lM›ÕþKó¹Tklۥϲ’Úr* ŒŸµRndBðrgki¦šbF©|ãýª¼zMžçJíi €I×äúW×~ŠÉReöTÏêù¼=2†~‡ä=ËQjí8_îÐÍŽq;×ßï Páå¾&~ãÐãçÕÓ«z*†afÙÚ]«�)O_¯?`dÏ[é0ÆÓy j+P»­}×r ˜UhÕ5Àz¾SL1¼:pök”ÏB}�G÷O’‰)f²÷´Ö¾L©€Q†€Yß^Æô~»ÖØßœ´b «­=Vê‰I6\‹ÌÌ(ôX.•OÝ�´“Y=V®·Êp° .©è»”Xô 1nþ¸ŠÜÆíJ¤3® �8pä;>v]ÏDôùÍ€ÚG8�°Ýxä¢:ÏJ5u‡åÙ•ßKa±ügFÙ-דÙî�±“ m ³¬2AGËÖV©HeÍ@”sØ#ž7àõÈÿ~Þ£ÿœ¶Íõ P…�AÈH$Œ5ÊD‚td¬µæÎ«Jâ Û+aê±ú„¢�8¢õP×'Ì:´Wȧ‰ôØìíJ�-|Í�”„U{`ÿE™8°f–{®>Âýg ¬ùùt×€Ú…ü" 1nïçÄSVe\eé³tY@K%ÿœq £þ¸ÆßøNø÷ôÇ Èjâ<æp<éçíáPÎÆ_Ú1ÁËWeÅãW”øUVgØñÿžž_+Ï·Â'óË` °YfõôŽÛ|ücK¨”*Ö�¦Kò«¯¯Ò)GAm-…l­e}Ýj»ÅåÍ!Çö6ÓŽnHØ@¶LY$·×âù¯Éñ¹½fcÏïQ<[þY`2Åz»qƺþ*Œ~Æ�ë5í5°ûÇeó¿˜|!Ÿ.}hÖãû10C•(9·Ó<ÏgŒÝÑ®ú{Á¯ß0ÏÔ›Û)w|WMõO«µrh­‚xyÏqqÿ] gUÚ:œ‘¤êsÝøýWLŽ[iJ21äjÒouFJ\>å ÏÖ¤Úh¯Ö†Ûÿ¾Å@U0Öæj;gŒ´Úý^_óªê×­AœÔë7�%˜íö4ÐÌÛÇK‰Æ÷kõ¾fõyVýóµç2 Œ__­U¦�ÙúóÑó{N@‰6ô*¬V’bl¹dbgˆQIæ%[²ßœ¯€À {ÿû |€ì³ºÔ6e¤­”¢Æúoƒtó«YU;¿:¡ÌMI®^מW¯/H½ˆ /`ÛréúïcD ’K0ŽÒòµÊt9¶Iä Có"ö{;'Ç}:e<2ðD'Šci5öܱˆvÆ”c 9Ö>œ7דOXÇ} Ò+©9ïðê@X?Žk— ‰-{}\KEeˆœ×>CÇ]U’L16ªR,«Ì &•øØnƒqFó%k!c¦aÆá RqçfZCé ò3€‘`4@�nGÌ Ó+rȰ|M9&ÀÑ�DŠq5„4ò—�Zs}C-*çXIfî¹xùÄdü ¿~]Ó? �‰ ÀÀ à ûynçûs„mWoQÕï!`5çGßK²6˜i‡)_ˆ®ð!›´sïGç_ŰºÙú»³9oä{zô“öìÎ ÷ßIÌwvŽü5³Ë¶Çy¹f@KI\E@ÿ¾qÉ×úZ?u‡ 2¶Yz5~™Õç·f¸4˜ûsýg¥�›nŸk=ÒëVZ}²ýmj×qßWSÚñ]±ª»ÖÏöI¾T–çaq¹ýü†; ŸW{¾Z[ÍKÕg“5Ëîo^/INšW¨È,è•„Ÿ ì;>îëÉZ51^kÙûªíøtÀ+«!û2<Êñ~™b“!Öæ÷P*€Ý>ßl>gl’zûvãŒÐƒûŽÙò­;HG¹çß½k‚Íí™’Fûk!É—{ºg­†Ì#åxÕí½-`;oeµïÖÁ9þÕZhªžk媯ÉTKï`ñv½<[áŠQµV¿¶[Vî*PÅg@•^ƒ.k¯¸u†žz.bàóð8ίç¥A·2·¸’÷>[›/»~–¿·“*¿þÖþ,f|yÆÙZ~ë÷+–¯3[q¿±�èZ]£+¨BIÆIêÐüF™‘<œÊŸm´^h? ૵öÙ4ÁßÍÖ]Zñåo(±hÓùí{…ÿÖVWC:±ÿþnö{à óÙŒe?ñéVÐn[Lo(Ó¶FU@žÿ‘R‹Q-öéîPÃaʺbÝq«³8±`L-˜¡Ã,rôc~3³«O”ÐÁÆ‚þ¾ ÃëÃ[ý8›xcúl›—CY@lŽ/öí`JJ±§ÇµgPÒÓSèg&J8Ÿ¸ÏÝUɲÌVàì9¨H\Í̮֬Ô2ÄÚ”þHÖbš ׌xä�Ú=%!é€^¼þĈB`‰:\„t#¾'‘ToAú HÀrŒ¦&Ø3�è˜aþ!°7Ýó+�¼þ\\€Õ'fÖüû('�|LZÇô?d�¸?4RŸ­Ž84Œ«ãÙþ&k—¬íŒÛS’ψp;ÿDÏ›{M @¸ýÕ’¹õ–KÑDý*¢* çH’˜§´å�À˜¨³yv\[ ÍŽ 3Ð9€ÇÚ©öÝQ’ˆí±þ.g£æó#=* ¬[ðEGöQnWm_dwUA"ìË"Ø9ã ó¿ˆùÃ^Ãv÷R£Õ'æ9æï;JaÚß\¢«Æ‹æñûiEóþÌØ<�ûMÖÒ€Ÿ‡iÉø7Ó~gèßxùØõšØÆš¼5¡þ:í×ùhiDÒ¿¿ÜÇ% c‹¬=축Ľˆv™%3kŒØ³ùN0)¸}®Xï½÷W¹c·jÊc߈ã}ÿÞþ$^bP9ä³5•Õ˜6õ ¥C3�� �IDATóUyz=Ðñoµ6×z¹j�CùúTýÜ®åúl“Ê;Àû«×ŽÃr­¯1Yã'ª2À ëÐZeæÅÏ…^ާ÷çU%c«÷c™¤£ÍO—?fÌeö< [Ù¶ñtƤ«[ ¬D!€ð €*¬Ù…€SÆäÊ ¥)`F¬3É~]9/cºýÔþä�Éê_Z›™^/ÿrc”‘ýf»›]{lƒÕ¤ÿ!0›ßÿÜ ‘žV8qÂüÏð˯ë¯_µøÃî'r>’˜[9:¬: ^€Ÿ§µ"lmù~_í¨Q ᯠ¬^ž‰e#ðÆÄLhã¾"S*‹¨Œ"+•ãì"¶q"IFE †ú[;>Xäé& cëùŒc2”bêŽäù8³±&Žeðiƨ®öjoÉþŠcž1jØ{Ó ·FZRd–]ÀH­‘€kœ9 FH"Àô�èPP$(mx?Ž@b7Æl›ëåÞ+d,‘z0�gÎ÷m¾.¶Ï —š½¼ÃÚtS{Qæ 2Ç ]qÿ||¾Î Òvnº_A€1z^™…ŒÂÛú~f×Å@‰JäüÜ‹ö~²3ºæëÍÛöü3œï×›<ÃF¿Ë¸c;fì®KáeãX{ Õ¯±\X¿78ÎËwåŽâù>ÏÒœì~_ĸ!róñöÌö8ÞRéy€Ò` Zcñ¡ö=ÈÆwq½ªãg¼Ø^Êbµ½ÍPU·š¢šÿ¬3”2S€°½Þþ@AnY ¢ß^•ÊâÙ<O¯ýt–ý*ðöBÀÜ~¿Y?‘^°ïÒȯÏ ˜õ±)æµ À+J7×§0ék€½ßë×·Í~^ tÈ€\ €¡4b·õ÷ÁVäämý–ž¶:[²ÿfè Î%Þ÷²¯ f?«ßñÏ¡fæ±ú´ÇöªÃúLóÉ�‡|mœì¾Å@ÂA~'k�ÆhØ<ÊJÙåí´Íi»+©¸Øa¯ú3/—­‰µjÏtª@¡brñzj©É}RÕç[·Ó¾ñ î7bSÒ¤ÛOY;ÄÌP,—Lóçe¨ÖÌ®sHž÷üüjýJ�|„:óŠ�Qíž%)C«[¦úyj®&�µ–H.�Ï/Y¶fÚOí—rV ©ØîŒ2Ëˤ—×S†R‰ÈÃü=P¶ÆS¦†EÚ $«¤2ê}˜©ëäÇq¢Âëá—ίƒ³-c#wË8û­£åt_“b0Ç¬Ãæ,¥|ZqÛZ6Q_9Î¥,†!ƒ¿YÄh3ÇÏt"èË;Jæó"i)_‘ß*3"3t[`Ë;0¤·æ¥¿º˜9ÆÝ9Ñã~Mëà8Azö«Ú3œ2ÆÂ €åaй1%³,¼›¯w$ù5²=3PB°K3À„À’b®5`<=Êß,°xkH¹÷©3å˜"Ì(8¡ÄM@fo‡Lr­ïwŒÁ?_Y?q!L@еäù $ # ÞåCΫ8ÑæÞ¤ò=ô_c |°k/Î’ƒý ÐtfXÿUØN'ȧ*íš3‚3fÕl¬ßÈú£~Þ|¾gH@%[~ËÜÀFþ[‡£gŒùï0û~±zõzDï§jÏ-Ò‡�«~onßCwY&a…ßSzÙõ{=·Ô?c*­šZªûóòos$«|÷JiCiAkZ²ýÙ�#Dôóœª#¸Q?Ù¬Þ¾]°ßD)õ³øíùrG–Cä+Ê–¹Ú,O¦ÿD©¼ŠEãßÙ±öÚ¬£éÆÓÐîj€Ë”™`}m°—£ì·•T¢/]Ö߯ͣ5àÈ¿?aà¿×[æï£õUÀíVf·ã=ÜåÁüºÜËi·=k{ùP²Ê¸X“\;$ùx-J»­I útÛ~«�ŠZ›Im_“‘‡^ë)3.}©ÖRçoý¾åŒ¬Õ@ž p•@Bvj€‰Œ±=5�£Þ3t<§ÊëY ´åkíÙ÷÷ZÌG—cÍŸ¬ryÿ¬Êû± RL_ï'ªå<…çÕ¥‘Q…ÀVÿ5Ç' )¼úy$}7€a~¦œ ¸ku©Ä’5Äþœö~ín(©HÖ@—ÊÞÿÑsàlÙ< fdƒ5džýn~õ�{MªPI¬AÙu3©ûn]½¾*O¯?ŸÈ²Å¥çßnj"¸ß†dbwÀ̑ǣ;·Œ…P›Š^jÑ^§=ÒÕ#•™)F™ŠœœÓ9ýB&Äq¹T¤½.xºýÅ|Q %¦P«MÀY9¹£Z-ÖÝœcó–šK)âõOÓóþ™IÁý‡“Õg<—ÖÑqžŽ+ÆEUb†3:´eÊUà­‰m¶_EàÎÀÌ[.³#rf`‹I&*`§3±Xö|½ž¿bZ¾ÍéÚšƒ÷qÝi7d˜ÐôPOÒTûÎï-¶OXU‡x$dÏYÕß‚ôøÂµ {ºÎ¨kf±|CÕK/Y`Ë8L³s9Æq=âíx@Î\`íÍ€RvÝ  ¦�ßnúûë'Êñ÷ËO˜ìó|–Ïwpûr*¦ö @ï*éõé^+ËÄDIê³/] Òد¾7ãÛÕ·#7åø?Â}Ó‰¾f¶F5Ë×úR×iP><~Nö×"Äs`j«ñq,šÞ¶Ïa…ó–KÃyN¯ÿ*ê%ͫߵÙêó¤ü9Tãv6^οÏg9°ÌX¾Ö{N÷Ž[›KÕÒz?BÚiÀÐNnü½Ãù\/åÙ£¶Î›Yà–úÊ[÷ÌߢŸõ×_ˆr‡®êÙxül ØÌ!‹L\ÒkÍ‘9žÕšeX~,ŸwÈ+‡oÍ¡î;”äSÌŸl­¯–l«öT÷­Âi^Ûcë@¯ïVFÓª4`}ͪ*p–•#.öúkís¢™“Y¨W`ŽË[eÂÜ{t¢ùä¶·?â@fVïŒIõ,À:oVÛIƒXnÅl¤6KݪL®,}¸¿d#€Z&Ù¨ìÛây!€öÓøš™bŸEV]"ñ K‡Ò‹ÓÚdæ¸Î@ÛÍë†@ØßäqårÞü ©Î1pÚ¶H_>qõÒ[~órd¦>¸#’úG›rt*Ààfz ˜xÀï´*s&rÔ¨a:Ÿ'L*i8ÌôË:ýÀ#Ø•TXÖ~(I6—„,BšèøËÊ©ÊËM1sÂJ ¢´SwL‰Åóã¬îpîŽpë <›|gG¦C kóùÍí6—÷VÎ:¦Ú7›8gÌ¿*`Á®9ÀW€7éИ˜dê}ÈžW–ï#?.Äz¨ë*é4W.�ú"ææµ[EòT_e€¾ÏÏöóò ÊЪ<¹Dá 8©ïÅxmý úƒôã}¶ã‡Qþ“ÙnÓu\ÿ•¦k¿€*LZÿ9‡ïûâw"ÒÙq»ÿì®7ï¿@?ʘòœ¡më13Ãnõ8FÙÅ…cüYaLFõn&_½móáÒ†ÑåÝ#™Ù5^y¾ãü,h›ÃU­ý5_™µ«UhðÊ5Ç×Vˤù¼ÔúÖq»šÙë*†TÝxùòyÈ)L¯%ÛÌçWâr‹˜ÿs¾ê=Æ|X –.7—Àî‹ ÀáßÏX:hî×â|l½Ùv­¸$ãÔÑ¢ü;}‰Æï0>z¿4=N]cP5 [óã,É”ÚM]LJ·ñÅA¼w™DZö~]?³ÍORu¬kǰêÑÆk´? 9^«)c¶hÀ%³£ãZ¾nÆÐR@O­}²úxFEæO[³k±¾`XZx}×%{¹Uy€ÆóZj±)Yn™¿v 0«71P¤Ú­þÞÕ¤%·/Ùù|Mª«¨wÌe�]ÆåÌê·UúñPî?Ïâ|[Î*3/>PVm°�PZ’$œò¡€ÓÄ@£×™Ö[2d´hC2ñÏæ™a_à·K$*À¬Ý›ßŒ)€ìÑ”ÿÂÏ’ýãñk2½Èq·­Œ­ØrIž®JYÞö!ÏlÏŽðÄ>“6Q˜Û'úÕ‰Ô§ÄÁj¥|æÈý×i?J,žÚwšOk¹ƒ7ÈØ„2Êx¤:¦;»üT¤§€«E¹õbݳƒ™M?PšŠEôÏŽPd–dŽ÷l{ØÁúZǪ¤p-›ÿpD[Ç):¶;@uÉ­YâŒ]§;ÄOdÛÄö>žƒp”f@¤z_ãˆc¦ß UÎ[î2`JYµß`ín«�ÓližªChUrg«Ã)f€âûg™T'HHî)l{¨È÷h³þd~_g`Å\c¼Ãeš“ÊŸ£sú¼UÛ#Øý@‰Í˜¶Š©Ïi…Y¿¾_fçá¸Æ3àìÚ_33IµSÆüÜ¡?ì»ÈÇKÎûO èG{ßïÏ·Ò|û®Y8ÒãN>!öùf€×s04 ül•б×U¿Ï[¬æÐÒJܱõQR•y€"–«Ã..Ž‹çòeм}óQ´àqðág ìŒß·6Ï;T ™.WÄìî҈ׇäáÅ1Æl~Çûùšß¼=ý¾ÜªwÖ?«À› D£¤÷J@WÜžÞ!ûÚf‡nwìåÞÊxMÍÿ‘©-“’ŠM3Þrh}Þ{Ç÷ö?!“eØÊ׬Y´•1øCkÕªŒ{=½™j•Æ´¶¦Ú5¦ŒÏ·`f–1'Cî〴Z;U%ä< ~ª}²öÏ€y]0æk7V÷Ûãš¹¶í¹ËÖË’ú¹àïêß´ôhvöokR¨JªvU:¶zÞ!ðÃF€(„!€¤Öâšö/iä:™4b8SÀ-Ÿeˆ}n®)Ö°0c’м‰þoß÷>˜a @û óŽÿ˜¹”kÓo»¾/O»—£jq„‚6ž^9’ªklo>öåC`M9â›ÜØãµ¿æÒv�ìmúµ°ka¿wHªë~O'~*òÕŸ9PJ©‘üZ;‹|õs¶2ñš×˜‰#ÚGdöì0D o÷�ZP0‰ºlZ8”1‡º—S€âIœLîǵìD|^kh¾î¸[(½f™)ž!ršr·é,3b0nÑÂ0[þ0ÈîÏ*ÐTetf€_øZ-¯*—b$mÍoëu³ú¯0I™EŽ0UNÿœfŽ8 @5—º=Ž÷þL1¨fà+dx±8pn¡¸>»ýkŒ¸íL½Ù*’„àŠéÙñ<bþì¾}?¶§-¯î‡Þ’ãsyY€É­Ü'úžn°£v^Ok§ZfØÉ1Ål Å G¶eTÍŸ#ïHf†kúÝ6žŸ)K<9ÄÎ×’hkÌ4%ýxLÒ¯HÆ×Çû¥zªÜµëTMKÞ«ë¨öædJJ·}Ÿ•c¾.>Gl]¯àøšg ùŠ–±þq´n�Øå±_[ö·3¿Œ_B‰Ã©\/ù<þßm;~À@ÆìûkOï°UÀK= 7_h¦e•Ñ;°¯â·Î@âž±V˜5µÕ”DÝê3 ³¬zýjÿÙË·ìk‰ºU†–#³3Mpò Ъ>¯Š)Ư·XòõŒË•_« «lœY¶öÒUŽËš©wõ}¨K8ªúöër ¹Þ¿.Iä5ýüñüózÅÏCÆdZ”WÍjùc&1š—˜Ü'½}-æãz™eÏ…”B†ÕVæÉÏl¿ü[·†Ù7qü›øES’¿B~Ôøb­ €lÀfÀŒg_Z`Šñ3Áúšcfð¥×àÒ„[-“Qkm Ë:~\I»dÀÜ~)€¬Ã«Mô/r›KIÌŠgDLŸ&YÅüÝQkéµÉb±Øæ ÕÑ¥¯9"µ4Žu$_\ä{=’�JZîV|?Ñ‘b–È$kÍNäçµÌZãQe«Tu¾bV)&še&tG¹b– Ó 5šP2ÍUQD?s\ £�ß`gºõãÜcŸ;ÏÄñåBžj'kçä}W‘¾ˆZŒV™‹Xž*3/Ú?·oäC 3o¯õzeíˆ×C&2-eŸÓþÎÏÿ\dRÎý;2ÊX9ûówz䟽§¶ÝOíTnçªmeúEÀh´vU5¡÷ã¬_>&çÍ@—ýNáþûç€\š‹ÇOô¸*Ÿ§DR£¸mipœ÷CCâðö«aì;uv@Ú¾ï¥f¼w«9t4ÓÉ\­�̪’‚u�hUÚ}MÊêy µ�Ãcê(ûæ]˜8ökáÊæ÷rº0°‹_w\/nõ8…ãZc?:ʯÇés=F?fË‹R£s—+¢ïÊÒL0üí^‚þ‹-¾�„ѵÁÞüñæç1þþáwƒ1Y¹H9‹ý9"þ­Ek<Ùöf3 qžö\i]"«òû<F¬-’ õˆ×îñçÅù Ë�}ìgpÄ™+ùõâã™Ä¥g´ÔÖò×Ámþ¼çÒ~µ�”+´Wˆ¨q™e�Èsþ×óÝÀy鯸>äšU );?g91·²öáí½wM¶­@ê^hfW׎ñ{¯ûÇŒ·T¶º6 _K,ÌXD:° 4­d¿²|”Ô!®~é–®K˜a&¿ŸZk_Ía&ØZ3ÒŠÌ:`Æ$oEO˜_øzÿÇíü—¿Ù5DzµÆ–× Ë¥H¸´ŸŒžóáPñ\Z1duÞ¶òÖ#G·µ›Š÷‘³Üáñ¼µË¼ƒéæÀô̰88ƒci–⌽vÇìï@ØÛý8+ßÜŽŠ!ÅÚgV꽈$0j€Ó9täW#'ц±x~º© i&ÝÙ*Ð;B= £Žc~\âFr7ë�ï_˜4ÖXãh \,@Õ6Í|cådÃYÖ~Ȱíwnè 8'íÊ΀´õœ×z«2§l:îp÷ý³t(Í÷‹—îi´}}ùT¹Çó¡˜Lü~œ]ýìýÖŽ$ øâyЉ:€]dhöüçßSSÀ12²xdÿüœ`{" ËŸn°]ðxnÓµâÀƒôYÿÛHzö]ጫ‘c43I`Pg€¬gܵé7j—ˆI­,°W]¬9 ê;ìW5ÝÖ`ÛK?ßj… øì»÷½˜N×··OÔ~™›ÓK¤Ù_e5†OVîÜV"îÈ<ºç–oÖ*ârÖ¥ùT{òq|fÕµŠ*^|?J£"S4.ÇÜïaÿgóY—Bš¿olþ:†­·öUy<Ss”#c¬Wîl<†Ì°Y*kZeؾ IÄœÿÜ`½}ð»‚é:€h¿‹œA—}ô~ÅéŽr%5µ~=fÇ´ßjb;vðªòz�¥&‰Õà†åò[öW™pÖ™ YÀgXáu‡e�YVTèúÅíT•ÒSÏc$p‡û¡D~5f>÷ZŠ®ð²PSùU%å<ðnë¹öÜ\e>5Ëׄª—{™CˆAS̳ È‹·*P©¤3ýõ2ãåÉ¥Oí¶’@­?7¼Y9•Õ×>ËÆ—Y¿éù{5ê…€TÆà¢û[ CFM÷òo%P2”tcPÎðøO­µßÒ,oö•î%çßµvÆÔÚb&íÛZep½ÿƒj=ÝËßìönÓÚU i_ÄE<‹™.gL1®8n¢íu€lMs×|ˆ\úFˆÏ‚T‘ØÊqÛ·t6bûkltfÚÈaèØâÀ]f•ûÆ"\£È}žŸg`V˜Kþ8:NÇs­$gx¤¦>”c¡"Vwhj`ïRe‘1@ÛëœN˜ìóà™`v#e3pÒ{Ü2hØpe–POɉ:N1‚ÏÓ¹YI›óTÞ^'�öú^[ïÀš÷ÏkAÍå=Áyèx52é,ð„€Þ\îÙÁ63¡X¹Ï ;|ßx?ŽåUõñRŸ¾¾}Ï Lžà~Í_‡ö€ÞÈŸ¿71p¯WiÓïŸÊ/à૘Ê¡yl¼?S*ýÈ7ö˜C÷ˆgíjGÆ“ÇÚ¥ˆÁ¤Ä*ÒŠ©ÅïÈ �Ll­ØúNß¿30¼ÖÜRu«–x`C­¡¤€ÌZ„0+—-ß®e¹­1%Tý”ºªçÞq1*kŒy Î3ìø]•gõºº~«’WØèñ¾çÕòÛqó¹ø½ðãd¤³òEûc`ÅNÝêiÇÇ3£ç1àçËÕ. xÝìz¶®M߬]Äx¶2ÁÞ™´¤í—Oâ{ìÀ,Ýž³gH%ÎÛŒytÛ¯ž¯­†@÷ª#Mª+“NÔ€Öñ^¾ØŽ÷ÏÅt¹óúó€­aÏføØ|sFL£Û ˜Ê‡õ«Kªü•?2Y’µ[p(¦J½}ÖÆ;ÞG1Ï ¨L¯ñ{p]U¿ÿU&e5_ž?ä‡òó¥8Éž“Õ½bÂÕÞóƒ,µßãõ¬3á:Tóßg’®u©H›Ïvæ^Vïsku�©a==Vʱ•1Цë(©Æn”a¶Pž£í'³uct}½Y_ ÃëÏ;p¶"•Ø™fÈ»UõïñöÚb/³çw`ì Æ#UD£>ÿÙ7ˤ£‰“µ*pÆM3Ûøo鵩޼֮™´Þ(ﶈßÈbÇ?FZ÷Za$7®ÑñÝ9¢:öJÎûGĸýÝVŸKò«ÎÏEÀš%5,–úù¶ÇÕµ¹ýV †G³öa º~«?Jç¼çãu@WuÄ0?O§s;"€ÃÒu©7›0Nh@Gcbùr`M1múöÌT;“óY9UûÍ€èF),ƒÌyXDÆ„sý{NØX`m0 æüfÆw�q@kœåë1·Ç¸ß½<£~J²ifD! 5çk/ËH;ÃÀ{<¶þþ¾Ö'*5€,‹´Wùë@xô~ É'—~î§Öàw¾/f6:VßL>\RÊ·SÆlÍÇeØa¾¶\ö<t\ª5y* ‰Ìñ‰8¯áù|¼Àöh;9 iEvW÷H!vË×lÂñg²šÙ󹃧:ÞË¥ UùŸeºVl+ð•K›Çãt¯ðð\Ë�À¼½4#9j‡L¶²¶Tÿµã'-¡5Çp_™Ï¨À‰ûm>Ùû§¯x`Ƕ{úCC ¬ÛXû«Aº¾?ëoI9Þ¡(3Ìþê�—[)¸tb_;’ÍO£�:oq Ìµ5ñÝÄö\3õ^áûïçQ�WeN¬–ßö}-°#¼™[æ¹5³L-…¨«h1Cg¿Ãuõ9Q÷m•U½^Õ¶BÏù>e÷y]š-Ë·Z¯5€èP>Óãó¼Ú®|Wg�òz×%EáõÓååùf®b¤UßïŒ)‰åB†_­üy{×úm]ïUâIl9¯Î�4^þÕþÔ3Fmýu>kD‘â{Õ.®8S€®ñ…é2�n:N.”xœL\ŠñfjJjq–Lüú`tÝì·0Öm–RD€‹I)²5Ç”ä¢n²¿óßûÖ?ú/a˜5Æ0[½¾³l`§Ò¯F¶¬Qjí$L—•ï’tõrÕÊ¡²½H[•Î_/ŽŒØ¶â°ô’Џí×à°ÛàÂHï‹Þ¯˜ÔrGÞ|^ô°|V"°»ÄÈí< ¼0‡”r¬ÞL=ÿZ=3MKƒE†@ÙlÌ1=Ÿ¬½WïoÔl%õ" ¼3y1&•ÇŒ35ƒ$–`ãŽX²Ì$ °Ì€‹÷L,íxšÛs¬E…€ß�mn²åûíõ- xz\·Áõð,ëèåôÌÎ4ôL3&7ç‹%P@-»>³Hb0² hæÀ4ª#i°Q ÕŠ"ök†g?ŽÒ_1ž¸|y?äÇSª<ì>z‡–î§+í¡Ö*CÉGÖÏÇ̅äÒ‡gHwv€•”™ûd–á¸c‹­Œ{V'_挃ªÃÕæ«¾›U&˜?¾Ïaã÷£Õ”Ö¹¼Ý4°£˜y¸[4Œí"Êé¢ÁĹýúïÃÍ´Ä ¸˜$÷lcÜêó‹qˆ…í;˜x À1È` €eëÀ •_t}\ Ó1)¼¹d€Úí÷˜Œïöú§pÜÀ˜Ál¼z Òc½â€šÛqïˆDü>¥‰£xçúÌ¿™ãXIj摲,d·/tï³aÓHI!{#,¾õµºªûW5{¯WmŸSòËó©KÚõm›n;µÚ^üúX/d½kŒ üy®,üyõ@â*³f àñ�΃ۧ^NÕOÔê­ûÕU`{MrP3á²qï6‚ÉUΪR“ê8O<c´ZßµtE`¯RÈÄê€Q�HõóhZbp¡ÀÜ&ÉFäùÖÈbÝP:ÑK$ ÄéwÒ*@™Úo˜fÈ{T‰_­ðz‚¤"N´†#Þî_¸‹ÛŽ#2ˤéü0¯F õå©Z <í_[¡æØÐ@Y–o\çIàÄWo­9GÖͼ´ÛöµÇt¹´b7 ¨åIåÀ˜ }b­ÒÓ[Iï€óëÓÉÊ×;[«‹¯ÔŽ–xM(Æ$ÃHß¹°<ZJ•·‡vhÔ�Îhä ÷éÎò|4(‡•J§'FÐRÿ“¬ŸeP)F™Ÿ`p4G&׎ûr1ÇÈü5Áò¡D +/J;žá=Œ¶pr¦¦•Bœ™eo$¿¹}g�µ5ÿÙ÷Îç‹–¶*]éÚbºÀîûÙ{@Kk¼ŸœûCÖŸF@MÄDïCÄ€±_ tÕÚÓW3ST1Èœ¥õ*̬L7úž!Ì–›K*çía¥’Ïïü§G+Ùzïº}Ÿøxë¯îÂGÙ¥Ù5üxkŸ’AÕ²µS³ñßóLJ8nVãR;^xÞõ¹CÃ3Yx¹Ž©ÃdŸá}9ŠùÓqš¯±@'-IÇ6ì"@|îŸ4“1~Ž/í¦›¶ùû’I³úúZ€ëÔüÌÏ�� �IDATRÙtëÆ®ï%õ¯­ßx2ß‚üï¿F‘lOv¾ï?ËþZ£*ó¡Ê÷˜Û9|Ž®ðÝÜëpÏ%íûwl~œmmÕáÈíº™Ó{¼ÿ½˜£ûaÈ<àõÏ%³”qàb ¦$ðz¹ª¼^ëþ&•N8Xj?„Œ›ÌŸ„×ib¿ÿìvÜ.õµØâñfPÆíäŽ*ȵ«xN•å�l¿oYùø~߯ĀR b»­žºØ WŸÿjûÄûW £Þª}jÏ]õûK1*€µŸÏïǪk^^ÕŸ©þy5 ³ÎôjóofhBûµ²M€ªL*c:µ6Y/7¬!öWCÉCÆücŸáw>ŸI*¶æ×“6\_’ã·*ýKk^2³€AºgMT1?Š3Å<zE´ù}ûµ/ÖQv¹ƒym›—sÿÚ j¿bºHJÞ.ü>©ˆØçEä³\ŒÞ/fo2–Qv~H/úüæt­)‡!¦×޽-ãÙÉ"l#ÉAd�¼Òü¸Cu6Ô¬Ez„µU‚$p´cóÒ^s{(9þ2©/e™C—‡ºU)±L:F¥‹#„=óeÐå°[zí0ôñ½Š¡f™w  Š" d°û§ËÁ#à‘‘¦Ë1ÒU™I¼|ÛŸ#\EåÍŽ³t¬ŒqPøT?ØÏgý#¶/åØÎ|ÿIÜ7µ¶Ê Ò’û`¿×·í2·#wTûv›óËâʽáwïï'—Înûïð|ü4¼Ì�× |ÍÀ™~˲�˜±( êMì_³½ #û»ÊËËQu�ªëÆÇŸezü3»pÞ“9{Ë…ãrªqØvFï|=U¾Öt Še¸óòz&32¿Ît܋׫H#òm?î±éü8v¯Tª½þ­ä3à5K"z;ÂñK˜ïÝ^”òÂý÷eôKJ’]Í“9ðIiFŒn½­u¶<‡ lË}óófü>c}3ÿAYoÍ;ãµÁüa(™XË-³Q^\Npœ×Ë·KU+s +P Ôéül½|;dŠCU«2^bæ´ª÷5iÇuéA,÷ª$e|Þ:³Š—sÕA¯€CåŽb ÏKÜmOäLKLÏ¥UùÔó¸øÆúcþÏ%0T™¹ëR£5?q¾\öœl5hcy•Ääs$k=—½70óåÈÖÒ*WÝ L1ºÔõñx—rTL°ªd"=®Ê=3Änk†ýå˜a_áצo-fˆÍ–g¸ÖØç /PDÀëý1ÃL®1ö,¦fD)�F1ÆžQ™K¢_™žXZ‹#Bªku=O«;®Ï(×`ô0Ë€2eÏpTT™;Ö!fo'Xkä ŠsÄø›ùÅVCÇv¬½&Ç»E€sÌr Èÿ¾’ãžQ`%å*íl˽: A¦ÏY8¼{å;„"¾¿cQõYr…1Äj¨¶¾ÌáŽÌd¼EŽîcÓ€UÜîõí*³-¾gY HÉ$öªåSÒrXÎ*ÐÆË—?¿ӲƬÊ‚œ ¦Ë±U% X‰òÁëdÌYõÏï;F ÷vW ;›ŸžpÙþÓ3¸ø¶Œ­ÃP3(æþ ÏÕÀ‰锃RYÞ_zIbØrvßOd€¿Ç­TâÌðî�{߯WÃ3»Ñö8²+R¼ó¶ �«Kð}̸8Xâú~”)©ÅçK"òvÐóÅ`ïû÷ݧlpLÊu‘娗+g²ç5fŒzInVîÖ€ñk0â8‹•o.¿ú" ´~],¤à Ú!³á0RÚ&ñ=¹¤ã§Œ¯·ûö¬FÆäxhg0ÙþÊxW;víš,è@œÏ[UÌhmËš5 $¼IúÕò_� {³VV«Žø‘_–OM²LKvq«®é¥×’â�1iÀPÌ΀$0®9²í¦÷õ¯Ž_lú@jôxu-­üýA¦Œº^ÍrIBnÛ׳õÐùfשUàb«©vϘŽÜêR¨µòÔMü{óç÷û©œñ—õKö>#`¶þ]ªùóÊ¿#]L¡eŒ+º?N¬J**ÆØ7ñKÏo‚i¦˜l7@ _­µ€9æ°/÷ý™Í€×ŸÍK/~i9ÃÌJ(¢qàì }Ô"Îʼ¤‰wdßl¿E\ŽØê�ÏVf˜ÕìWùeŽÇz½j(”Nñ¹ °ÛözYD¯ZkÙ¶HÖïtBÜm§i»§g­užòiMo>‰ôß'Æ<²žISe޽9âɹÃM_õ\ZÇ:úgG‘rÜ[ ãœ­ÅÀù ìÌÏ™e œ£}äkÛ /ö¾¾ÁqîˆÇòÇí­þUl–j×Þ>Ñvõ¹fŽ#*`ç-ùUVe°ñzêb|V¯_a&Fíµ§Ê·‘ü¼¤ž®ï|ယ¯¯™IÚ‘«”¬?Sæû›˜©š3ï´£A1+Ùù—`|€Ï]t¿GzkŒÁ=÷o™ô,³@jk²ïâ×÷ßKŸnfPž&F·ưõTàJ×ñ¶Å2¹ô @ÒekåÉÊ™s÷+l‹ˆÏYhÛ®øøá˜¦¯Öã¹Ê£||Ü­�°ˆ¡R‚1�!H ÀLó%¾>] `TˆžÛ É—G€v|k#À*ðò� ¬¥oR‰ù ´aöú¦æï0.xÁqé\NÕ^œ ïÔüÚçÄ~çã”]? ôQ�:Ê"‡u5Pˆÿî]«‰—[1§Ökƒ½Ê™¯µ´ºæ^GFkߟª£x¤%s`°;W™dç$ýš_j¬¥‡ùÅ’”UÆÇ�ÜÖ˜b9#R9Ò«€]f5æ—:¯ZÞ±–Tµ?áÌËÀˆ×0«3x¶_ù}QkÅÏáÁ=¿™©µÏz~-Ünéóœõoê¹z6`hßc?§ùÚpµvª[Ünþ;Y lèùd„™Ÿ¶ÈÊ,[LíÏ�½ 8£çÿ$³û¹ý&�¯ßsËn+F·?g‚!�&¥¬[¼æ˜£ø+ j¤ßk()€k Y åèÒaù>Ö¶;"Ô�„¯¥¦&¬*b·ê�Ø.iƒç׈ ÒòÇkTê³ê¸ë6K'1 Ë—z–búD'¶£öÜÑvš"׫õz¥ék€šbbô|•#ÖKå»y=î¿’hTL¤Jä®v¸ùê+MçÕnh`CF ¶›uäûë¶æ×Jò§AºUcÝ‘£½*Ö÷Ï¿¤[‘ÜZa¦¬:ö«Œ˜Š”&>U¹r†².s°éµkõ^qˆ+Iª~þÍÿ,Ó3É%üÎhÆÁ�¶*LEúïsÌΦ}¶Ü¶Þþzg�¤âµ¾Tù±¿j$} ò©;е4pÔOïå'šú^Îßgûå*¬\aQ{ΦÆg—éy½í¯Ž«W^öº˜ï*ðuqãðšÔOùx龨2‡yÞÖʉý•/7¬ÕÚ¯jŠñ•µ‡¾^HxÞô}eÊj+~m©^øpz�cÈ–ì°qü¼¦nßæGX®l¼Z `Ã5Ÿ k�\U�« �l:ïÆ%/[î+šm?µÆšÍ‡*ÀÜuúm÷ë´æ×ZC�®â(­Œ«Ñ?’ùKXy¢t9ðƒ]Õïת)¦:¦‡dbæy.óE1I´Ã…*$éã?ʶ2\²5zªL¡¦«3ó²µ½lº ðôCj½Ýúu8PÁöüúÚw3GÕw+0¼ö~äsÂß³ 8΀ÅýŒ$Åxêùó÷£ú<WÛ={¿òµÀ°ÜÏaÂzƦz^k~úufb äb>úyA&W7äÊÖëljô` xšdб–1ɲãUœ± v“JD€Öç6c=b¿¹tÍìG -Ⱦ:ÉÄÙþlE›�°/­©5ǦýüôPñİ>ÀR>!¨pÙÄ{P–ÅQé1tåí82Éš­Žçý‘¿6ŸdÆ 3ÑZ)ß*#d p€Ž¹0Ɇ}‚ß!ñd¸†Y¶æ?Õ+[+!cˆÌé3‡yäR„~Þͬb¯d[]'úàr� ™fÕH_<ï,ë™ë菱u‡ÿü>ÍõÈ‘Á3JÚè¤S %…Ãî#c¦1Æ‘Ê×·£½žN7ׇ­M5›ºT9c*¢U=T{DR¬ð<?ÚA1¿°<ê¹³õ9»çš1üf€8{ž”! ¦€,µÖ w\žhÿq‘ùq©4/é虩öº¼Û”³Œ!1oבy>¶u¢KâZaý¼ñ½œ@f&ØVÇì3L]ü{¡ðþùEf½ÍgU¯³ðæ×±ÀÊ¥8ÑE¦OUù Z/]n4õ}æãòcã@Òz PÍÔýÉç hgñ«ÛA1 ±<,ð§÷×W€ˆe‚¡qæÚ¥eÿ•(@;‹ïžïƒyoà̆@Í €½Ýs¶€Ï%­_/q5`êu�e�3R‰ fM}§1ÀË33†3¦SÀâlw|8Æçïø•äŸÙÚw…û)ðxfÊá[_ƒ…qöýÑãC±úeˆM­©t€J¾FX|–œŸ9f5£)ö¿h‰±UÆ“*ŸúNU™7«â{Ó·ÅóU:Õ­sf05€m«)  Î‹ÇõµÂbà/g�bº ÐÈžG°fÀŠ**Æ`ÚÒñZÖÿÕž[ "@¥®Ûûžó칸¦ýVí~ûþµV~ßÏÓç¢�d)3鈤a˜>81ºV™Ún°6XL·¥rYÉÄÙþ‚ߟïé~~¤ø*%oçýû(«­=Ö÷gRŠó'�Œ®A6·åWßîßÏÔ ï05S¬Ý+‡Ã6ˤYÐQâ lbzJöór¬vµz®3ɸd"Ö¿*}ãKÕ¢¶ªÄ`¥Ö¾ö�ÃVy3ém¤ü¸»8óµSÌ2¿¶Ùj½VÖPÉDê|/±s¦ÀŒb@°rrÉ–lBß ý9©ÿXS;Ô•Cé,MÈèí`ßÍø8¹|8#G‹z-‡W±ÍÍ®×Ó) ½9Ÿ¬Þ­ñz6ÈÔ“3‘Øó†ù±ý¬}Ø}PõÌÜ•~ü­UúeîHÒŽ.ËÜœŸKûüžMýðùf× œDPjIIòmt°b:<nßïKóýÁk €Ù"i«ñYéÕÑΜѶÂàSí ìqÐÇŽÇœq5·×Y¦·ßGß[~z|Ç0@É-ú¸#;ÈQž‰ƒÛ*¾êð©Ù1ùUâë¯:ÊPr0cR~´á|æ ûÕ}³¶?�0>O˜ªýÔü!^£keÀ¾ïjMí>�Ò3~3æÿ~`  L?Ž2=½ \©JúYFÓÑ¥»8Wï˜ÙñÍQ~¿š—D|‡z˜5ÄbÅ…Û10ÉÖÚãÌðÜæë @q8Ù÷ÿ ã–­–õSu&*7tØÕ¯¬¤ÝŽ"ÕŽnëÁÐá9aÙ÷­ÆÐñ˜kҊò@“Ìÿ‚L7žo¨à嫯Ņ×oæ|]¿ø|Ý^¼]ri¿míPß_mj ÑÖñ°ç›KCòó<#†×[Á«Œ1Ìûé®Å÷½~ýl<Í­ÊÐó¦�-%é¸jü½ªöWÈ(Ô̱ªtlqYe¦ùôñ÷á*ÒWû×\ª±ç³*iH0˾Áþƶ ùQ[¡¼ßîé¾ÁyŠGÍJ&~ RþE~o̱ßîÛCR±µÖ~¾3¾fà¬3Æpÿ|a3p6¯9ö 9Nmb}ÎÒN¦� \ ëÙ† "-Íd©í€JÆÜˆ·ý~5á®:NÖÊ×-èçéë·o>WL3Þ‘ÕwkÙÓåKÑ#æ‘Qö‰NÜF>ßé62Ót­‡£2‹$]YC¢5îQLŸì9ŒŽ#ó†;ðcéµQž|@Ä¥5�ÇÏGÂ9mçcE¥×L6°qé¡£|ãë#�¶*å†ÀhäÀ}ù!઀=uÓŒnÈlŠ˜¬ µÚß"i�VJJ*ÿލçÛW8Î"´ýóî¯ÏLÏ,àíéßC”`÷GL5Ö®Ù8׻ߌÄ„lã󴿨Ãþþ{zœ3“?óíŸèyzÚÔÏ‹·-_ó,�†¼±£C3¤W-k «Ì²�(­¨pJŽç £y;Sfxa¥âï|Ît‹Òöš0±ÿY—®ª0¿¢ïQ ”ëñ”÷hænH`õc€‰ê·£ï8¶ÇÅ•ó=›ôº}‡EŒ[/éw³Îl:Üï€f0;õzÿµéṳ̈ƒШ¤„ùø’Ÿ*mj\Xฺ·'o¿mÊ Õ÷ÜÖµˆõnʱ¼UZï"J®Á¶JÏ¡$âVÆÓÕ9Fã|¼c|ÕA‹ÆïãAæ» ÐÕ;ÕûŽo-¶7ðF½¼:0#¾ÞÞû[IÔÛ‰§_eÕ ´Œ¹¦ê÷£V¯z¹²òdÆÞUFÞayÜœŸùxϽkR Š1ª%ü°]ªåÎ�Ïs)½’ĬJ'Ö­:ÏYë°]½4ªz ‹�DTÂÓ½ÿG¾W ÈB� %q?Ùÿkr÷kˆ!ö~›Ø¾Ù Øḇ.ÅØ°lí±/°ÝZkÞ÷#Ð¥ÖK1¹æØI8ž0°&ø|©‘Õˆ,G†¯EÔ#^mD®– É:ˆ:s»N-2ôÇY èÓíª–0Û21ÚbÑÄNO |äü|þxË<³l>ïäò±Ì3YƒŒOŒÕZeµ5ZV^ŽÈñ<ç7/m:~)|p-PR°ê÷-v) ÁOì1’ÙÖß3q0?Þ^Ö1Æú=ê¢tìþ¼‰ãÊÑÏÛS¥ãíª€.ÆFfsÐ!?åØûŸ0Ì0/­×Ó«~AI:ñvÀ�{ŸgÆSü°ç³¸ø5{~ÆõÑAª˜ ½Þ1ЬÛÇ'1óL1—g†Ÿ’®T¾¹Þ‘êMür`J™¸üþ.UȱÎìòR†¯Ýí±¿Ÿ73¸|Àî¯}?Êòq(R)IçL"ku"^-O_· à©9JV•2fî~€,žø^Ä}õ÷yUBªfë÷5“ŽZcRºªêߟcîgj7˜Xñw6Nx9ð»4æ±øÝ™¯ƒ�œ^ûѶSeû|Ýl8,s®zðWÌ®¾¿3Á̶ ”âfÓ©û¨ß¶0è¬T¤`±åº:Ÿ½FS¦ô¢bX.ë^_ó¤Z^,×%L·Õ¼ãëŸ9^»Åý™–SŒˆUf:o+ók›þZüîj�l/3fk»mµêó×Ï45iE <ÅÌ@]Γȧ§Ï€Ýç´Ÿ?Þ˃׉ÏÃ~È÷KU@­Ú?óò( c{?¿ `ÛvΟO{>Oõò×ÞÏúbñ~½¶clãþ¬ZkížõÛª]‹ývyõ-IW•X4×ë¶°¢�a–mZ;¬›eˆ}¿_Äþù¼¿D>?;æg‚µöäû›ÙÏ$g  ûµqG“²Kq ðüÈÐØ<ÄmÞÖ¨¸ëåj´=ôÚªÃÙiSsÌüó€´Z‡è#¹9³àަªÔUÍ¡9�¬y >wXv;9©F°1Fƹ �Ì®íâË×èyº=²ö\‘.‹Ò3[½ïùãYWùe�ìêD9ôýÄKÏa„x>@‰%&ÏÂ1áËcPÖc/nÏŠPš¡«'‚6r\;ÜhœÓç’§ð>FÌ2´ø>œÓóy}x¹4CkÔëV~+=5ÒÝsX}/˜ƒí(š—༶q›;†ó~¦ºV oW-ûj~½ÍûÏ‚©Åòµ¿cMªP`Äõ|–CG¬÷eIzÜ…û«ìZ@Ò*“ß—'+wv^–.‡fkŒæ UÃq|¨ça‡x^ð,ó h~Ýú8»îÃñî ô+ ^öþ¨�4;_ÔóÆFõœ>®¯•þeÌអ8c)f¶á/® †õéÇY„ü*£ém¬ýE÷GÀÜüýåÚx=Ê÷«A»«ë†õ1íÑšìž`\{}üÖòWVOW%¶bCGuî0Í´ì–ö3ð\²ú(�f�~U†\ PÌ'~}u|«¿iÓ×?øaþJJ/fœi�#°ÐÒ{Y;eß'ðUÇSñûŽí˜9ìµ#k@:oÏk2~ÊѪ¿/–ºË%G9p£¥BѲûž1“8C¯›ˆÐËî›bÚÕ˜ú½¯}T? òÕL0<¯Æ¤Ó’‹ÜÔ÷ ©[¥1Ÿga=PJ°MskдA¢ñ[´Ýj ¨ ¤Õše­5ĺEÒ‰Ê:Cì/Ø?¤cìfvͱqݯ°0Å”Íåý¥Y ì—¶jUJ*Ÿ0¡D…’"úx³/„’¼ñüü­/t}Í�¾í™ Õ± À×£Z¿º­IÙørXÇÖˆVés@­Û^‡^<AäÊ3a‚½µ¤ùÒ~’­4—ÿçŸezåèüäê“ItõíUÀkÎ?b*ÍéÔ*lí*”þ‹€,‹H· ’xBÍ2œÁ–KÄõòp©Çj„ ZÃ#ÑñÂóC +›ˆŒ_î@òÌ( UŒE’¯LŒ_“ãj--µf–m§QlçZýNØCGY\ßÙ¡ˆ’„(AÇê5¯Q†k(&b?O2þZã@V¿N&•‰õeù„Ùr éB °kvY�ìäÎÿn�7ßß÷ý·~™½·ýߟ híµ“tÄΖ­õrLÇSÕÀ‚x<¶tñôZ‚º‰í*`¦Æ¿ýº`Ò€ÔÇŽË¡’ê}¼ÙùRÒðv6ÞõÛ ÈgLŸÙò~Í8°r+†Uåùˆõøªå;KjÛï­’¢ö�X¶Þ`»µ±6Ø\^ €é/š’.ì‰ XzÌ/d†…À˜eÎá¸éäž“¹Ô9cpXèÆ xÃ!:�0” |Žòú%à_“8ë–­ †éêÆ™…#w»¡Ã˜·G‘Ÿ3aâï”Z³*wà*‡uö]ÜVŸø««±ôc&Š’Fó�£O(©Ò ª˜Kc;fê­šT××zŠË­ÒåŒU�)nßob>ªÞ@¤ÊÕó«Ýïü=Éê©Î;…Çýo­ÈÖ`SvãnÕ?é5ùû¸ÊÈÚʤÛËÀÃûª%?ã|äSOûWß÷pm1 ­æ¿!ݯ󯺪 ´–0Û~j­ýqÿÿÇ^Å ‹ì¯`{Îçgxu ì+\w0ĸóçòU¥‘1¶Ù¬‚èÀåV—ÜfÝááãè¨æ‘¥e«=ÀÍ€²}€^V—¾©G¯v`ª~>‚tÞ?€²“ÙVùe…=Ï튣™_Z²ê“�̾?€®ÛùÝ‘ª#ü­v\'ÖÁêíÓãú[Û)Z3‚­A17¶¼‡Ì½ �ÐÔ^â‡3Á,óÆKÕx‡Jòq©Ä±Í/õh©³+_3û›ÛÏMKIòü¡–KaqF§f¾ñ|òzUO¶&FÎøå�c<pIAOgm<ÿð@Ôȇζ˜ta\O›nÅÜÃþ�¯Ÿ­Ýu)¬ÉhÏSýœg ³~v´¦ï7_É6eø]85¼×÷å¶û¬áýœ÷·–×Ç%YtÛµrU#÷£÷—£Î Šëo¯£$Ô={üž¯3 ïcÍ÷ã¸ÉïI¹·[có­ñ~w>Ÿõ{  êåb¿>‰KûüÔÚ’||‡@ö±59¾Šç©¹!à ¥_á÷ÜÜZôÐŽ÷í£hÏÑbÁÚ_ïð¿ˆ~í]ÏSÓÍŽ›"F˜úNÆÏɸ>Û?vgÓŽ#ò^^­Ì›2~UΤª9H¶îh\—ÝÊÐÕf™xÚQ\s {i®ø< ôÄß7ÅQçŠåW¦Žcã*Æûhg \åý°í­¥3&g²y@«Ñ|ë’€«’vêúXnžN—¼ÜH;…ùTË©ìä[èôµvÃý¹$Ý)L·þ\ì%&Ä~ÑHæû3IRͬÍ$c›HŸÕ ­öæÒžû�Ðjy«ïY]*WåÓ § ðúUœWµRþàõ­5tQÆØBùèhCì;°ôG«šb–Í’Šã÷·Çö (ë†�Ø×@†k›q Î2ɘ”âܰlñaåH´¦´ºŸ5‘Í | ›K-®R‡y¹²òV™V:¢>ë`²ýÏaömÒ¼­EréûŠ@–ÏÞoæ ê×Zu¢¨Óoi±ßJ_»úÉ¥›óQUd0&Â|~w°ÎŒÖpm›ÜѼڎٚM­ERwÜ”ÔÏ,I4§c��ìG‡N$ 8;¼””ÜÌìaíÑ×ÀêvtùxÆRÁ=ì,\Yé==ƈo~_²�ÕÏåýbÌœó¦{¼| 8ÃçÇ2°óin/aûEkb±|[ãè(Ò*v½LR ¯WI7ï·÷ûŸïIÿóÉ¥WV“šµùù§÷z0¹:PÕ4\“L­Ùõ&öÿ(«”°þÓ¦ëŽpûÛçqÇ®¿­_ÊVõ¹Dc–_Àãé«Ôl<º}W›`ÿ¬Ûácždõ}™¥9�Á6º_GÛË|aŒ0µ¶Óüüq&7/W–^ßV|-PlÛÚÙ–T˜ÄUãéo5»BºÁë̯ã=Ýhúãxý©½p°túëxFšØñŸï©@ª¼]íý»’ñämÿÉ´ãõ>¾»6µo<Ï­«û¹*#ãG™-ñx:.æãÙ«ótpÔ$ÃTû(‡z¶†Ú¸þ�™¯š‰aóñ ¤X21DÏ‹éãï¾ÂâÀáŒÉR½oÕïú:c¯šO0êçŸévøñrjÀ¨ÊDàÄ–òúf€×Ú}QÌÏLÌÚe/ƒiSÐÛVà•?Wšy™]WÕ³çÏòõÀŠÚyÀy•Ϧ[3½6¢jŸ¬>«þy*ØS,–ªL­`?°Í�À©;�� �IDATaâ7øÍ®OÓÝ�±°ô»;úEìWö™ž¯ì\ý {S¬[¿=¶íïo ±ˆ×Ó‹Æ[ä‹#ñc ¦1‘ôçñHµçš8Ú •<·ÝuÇÊG—?³ê€£Öñ)i-%·VŸí÷½IÁ?Øc-«ŸbT&.!Iå§Ÿ¸BÉCï¸ekÓœÝñO¢Üè8öÀ˜rÌ*¦—Ë$b2 F›r¨µÅc¦±þ*ÎSŽ­ùxƒm±ÆÄãWE{`Ðöƒœ§ÖᎭþ«€/¼ÞÙ¤ckT±öfõžóŸ¢ìþúÅÓ•´Uƒtø‹€¦gTÅŽÅpÅúfŒ1.õ7ß÷ˆÉP•ÞÉ™UöÞÏ‘HBókm!PƘX£ßû$Êe 4˜¼¹Ðe’Eíó&Ò=ÃѾ×.í,údn7³Ý ¥¬p|6®ƒ¶A¥ò[gre¶­Ë­ú/()óÕògÀ¹ªouœ—35>óýg,¬¿ûg ,ðôº?¯Se@ãÚ£5€‰IRGL°è>£”òü«�ñù½Ç€h1ÿ*†šèf ëzg|Í�Xk ‹jL�.zý6¤©­Í<sœ1·³ñ@dœáf¯shI7�„àºÇ[UÃqÒÑ'³@(eµôu!ïi<ó«azöV[]ƒ ÓáöUŽlº)�¨ ¤(‡,ªVý(UVͧ*•é t™)æ^o‡¬žM¤ÏòiKÇÑ<ಕ¡‡�Mÿ­O½k�ZõþûzÔdùu«@WÆØáŒ8ÅôóíVeÏsÎ<ÚÛ/gýO̽&ï}•Q¦Ç«Y¿T $Ș«íÄ·«Ì¬C²ÝM÷û1Ð[mçä{AÖCƔ̩elÚÿ+Û?SßÄ/–SÙ¯+é3€¯ÛOï¶ßŒ°þÛZ{¿K¾ÿÙ†Œ-eì<µæØÏîìŒÍ¿³Äb· ǤWž|"ƒv:Å̲Ò\«ZØÛ†1€£�¼‹ø@åš}–­9–_'¼Û(ÈYþÕò©ú¬3æªÔöjDxù‚ÌÆÊZ s: (~´ñµ½F«X ëL…ápµ 3Ï@뿞‰Æ�·Áˆðùp©E¼¾g|¼™_ ¬¡ã;ÚÍOGd«ˆj&EIÇ5‘ot<zÎæîì9dŒJ’Ž—ó ÀÝYŒ (Téð—•· Œ"@–å›™bbUîWUš-“–cõŽÚÏXnåðÍÚ=ìÊÆË9Ö䊯ï¢=mÿ1÷§·ßÑ¿±þó,Ö€<Aþlz¼µý²öbûs€”§”D±nÐÎ"ÿ½R*Ï15>Ù.½½ðáãu~6îÚ_~õqÐV ð¹–=ou%”ªÍŒK¿±5{9#˜R(Õܯ‡åÅzÜÞo~*ßµ1˜"FR/§e )&‘·(À ·‡”ÒíŽ @ççû'(–Þî ¯W|!PÖ™`/0.˜Ò)In¼O8D�‘mÏõÉ€DUß[;¢”›žU¿WQ: ˜ÐýZ­­7ÛÀ/ð_uþ_µ|M^o(¬¯•´ 0ÖÊ—Ižùü TýT>µfPlZŠ“•ëÀÜV«UiÃQš´Ÿ—¼[}?×€™Cê˜Çrl°=ÖêuM¯WdVÛ3cši&]6žW£ûá}»eícëé«×d?³¨ëmž¾ €çï½²c;gˆõëÚñƸ_¸VQJJQ¥[’*D`l°c¬EÛ$Uð{¬!ö~ŠÞ`ô{k­½üòLL1+YøG D1FÖ_m�c_“TÄ߯&_/±ø®;˜e«‰qd^üë%¦ª¶#Ÿ(2’Øù»ˆ„¿òÔ [ŠÃš•¯.ѳµƒåÝŒ9•[Õ#ÓJ¯—o­^Š9¸ ÜeÏmÆŒ¼‰?ZÕAÌ&ºž·ÚYH‚aÇøb×÷@–’RŒ7/ 9Ž£t™uˆ+IGßN¬žQúxB¯¡–;„øu”„œŠü#ƒ«’tý<æHª�¼‘tÞœ¯úþÌ×AIJ%!t!é^›¯¿r©vÌ"Š9­}¥î§êüõÞÄ/+GV¯¨ýæò\‚têzä“Ûwù>ð5»°¿@æé�¤*�÷œ?J¶i»›ÿº`@}ÿQ‚–}­öJFõª0œñýÁô¶Dµ !~W‰á’Näž3ÍÆWj¢×¸Rí¤,žàëþµöD(à®ÂhŽM1[qÜ\SR`ó‰c8ŽW ;U¾ 骢JZ°™ý¸öæ úc_þ�ë6¾‹~<ª$Ÿm9êåËÕ"&ùÉ|—._”ÌÇM­q‡ û^îÀ×áÁ»Ü÷k€Ùëæ3”>T@©×»ÿN+æü4èíy+ÝYÞïÌø÷ÛÞ¿.q8ÖRãå]e° Uç¿£~Õ÷vŸes•’F{Ÿ×Owãý”gZÅç0æ ¥ýz»)¦F ÷g€Äuq¿o—m¦™ ¼þÚƒ'.ï5I_ 2F^]²/>O1m²çèy�DQ…@Žf„©öëùà{Ç6% YeàTâuÀ"¶ì9½6(f�2OW•X­ÛZ€„®G¯çV©Fu]þüÔ-kÿµ�¼ý¶ª¬V«·^ûð[‹ÍïL2Â( Ïk �Õ-æúZaý éW× í!™øòKûý\áÚa7¦XÎþx0Çnö{ûb˜dÝÔÚc&_ÇSöó#ý16Ÿ‡kŠYæÚ�Ì”EñÕˆ¤,²=—<ûÙ@׌ð³!Œ’=\Š!LžUnÍhã×Ë€FïpÁúU^Ê>v¤ÒmŸ8ðÈu-)¨þ~à󬤌NÎa–$Qz¶?vX£$"îÿ.ò·LˆÙ!l2k'˜õÖµÒfœ]úOp¾í%Ô¸!À–Û›8mv(匫ºU�/ÖÏ#CJ=jÿŠTåêóŠ€QÆÐ@àiE ]_IªvP 8V¯EÀ´Ê«¶ëzúÁÄlæ·žO¶v¾pÛâ'‘þ,Òò|7ŽdHëdõEÉYkóþ‘†Œ™œ3ÙeõqÊ)L¯‘{žÕ‰ÜjÀJv~®d €;¥”€çÙ/åÖµ¿²ö¨Z5_µ–[ýºÛ$Èëõ©1pý}ȬârGŒg8µ³8@å¯{`ˆoÇäybåÍB:@‚ó7Ûÿ à¦[ȈŸÚ~­¶‘ïªÍý::Žc%¯ðÕš]Ìæ{q×yõ@×ËÜϾÂþæ·ß½d´_Óޏvìú8Áæïás;î×ï¼!‘ØMÍ÷c«D¢bËsx×äwµ'¾ˆóêÊ(¼ÞUÓkÔÔ€ŽêšWŠá¤ËЊ”*C-[ƒÊç—Cè¯21ªßUÇz,q‰¦™Uɾ*°©€¡~Ý*SqëÚMü~e’WÙþãÏÇWÑŽx}?ÎôüñþÄï}ÎSïùª¤§Ê˃ù+ÛvݽùŠßêÚWÛ-S¸ªne´éþ¯zÝ*P÷Ï!Ùü}Ö÷§Jf»‰5½ÔÚ^Àú•å‹L°@ÚФë¦Ê©Ê¥êÛ@ðåû¿ÿÿêÿù_Þß[kXzùå^À?›œn6˜dŸa¿bf©5¼*é=3¬Û×�ööóô­µÖþ‹ÿá?û¿~ú_[nÅÀÊp0‚“IŒ}”ƒ©R^Åø9ÊŽ¥*%ð ¶²ú}®Ü”­Õcëó§WûŸgu¿â®Eçj±#%93fMU Ïÿ‘f¯oÍúéòRdsúq>—dôOŸ’$Séíy ÒkûNëË�ÆU©´|ÔýE)ºZý?¦<Ìq¶²fÜœ~où¶åü-åoâ¼½kƒp@jë}®¾/hšßCž¿}Ÿ*{³D¢ê7¼å ÓZ{|ŒeQ—ò8¤ç£˜?hU c›äaõ»Ö’t:½bjã÷º:~YLôxñ¹Jë–½I«å<µÖÚÿøßÿOoW29üoÿ»ÿæ?9$ò ¥r²ç%cNßÎ{n€]4Uß5ÀB߇(¿Lù�ÏgV™o©~£z ÉÆ“ÖTþÕñÏlש$–Ù…€ÖÑ­%ÖÌþËÊ÷ù)U¾ºásn˜Ï~~};r†PEb©*q¹b—Å~¶šµ½RR¶•V¬.!¡ëÁ¥…ûÛ¶�}¾r°f�gÆdéQŠÌ_g¯Dsæ/©:êm}¶?‡«þ‹ÚyZÒmkûì3½FVvjãºzþ«V˧ʨÃr¯–ÃKÝî-×Öòme=«_ŠçÏÚèöò´0Ýö÷âcl”Gõ'«íKËû¿ÿ›ÿó?ýÿçR‰pM1c Ê$ §ô Àz–)©ÇÒyÿæ¿üÏÿëŸþ}gˆ{Ÿ×Úš€°—_¦m"™øþç$­ÈÓu†Ør ²H‚q–PœÇy³@ØH‡¿Ý∌UéÄfÏ–±Ž(>ÓÈùg«‘i'zžv<}lµ=‚º¦›kØV¥tT9ìþ½ mÕr«ÈhÎ,¬JÌ‘øƤo¢ó+öl ™9ÌÏÉu:3ÌK‘ÙóO`öÚšl}¼þ©ay¼cŸK>ªò|˜„£?Ží•;â{y¶2Í2† uðTvÛ-v¸eíQ—ÆÜ DÍç_$“I•+;®¯Ku~wÇ·®ÑÁ¥F¿ÃsÏ¥XÇï'“ÏÄüüuoïó'ê(×ê²ïí§Çuçß–H¾æí^Â>Òô8!þ¾(Éç<ÀåÙÒ$ÏÂÏ$\õx þîæŽæmÌ!,?æW•–~¾)[ßFÅ[_ üùhE‡lÍ ŠDì\~f[æ+Q€2—»´“:ŒÆ™6}Ì$b’ÉJ2¸j¸¶×ü{¼×‡­M63ÅØ8ûûjÀ¿I ¿<?¼<FÌH¾Âþ̰7Á[W÷v±@XŸÿ*fßck«©µ`"&ÂÊ}¬¾§9oŠ¥¥”Ã^1p{]ÑöH«Ò‡Û%l{¹-Àƒõÿ¨5pr†U\~-}Uep¬J½eÀàj@r±áÓs¦Žg­–c+ÆË».½¦êWuð¯=Gu`‚gâ{6ò¯I&gŒD¿ÿY€Ó“H¿ ¸jIÁjù¶µ‹Î­ÞŠy”•Ç?b…*3V×GËK?ØåæŸã¸¿¿¦ýiíºÃ²5·hº`­.•/2Ųôj[­YF`“¤bv^k ±sË�e7ûý±ÿËXsìýÏ ðêéð…¿ª<_Äv ¨}MÓs)ƒsrÜJ| ) "š¸+­r~#vc 韌ùrÄåÊ%‡ª™µŽL­¡‡õè¨Q‘Õ-ÜŸhбç—1¶;ÊÔñj„øê‡™?7þ½Ò@Ùm;–¨êk ¨ûÈÚ]EìV'Þ«k©VɤQ‚qÈÎÍK''möI�u(Á6ŽóòzÀãÆDÁrzæ•lSŒ ¨Äk }O5%…7>]s�I­\ªœÞ¸i�5kŒ¦*°áë­a5·OìøÒÒ}ªÜkŽÊ¬ÞU ÎÖw�ÆhºS6ÝÉTßé{ç¿f=¿ñ~Ø5¼Fú™Ù…ís–À$¯wÔ+ï XY«¯2^±Rjœ)pD&Mx‹f([mŸõïw6ΪZТ˜yöº{¥·›rü ÀäŽ8¿¸~«Õ?šè5è²_oÙ|ª|LŠ~¬m1$ìWåäÌ#ý¼ÍÒyúüœÑ:ók]Žñ=J=Úµ±´q)Ä.}xq‰|«cR??S›Êûk˜âš_È{Ÿû™h­·ñ\øç¥(•´uô^DÆî»r<nýÞTïck~MX=O¶ÊÕ@̪„œ–FÄ’Õf¤—ûö1Y3lÕ®¢Ý•Ôš·Z@L]Šl5†Ÿ_—îSåË�Ó¬|1ó,lø÷4_ƒh@•§ËêIŸY‰;ˆçÏIõ}\ ˜ö–IXnT×ü7WùüÕ�5_®µúgåëvHë[ül9·kí’׿@ç€Q ÀÕLIûÝÌË]­_µÜ«€l DùÀ‘ –bÄóÍ\Œb†)  % ¿Ï£FÖ 36寘i%ÉÃ&$«vÄPT³?fIÅIbñw¶Ùtß]>h(Õ8ïÿöãZdÝÓõýsz›ßYNd¸ãÛ;Ø£. Ô„k±À’ŒQƒåøQ@™Šüõ@’rD4šî²Ø)SÃúŠäÛÆzËæ,"C•§<f’1ÕvÑå¯Ú*É¥P¸ÊÚë=&žÊa§"®Ï›#ŠŸµ6ÖͪkøØ5ÊréC¿&Ù dÕyŽÈPávrkž!î“8o\l £WzœKT²öƵ–æ|[C)ÈUfMumºêÚUžÑçv&̤J=ÀúVJ߯[gvcí»‰¾‹ô°¥¨Š˜ˆVŠÐ2º|=>A¾¼ºÕãØj�í3aŸŠ$åQôçY3ÆQµï¤V<³ ¾~ÕöCÐT ‹¾® ̉'VÞ¶2æx Ïþvý(‹ë‡ Œ ÿ·¶ò?«¼>ßάbåÏ™i1#L)`dÏgÄT³ïï)ì?£z³ïðE<Qyq¾ÇÇc*`1^µãË¡à‘IBªrÔMn5<´hÙú;ùj~Uûãö…g퉥¬t;#s°ÿž\ûEóÙy5KNâyq„|dµñ>¾¿½>«¯ÜQ™1´móŒ÷î"ö×ÚCׄ1@Qu\zI«š]‡äúZ? x]eNÄ–­E–3Èl>9#¬‰ý\’­®<T58b`Ï¿7k€ªfÆl âëe÷+{³v?$å;ˆç¯º6—.ß* çMÞ;¿m™;õþs+ÀµjØÞ`ÍÛEÛ6@3¿ïÏijvÉò‹ûAµæ·¬ŸQé3ifõ‡:“”!š’0Å–€¨)ÿ*ж*½ˆ€-÷OHªÎ^~y�\ý·3ÅZû¿Vb±Êô²€Ö_°¿¯-†�€çG„b%20Z,ºµ\¡i¹Gk'èj±êU ÈõëómŒÌ>ʉ=:&ÐaQøÕ:ÒjÄuvÿW©ÇyMÖq×>´Yù·¶ËÇx…ãJ93¦Ù±øaËÛ'f¶V¨×€³x-"µçÏ­†RŠq>9 Ñ™5Ö>°¤�…OàŒK6v` ™qõ@ÉJÄ1 FíúíðA&Ug"3©MÛ�-6½Êßî?7ÅðAÀÎn#tí£ù˜ÿ'q¼=ògå<Ã}<À!J‡viÂfòÑkÜYûD÷Ïí>·ã °©òE׫ ß÷Iƒî3/ý„ŽdÞâZ0÷}ïéú¯êß3` ¿—Û"iµñ;T @ÙÈâ­*ÕS¤¶ùVÇ‹CýyÒ‡ˆË*cMcecœ†í]›ÀûqNÁ0ÏoªãDT(FWþü1¦xÊž§(°ÚOÞÎG‰CjÎþíÖ~£ü1Ô ¤óë0ýÎvh¸&˜º®1¶CÀ{ÑóÝ �SßϬˤ# È™h£Œ‘vuÛkÌb�|æß+e1P޽ºc7î±G?u ÏÞ*‰˜­qvH¾[×ôûÎn (ȤæºUÔª´Øª´›/¿’[•øSLÜß¶Šqcçksñ÷qUºÎ;¸ãëè5~8`~-ûz{dï¹’°«õ çïªä {Ÿ×íkûUó¯IÛi‹û‰êšë�_M:u”£Ê|Êú­ó!žoè>ˆßªáuüÚ‰¼‡$?ÕfvM¾úû¡ÞSÅd¥61¨~mm�dUæWK¤òAfצóŽSàí' u[XÛËH$"Œ3³þxH,~ ,–häåCÀë/²ëqû]¥|ó4[ ‘Žck6E•Œ_4\Û�#юɇôÙ�ÑÙM3¯p[Q³Ÿ¹åª¶Ö¯.Ťʟí_þª©Œ9·w¿¯÷ªãG™T¹£T1#Þ«IoŠY¤v¥ý÷®ñ´Í<À£€“Q[~¾eh) J tÆÍ,Q×®Œ @ÅJK~¢ù�gHØuàb.Wä¾cŒg("Îç3· {»ß`›µ32™¼4æwwíyß °4®cª3aNa»ZILÎD½¶] ëÀ&k¿(d�£•T ¶x³Ò†óyøÜÚúÖ¬`í ˆ‰¬"e¸õûÖ—~m%žÿ1ýþs¡ZÛiØÞ�™m㡌1“GúzøýÉ&bŠ–c©%Ï@Úg{׊Árki1»?^jãêgÕ/gø¡$h h =~©˜ȘY@K­•uN +)g&X£êñ›Ï£²y–§\gS/­0ú'û½ÐÏbªÍåž®^Ò›Db{ü¢„¢¯Qk•;ˆ�XAáä½2Åv¨ŠÆ@—ߎ•^ÎpüívçÕ¥ç*ãp@kû«Kz]Þo+Ǿ–@Œ÷«™"_>Õ¶µÃ|¹”gHŸºls4+IÃU&Y^o[ßUÇ­70Y`'c>’ïdu­/=˜½Wñ8ç–#3Å áíèψÓL”Õçou|«Ê±‘¶Wò2—¬¶Çs˜V‡äz0|C)—’Ì®¿·àÕéW¯¾U ûÿ*XÕC¯Êl_î¸Õí§ÚGmÛý‡ôù±ß?Ñ.Ó[ßZ+I þ*Îos>Ý:°5O€µjߊÛt 1Þ~j½½1©Þ¿6eTÅk¡DbÊþhíÎ$»1Å~¿a¿ß±ß ²fÖ$CóŒÝ”Äâl³”â—¦*Ýêk?àŒe’ ‘F¿ŸxíûpxGUÎdií#1ç¦wjí4ÅüYáÆ¬” ·«‘´y;ªû¡[kGUŸ ÅôÕ5ͲúoZ³u5¢µÉ‘¼ÿìºóÚe¬ÞÏšŸ+ͨóÏÖ:ÛW^.µxvkœë²5”Nðë %ó¾›þ›1ãf&Ñ ˜Ì�ÓIHžÓÈ2¹|y¢ß‘ä<£ë ÊÏ�7-)‰€Yƒv³Ò—#_žm'¾µ|š +•te̼âL1è²üž÷Ô­²v×HWæ«�Ípäu³Ûz-H4›Ÿg˜œÄoƒt«¶mb½º–¬j¿&ÒûüWY;eŒºø9Q’t¾žÏ¶Œ©…ßÝþËŸ«fz­Ž›½´g<~¯ër…ƒ8Ÿ’ŠTê0Pút]"Ï2μô`µÿ³ÇOtÿ±y€«m°; Àæ¼±\ÖðéŽò;ßÊ{÷ý…=¿q=Ôavž<¿³4â±a€Y3í?¡™ÍåDÀëÚš·¿ÁöªÙzúöi½«ýï·sªnÛÅôç£Ç=ë(?¯gîPU¶™pÛ{Ôk Cdr‡n¾ÆWæxÆëðós ©p~HÒeÀZUR/b2†/‡L¬C:·ø9Òõ_z}V§âöÓÏ_<C( ÔRïcÕªÀv•¡µ:OȘO  ß:¯YëWòþ‚ÿj¦–úe3õmÏeÞ’ãqûé~ƒ¿‡ÙnÊj~éCÚT÷·Ö4�6E ÀRR‹­5ϼBIḐ%R†­qæZ�´aúÒdƒ!Ö^~{ìÍVÕµÆHº÷?oŒ°—_,°51Äðøónö{z/âwºÞCR±2¤&.äÍ"áVì(~gc‰™cÞ[°Ä̦½‘_uóè·ß S¦nû€²½Vã¬2àªõˆÄZù”åŽTûûq@ëê@bÊT„¾ªüþ)æØª4’zî·¬uöQ¶vý ÀZ;omúk\k ¥ùæý'ÁkŽ5IŒ™¤$ø|~7;0¦ßv˼jî¼OéyØN´÷÷“¶¢òå½gìáy,?lßLBêÒWí£ß¯èyÈÖ4[†9‚•ä°g67Hw¢Ç}zþ½õÌ0LWeîﳌ±­úÕKr<üȾ·ÕÈBl¾]RV¥“÷Ï×¾sØ>Ççÿh«3ãù{=ÿl¾QY«ª5 „ãšWQ`^ xùž6s9éUôT:oëÀ ¶ç�êN 'dö®-Û%gkƒuÃ5½pͰz»tÉÃÎ{ÒˆÙg¼}Oð×÷L@ <rÓåñÏeØý³ÄäµKçgÌ6Üï‚¶}òµÀ3‡à³Mõà¼G¯Îóê¶IŸ*Ïj/½VÌ*£GÕso½Ÿ nýn* æL÷W×ÜQ†@`ù«k(i`¯¿tdyo ˆÖ×râL©+\߯<=šfبçÏËL *ÝÞÀjž¯ž|ûÕ€ëì=óÛªkŒ#ÔÖßU o¯<¿ŒRÞzý²ëZ�<ë×¾ó¸ø.Hvû¶¸¿µVÔšÂÂë!�71оUÒ·„¡ö“¾ÔÚ\Lšð¯æ§ŒI6WÄ3À<àõyl÷5ÊŒ4cÓùÓýsy{=0²1 â|Ö‘y‰†h ÒŠÝPš­—+’²àå©(Û$s~<ƒÌ–ÃKNØzz áDÓmf€V¶y–oæ€Ó€`6Ѫֳæ8ÔÏ/Þ¯Z{TÛ+cì¯_Ü~XOÿ<œÃãšDZ¾ÈÐht;³íÒNÞÅD{F>ûÝŸk�ܹ�äÍ̳ñV"sì{âPSR”ˆ; k’NŽqV·=@çJ|ÓAKÒÿ3ã(þšKžáw˜ùž¡Šéì÷!Nôwîœüf×ù±€ÅÖïðÖü½eíÕŠÛx=È”øö*“yÝç”ùñÃa|iSïݾ|VÞ 0õr¼‰m&õ•kˆ²r°~Ä–…L16^Dæ’Êë@ÇÛt¬gÂŽÍJ;và«ïgŠ�U ¿&Òw¦Rk7�Ì–Û2Àúb>Ÿ‹�ªÆ0ÉÞ¡½_Ž~ ƒL1Áøýí;J§¤"œ¿tÎܰhûU&a¯±V7ä"Ñ[Õ!3zòµª¢¾±äæG153 ëµ)B~¹<Ú“ãWý�� �IDATö^'sŒfÌ8nšÁV+O©5yFù�ÆÏ÷嬖w/“*kßU‡üG[Ì ÉêÕM­å”¯Ñ”[};ÏçÌ>ûéókùs˜ÙÚýÎÛO1!×¾ëÀ böUì³vá@æv)Ù*ƒÊÏûÑjýªékó¶lÁ¼?¬hâ¸í÷ÿ˜TUIÃÎÀÊ$éñÂyS ¥³zQókˆ!3¬5 lýu—Rì�ÒÏÓ/hŠ©ÕÄþÏàúR¦X—VüLóÿ#•plô¸–fcÛ6ÝÉOñDÈ Ô"¿³TD·ˆ!¦&5ÃòdŒ–5ÇųLê¼ ˆéX3Ý~V¤Ù*°“->éòí­KÙÀtÕAgó_]{¥Ó??bQÕ;û0V¥,mú£üà)fšbtØû§§·È€kô<ÏÐÔö,@!.>Ê~ b׸òkµ)[“`B‰En[¦wñ}ù¾˜~¿eŽÇÌQY±gE<«÷×òôýá Ò{)5;~ˆ4 HÃr¨5G}?±u‚±ÍÁðQ@ÎWõ—kù×#þפ7<@Äȸ¤L·J²%/ðÝÌîÏ+·2>¾©·w&…]ÿ>0à«KÍ1æJ­®;#…  f ¼¨ü:P`\Ï^—+fŒ~R•›Ïs¢ëó|¸„áê»åxxüÞì ûgæ—½î詤i¹ß#¬d"®½ÕÛ™µËXsͶc¥<ªy»â}æãîÙ1¯–›z[³�.œEË^è@«9¦‡UC515î_]={ÍÐQ=�¿3ìç¥zͦžu~¯¬U[»ï×År)»–Ç<_ï Íø �ãbëL¶j»¬2ŠªÌ‘v¯Ÿzïªå©ãͧ[m~?¯ò9ÌÚ/n7L-æsçWÇͱ)`PåSíò€„g?÷ªŠIZw­šÈÄ|ÎÅ|²úªþˆ3}}:pWšaÙèïz=T;)éÅM”Ä ’¤éz>J2± ÃnÀÊ�²ç›rTÏG ËñSkï_-vßþù¾¶Ø¼¿MÛõt÷}LZ+)n6Ò‰Ýþx¬I6­U6Ùïášb­å‹ÊÏ^=ÀňFÝѰ‰–'~L;ÝægÓ©úT†¯J2¢MåÖåÜñ®ãÍþ9‘àšÁ¤êiÛá²Ü!­Õs«ÃNµ¯¿/µÈòºDuÀÏ÷_’vª.âþQá 8Ò4¶Jé‰7ÿ€£”¨f*z‡zÿµýg ay³öZgöÕ€ vþÒ~”U¢UÿLrpo¹Ÿe+ÏÍVi±<ÿØAΘUóÚ*Êpm®ù=}3×E à,öÇí’I%¯K_<‡±›RYÀɺñþr5²ÓïÏ¡q?«% íyëÎôõóåä€bÔ!°»õ><×2fÚ±8Îa-æ¾ã&~GyÎáö<Þ´Œ/~^t±ú¬ì¿å2ó.h¼ùû¥Ö†Ž�¼y;º×;5’GtyGÚñ~½ Ô¥M9è2’ˆ…ñÂ;»?U ZûmkàkWïØôýè<ž½>˜cã¸ýMÍoñx…iÉ÷W™@öW—´V£Ëý÷(Ͽн[ ­ƒ¸«�A&-¦¯»M2oÿw§Ê ÇzfíPs@ïeléµÇ2¥�4uß²váóîCr½CZ®Øñ^m§õµ¾jçi`±êgˆÛïYã©  Vå¾>iÞ† ¨Ë˜uÛ¤ìêéøýÈ®«Ÿ‹5IÆ<ÿØï‡í®˜z{-ï'xâAÐnÛû» ­õŸ>}¿®bâ5ºß›¾Ð”¤a_;¬œ-l·ä¸a¤-H?"�¦ÊÛZkí§)é{ùí ½üf€,Ç»3˺Ô"ƾLÇ# Öüš€±ß#`íå—‰!¦òUåXqÀe޶F*ö_ÉX—z‰pÏ€<VaYÉ×É:¬ƒÒ‘ðñövãåòF»}q€€r8b»ý˜ˆe´U IIÕy-IßÄþøƒš3)jõl"]&ñ˜¯áVÝ_“&­8¦xû Ãôæëï»r€áùkÚè‹,uÉ1Ÿ>r´=ÿóV€¨"Í»Ç~D¾Û™Ãçðüœqë÷èÀÓ©üçtŒ‰àßÛñ™¯—KÊf̘Ú@_Ÿ÷,[úU{ÆNù8gµ?©Ö£>þ©1�²öPªþ„aýúuU@Ep„ã.ìn <Ò¶ pT㦠¹ßqÿy~¼ÿQÿŸIqgã—:°ó™“,ßÌL=6d~YfVƒt³)�ª‰tó6J@¢ôßö+.Ök¥\ó|í:ý¶i»ÛphïÛq½„a‰³µÂ¦öéL¯.‰ø8¡ ߯þ\NŽZªï<oWý^ßÚõVͲ"Õ|+ÆÒeÌÑíÌ�n¹C1›!] õGs‡y1Tòz* Iî˜ÍO™ƒÓ¯™Ä¥ÂrÛæ7ÈÒõµ´xý××D[­Ç^@8ÌT½øñºD 2Kð|ÅÈ©æå{J‚V ˆŽ-gèmâ8s§ ¨êúoc&éòo•ÞTïwæS¶u~Óîí¥Ú138fõÎú‰8_€­æßóÙxe–ß,Úú$ý 2ºX"Œ+ƶÄðZ0“/ÿô2ÑZ]²µf�±fbM ±ÖZûë=$'ÆØ,­8ïoSúž?[«Ì\¿)fÙsº”½ÿyc€õ5ÉYÖÊ䟙ð²HKÆì²¿Þñ­�&œh¨Å‡3iÅê¢Äqú àkb;“èá@ÓHÿÏŠôÍÊ‹ébÇNùü³ë“9†½ãR«‰ÌxJŽÇåJÄtt¼: Ü.õX›�<ßâü/é@Ø:æ5#4—zºå3Ž¿šíxÀ¡#p«Lûˤæža—v¦ ª>{™qÿZl¯Ô)šèí~ÿŸ’tö¹­JÌer¤ç÷…˵úçéÔû»Úß>×¶Þÿ*£=[éD}ïÖ€5@Ë—{-`$t«V„z®ÕNï(¿o¯ã“¾“y?eµp[÷¸íëQ•�Þ"Žrì¾W֛ˉçq L}Y¾Qù*ÛØN}<a¿»gs¼Ÿç¯›KTV’óÈöH’_k³ƒæâ¶‘†÷kú}¯Œ#:# ¥ÓK­‘m•NÆxpžb {WÖæ™{·vCI6tհʼռZë·ØË¤½r©ÄÓëòØ ÏÞn¨ÚÏc>µyŒ?ŽùÙ㊙¦�»uGõj Ò>«vÕòfÌ¬×æ’wY{´{>UDOßD:e«éö*ðàqžn¿5À�Ë÷apÜöœâ}̤ëÒ«Y½1ÿZ�´ú­3êx½òrmÿ)Æm,ñw(Ï£šI_]kN™ÊÖ�ÐërV“`¬2Ÿ5SQ1)ѵ¶ˆ¢º3«ÊØÊÖSéV™d ÈõÇ(ÀwÄ0B@j–LÄ5ÅúñŸ;c ˜cs>P#×ËŒ¬öò‹[ƒì÷;0öÇ(ûýq¤ks½˜#¸ê€dé0ÒÑ3Xp ‚ F”‹­Ž$[˜´ –O¥oâ<mºCák¥¡ãÁÖC1S~”4Î*`ä(UÕ¡ÙDºZ=ªõÑÇc&.×j„ÓÚ‡SKùÕꟙr´fÝ_£e5â´AúÚÀÔkÍQëT_þ8€`!u„ç³;h²ˆþuƬº~ÿýJÜÖ,¾î*£f¯iƨJ3›°½" éÕ¤S�íÖz¯Môü}Œû#ü.èväŽißÂtÏú^<Û²û_e°¬\* !ÿ9Ôà¯23 Û!cÎ=ß‘Éëí©ûY�ÖÈϪGõ¹òÛý{•Í´cw‹"¸±ç…1—СŸ[%ù‡€×kóßS–ß\.8™R̘¯?Ìx{›fEk±ö™íJÒÍå9<¤ó™Ug‚)†÷”ÿ{±]{º—c®ÅÅL¨ó÷ž~Dã€m?Þ¡tkç¸ÿŽNfzÞÿìcþ*[¾ÐâN÷‡Ïýr(æžvXgód)Ç*no²ôèÀU "Ußµëk‡y<_ö€] £ŽWÆ÷ïgýyÂôÙøŽÏr‡¶l•)fNlš¡–õGPª———"¨þ7€¾Êçºv}Õh©2p«LQõ{*¥?¸þ¬j[Ÿ«p:$ýÇêšhš™Å`EF_}-È VÏM˜âËUe’­Ýçü»•Í_QBP1¼~…ßžžÖC3瑵ÈB�LoU ÅIêQH&þ‡¦×ø2@ÕèzH)viÅÎ(»'›/ ¨5Ë(›-clYéÃ?Zk‹™ýŸ[{ù¥¡ôâ&Ùtþ´ÆÎè¸Ô„‹h²;«Jþ GßpܾM噀Ñ%“T©›dƒºÙ §vPYÆœf¸U;¾µŒ±à–ý¸MŽÞõÈðmõ_]sEoŸÅ62+¶F0­…õ5:£ÏÖO9lÕD¿ÊÀ[=þ,Àfµ=òôµ‰¥– ÍË3VcÆ[ëñ¶Òz>ÓHEòÇŒEõ|i�ѶW�(&ƒb4eïûѽ×Û$†ƒ4¾óyl O-™ÆíèÚ ïkƤÂvZ›`æ€Uuÿs"ϳó¢qKô‹VjZ+‡ïg÷™ƒ(þ^dÌåêwDÕÛçkíy€;¯\Ä÷ù"ûØÅËñ15Åìôéø÷ˆõÿ|¼Œš|\–1Pæqð DDгqIvdöŒvé@Ÿ§#�x’UUUú°—Ë2Žpœ|¦@2ÀýwG—we °!}xy¬Eeפòk€ÍÒ~¬%ßîùeóPÒÎ]ú× ›ö{�0fd�P<S�­‚²÷lÛÚp€Ìûºc;¶üû’›¶õgU‰;í€ç_‚‹;Þ™_ö×§–YÇ%J#j†bu‹]>¿~ݽþ*]ÏŸ[&™·u©­k~©ö©*·dŽÜg­ ”åŸßOt¼[Ë×à±Ïi¶ºNÎÄÂýµçÖ÷µþ/Œª¥™e ¬<ߌaÄÏWíqÏï*ƒ-·ø¹ñí´Úß( mÍ®òýæõ®ûê}ãåÌÞcÍÔÍ€½n«3ñ{£ú ªöRï?g¼¯[?¯ÊÀúïkyµ&&ÅË]=óÛMI> N]Ëo®ûSC“�H(¶ Ðú<ïÀ“Fìkõ5Ê9ÞàüFŽ#pfËû{k�|YFÚ�¢P„/š\P´¦¤Lzú1¡°/Ь½Ï#ûrJuÇmÌjk»T?|z�kÖûô³U¾mëL,å°ý‡Òj{dkU`¾è€Þ¿W–N94W'>¼>™ã3[³EåWeд$ÝÇYuÀŠéWÚ,ÂJ1b”! ¤�Z ð( %ºÿœ¡Ë¥À´´ªMwÏ>×Êa€ô‘|Wæü”´Q+öŸÞ±¯Ÿ€¡€>¬/¿®¶Œ¡ÂûÙKúÜoÞÿuXÖnÕ€˜ÕÀ ]žLbµ™ãë ¯VL·uâÛë�;og3ˆóñ˜z^kí¥�¯c’Ï–¼Ö¦w°¼\Q·—·î1¶¦V 4U¿Ó§!uã§ùûŤl%0«ŸÎ%üügU«2•úZ`7F’ªÇÅm¿Ý[I)²78+OÖžÓùïóøA­ÑÅç—vÜ4Çï™]¬—›;À8£c[;æ·Šêq8*PàöÇû¬]âÛãÇÖ%íïÑïõ}V9ûýˆ~UŸ,¿L‚Œç·7¿¸ )f“’«–S]?c²`¹Ôyê;W•r«1õê¶ú^Å×ÏŸ^ÿ«t\«ëÄãÚ8ýØ€o a}žÃ¨Ì™š1°Q,ª~^ïíÀt7>OÄ@€ÈÎü€6]¾F[VNž/î_º½”q\. 8Uß§ X‹%I³vT̵&ökŸoæÏy­ú #kwQ� -\£L1Ôp­0bÈL[Z+L1Ò¼dâ¿kˆúÒn@Ù-«¯|¯Î ëk‰a�Æ€­Î sçfËÛ×û7kŒ}i6²'TPqù³›`¬FHr‰Â É4û}¹ôu¢‰z ž•³é¹ö‹"i3 ã41›ÛÃ0œáñ£LF\ K1BÆñŽƒ©ÊˆªKWÙýþ~WMhU‡`Ö¾1p¦ë·OfŠI´òþFé3ÓIÕ Ú³ú[ïk–®:qŒ”Š1áï^§Æœ9 —êãçWËë˱÷þ#P¹ 8a~ÙsÙDºµHÅu¦ò¶~{ûûϪ€Yµ_«2Ê4 ½ö<Õm«EÜ.ªþÏ·Õ÷l �FFæQžÿcê­úËj@ æ3KÜÎûu Œ~¾Øx›½_•yZäkÀU+¸61—öÌΪg{¿ ‹ A¾¶]õsùœû=Ókìç6Jh¯3€°^¢L¢² }ØÍ0²5Ĭé~ƒÝ'T*A¦˜zÎÙó>×ïš|w‡„‘/v‰ÄYúme °¹œÑ~µ6±?ÿ$~·ˆµG=c«­™+ÔÚekù‘qRw\¢­2M”U¯m20âáUÇr.Í?oW‘® #+g¾( R1°j€ž–Œ­ÎÀQÆ,jç,ßúšYX¯Ø´C>Û¿ÊL‰çEWù<Øôã§úœªöÏÌì:«LÕÕù±ÊG_ìn»:OŽÛK¥¯öß*0àY S €×ü-M¦¯^¿êŸª1M5›•+” |¶MÀÖ·y›”'´`1̧qášeÊn€X¼>7Ë›íßMÿSiûtb—RìÀÖ,©h�4�ÖPr‘I*Î1ÈnöGÄ${0ÈÆ¢¸gø½Ù¼Ô<‘DÆ×lUÆËgŽÄŒY¾\žáÆ5ñsà€]7c¾Tý—†Ì»mU¶–@T^j‡ô³-¶ŽÉÀDKMbz¬×s#W$Açß ÈñÌ•8?Á¬@ÍÇóY—žXk_ €®µ§² 8ÛúÞæï­ÀÅVÛÇü««û³rnzÔu¹#W;ÀàPàÅ:€¿ÊXÙ 8­³ÏR÷Y4me¢ªü³tÕ~J—+£n•‰º tÆý1Z,æÒ£üxq¿ö<â8À3í!ÚËÉ'Š 0y¶­3ìùù (a鬭EÎ2†»Î c&Z³jÞo™P8`k<ùzŸè°í1üqžPY k¬!Šó«~|nïK¿e4é@EÅ\›m8 .ô>ÌÇçtÚ×ó9@ÖZ‰Cl‘çæ}´û˜ïñ�H@Ù_½}±ýìuϰ–gÜ~‘Íù{àà|-#%®Xõ–µÈ2h®l‘ý6±m-4¯Î�â®*Tl7¼ÝâÈxokûë‘ò5Ǭ¿^mœ§Ö¦É®¯­Æ¬XÍ€l >刭3w2†GèÙvÈ%âjóù\j-–ŒÌÞÚó®Ûq[ ×¸¿UÇÿÖç Ùø©ÝÓm ³@Šf~ýs›1KWû£˜é£Ÿëì}Û+•Weήÿµþ¨ ×™±Ù{[Ösàéùa9TùÖ€×ê¶’´\4dh‘ý*}IjQIf×i°¦Xk—©ò£Mk…-ÙO­5 <uàë?@Ê”u଩ߌ IE'½8ÙçvÂ>·Ö~¾¯U†Ò‹3p¦�/sÝ`»5æ´’)} =O¬û¯’æx¥Ûqd"N4.°ß\-pç'Bºã'®'9aÏ$«dÉ·Õçs„û ?ƒa¶•©´×T¹ù�Nd1å:Ó¸ÿh—r°T¥µ¤œÔ²àj„Ú^J|éù6ýj¤¼Êg«å�Þf8®RÏpº­rY¾Š •Õ3îªL·<UÞ½ŒÀj=¶åû£.« ¬êyÕzd 1ÕNõmÌo«äÊÚw,»^.™ÇÓo•ÆmÅýÚxáÌràÚÊá«1ªâ}¶Ú^™À�vV¥··lœž­V5¾6“—ÄöèçáZdÝT€SJ 1›×Ä�E—ª@‹â´"æS•–¬HÎÎÀÕ,~Ç®ðF\ðeìý2½YÓñ—{ý_î€éËÑgÚÝ�fxÿí<HÚõöŸï{Ÿfà‹õ{f›i\÷QŠÒ}9³­b™rÇØŸö?êkMe_˜¾˜•DÌBköŽoÔZ.ÊÑzXw¯®=¤Ú3º¸T•fz­]Û#wœVŸ§ªÃV:àòùóqXÎÔR@DÖ~{çUÕïx,‘¦$Úê’|ª¼óc+£¨—Ï–ß3ƒ²|yùД1´ª@ï?âùÔíiËí¥ y=ª~�~u^S Ô®Õ{?€¿p¨Úç9@ffU)Ük¹<ªÿ· :õÃ|®¢Ÿ\•ôÍ*ð¸z_Ìu‰Ôaßf$ §5·ÌñÖd~ô¸ºNK$§ó3†[Æ|û¥·’‰³4â,ˆ’Š­k5.¹ÈÒݪøõ±¶Xk­µ;6jóù?O€ša¢µ&¶¸|<®5>˜ï‰h# ý Qj­"Og©ÇÖì„™-=ìùÚcùâÅœ‘…>?%}®9Ðqm·Jùu„iìÝ*ý·ÕªŽI½ÆßVÒ?Z¢ðc#À÷2ªùûöÂçyD}d�¾s5ŸêZ>—¤Öåö<õ[•^ª^ïÿ?¶:0®žÿ¬r}4@ùÑ×yNþÕ5²ºUŸç*Skk9«�dý¾·gšµÈì>>½b@Y«ÞÏ–¤[=/ou½¸Þ^2°Úx@[Mq«ùÀ¾­Úé çñt8>έÖäk¶\ú}]í¯ÔDwBÍó‘yž2chóñªe̵9ÝÅ¥WJ ¸6Y6:¹ýб”I#¶6€¬.Å7$ù|I[‹  ™ýðzŸÛe*]ïì9FF`Ö>ØÎx^OÏz¾vJª2owkƒAdHï ®2Ñ*�4Î)&³^±HdM9¼rFS¦Ñr1G}ó\XƈÉ5Ï B‹Å×ò¸"“tãùãuÓ`¤Ë€¨ ¸È¶±\þÊÀÉ÷W™ÊV¥êðyÊ%³üñxÆ$ª~Çã|¶JËéú¨ûÔè¶2žr¼¯"±eH&î•ò[ÎU;n][L•+»U†]ýùQýRöœÕžïíÌÆ½ówì÷U?T tV�Ù6ÆÙòÏï;–[ºÕ@µ?´šXÓ‹0¼0]gz}cÇ ×YÐY†Ì·_Åùˆû©µö›”féÄþ‹’‰¸Ö2ÊfûÜÚXc òéöX[ìxýEÒ÷ý°e�œ:ÞM8ÔðsDĉ.2/­$)¼EÌñ<Ÿw‹À´åe/J•©…¯9u–Z±ÒMœÏë¥ÛOµW•ÁPÐðíÿ¨Èé¼< ÈéåâõÎÀ É©j{ŸU¥¾êÆï³0q~¹Õ‘UZ°ÊÊ»*U•9„W¥ßšH¿ˆþh`mþÛ£?ŠÑ”•óGK¦ýk»þêyÏ–Ð;ÊçA[)~}^I‡½äg|ýKò\ný.”„TK¾'ù{m¯ PÂÒÕ¿Ÿ ˜W¿Kj|W˜òzT$µ3éÀy;šòqÛ8o–ffK´–J52†¾šo(ÀIн‰ývmæ^>œWèyÊ+IÇì5ÙÏ%¦^Wȇ4}°^»ÿø8^˜ßuà«3Å #Œ·c·“B[0ÿìéy;ݼW­Ư³ûµíi»ÁÀó©ö¾lëô¸òÛ6½Œ0å0«2¿àÊJÎÓï/ôìãæ/™<ÐÁgäu  øËTÕ5UVë«Éx€±ÏÇU</«@b¬’ãº~¶üõvZep(‡²Dñy¨>?ü}¼nvÄÇ@Äv&^Û­Êü‰-_cn¯­€[3nªí’ïÏÈ3à‡,PD ¥@ 1ì—b;¤ýB­]ëkáí ŒPÌ´«h÷üúY ;^¿jªñýQ’´Pç¿K˜NU!Ãj¨Ôùß V¸ß'’‰™TcX"tV2Q­Ö²þ;§gÛTÊ0J4é Cì3l›ýwûKI5¶æÖ0›÷3cR 8P¾Ü'vs$Ù̼š¥ûq”$ĈÉl"צó0ÿ¢æ|°†bŽ`„ýúÈHŸ(¥¨&îª5Óà€C/G•Áò¯ÙR—¬‹†G1À÷–E¶¬ ”¶K)ÙtÞ¡øœvÊ×Hâíã'Ü«ÍjÄKÜ^º¼ŠùYd´$ýmb{õ=Ê®W•žÛ h|´eŽþ�ªŒÂ­ U¿êóTehm-O–OÖîù|h èÁïUÆ\]ë'V'9£Ø393 Û>ªYeêýèï´,ØòÛÜ«&¦zí̬<?¦þž©lÇ“yÿ¢³ÐÖÇL© "58ç=ãj«ch0½¬TûY�mc\3¨) Gö>dóXøyŽÞpþP•R¯´7–¯Â,Ât½&·ýØ¿½&èjæ¸/­i`‹2ÅÃzÄÌ<¿†´j×h^Vi~Nîw>ײ9�3ìиdãªcw~oÙZjªÒVc"x@hÕâÍÅms†˜ÊuݬZ9˜½ÃZ9öãþ8‹x¯Gê«tÛûa[yysf‘*o<oTÒA&U øÛÞ~Ù¸R1 ×®£Ñs’®Zî~¾rhWË»æøW@bÆtÜÅ€ôÖzŒüìonŠq“•Ï_õwáöZ�}õy¬Ÿ¯ê[e஽Ož™WŒìñõÀˆj½±¾¼üõñÿ¶ïBö]Ì®S•àÌ×Lãæ×skTúðÛ}¿Ù.X&MhŒ0½ ƒ¬Ÿ�,üUÀZ–¿*o¯·“LìL,8µ¦¥#ìsó�ˇ7ªöõÁ(3k’5 ¬ý…™ÜÓ?Ö{ÿÚ*V™@¡4b»oãD§æk‰áÀß¿H|Qd¼ªÙÏ —´ÃÛ|z‚rœd¹fõ}L‡*ãÌ—'‹È椗Ј‘6sE›d[2âg�� �IDATð>dûGù3él@ñ1‘çÏf–Ô™Mñ@Õr5àpû„}k„\–_u@37”Ã÷ûçn)·*™V]ËîG;Ö«�Pu;Ë·Î8äÛÙu«õ­æŸµ€‡ØRÏu<AXÿέJºTó©õž![{ïÕsT•tÍòmÉyP×¾[J¢«A»*ébýræò?ÛVûíҟl<=·Ëjyçm¦ åºÐ’×cÍÀ)æòtÀ -Åô©X Œx‰Ò®@aËqvóø§ûÍÕr«zt�ŒÍë ×ü:ÒóGýͦ’†“` /R_Ãcó͹=·Ù9œ'FÛkkÄëµæ¹ó¼Û”{û3 ̼ÙqzŸætZqMù"_;ê96êócFž3`yÛV�¯ÖÐ’3ºícÄgŽüçÕoŸã¶.5ÈßGuÿªí¤Óm[Hç[»Ÿ™ãø–3–¸Ìê—IÓ)àäY?´úñòéç)ˆx{xæ^`:%Ç9óq·¿õvÉ‹œÉœK+Ö˜^y9³À‚­ÏA/G5Ÿª¹z·ƒho~+€™•··ÏÿÇÞëJ’,Ù~KÉLð àÍ öýÁ*« @ñuõÝýD®ÀêV[¬0ò¨óDI”·»Jà«n… 0Ú ììp‡Œt‰ÌÞÜòúu·c瘙Gäíî!ׄLD„»‡»‡‡‡»;f(êýå¢Þ¯ƒLß·ÈPDæV—À5aU2׋K1Åøê@IÞŸ�}xœ=ü§ÿíþíÿêùy:7\ZF—˜ÞO®™Ì±È6Iw™ˆÌ²é|?¦Ì°—ó_7Ï›b–ýÙŸþËÿýÝÿýr}-(p~ݺ*A ¢‹_À[æYý¢U‚‡3Wx,s±Â-Obƒt¨ªlq‰Ç\ÃÜO8cjºëLÖoÚ¡=FÙëúIIµ>¹e;*èjí»¸òVe›"lµ_öö›o7_`¡«Æc²pÅ~¾€Ûª@oI¾ªë‹¬^*Kòáû¸M¯\˜ùñÀË¯Ž›ªT]ëe÷_­×ê}Õ}ªïÿºb<vyªëóÕ^Y׫íZß²ú4q«uʽÆÝÞü÷ŒÂ„÷žŸQâ|¾k.".Y3àoûwi›¥ëÖvU˜Ô|ýëßW»®½wl¼D ÌE’1Žì~`|_Œ­{yéýDV¿¨ÃõÞM¼#º,<Bùq??ÃtÀLå#Ïé™§j 6›ž÷£_öZW=!èzÅããLÒ~ýÚšDmzž¿Ú?õýSl˜¢…»4ÊWÛk¬Ò7“ïrç/_Ö.«ê~†Ü2~¸&\eà­Ökïºiµ>÷J.×ÍÏËßšUâvûy~õ¹Äë_þÖuɾzì}žØŽ¼ßT:žÞ—3èT}œow{ß¹TïÛdºÕz®Î;[ÇEÖ¼Õç½*~<ÄíÓíàùëãã­Þ3œ/²þTýTm÷6òÿþ·ÿø¯ÿéoiJŨª2ÆJÒ*Ì5 Ó›ó]¦Øc›êûÛ?ÿÍ_¿û›ÖþÓÿôÿöÿçóóp)ׄ(ûH¯[é@˜b†½ÇüÐÆþêÌ±Ö öp½ÆûšÄ"#õþ³3b™d ueAÇ" Ü€½ÁlPžÚ@FçÑr‘)29À7ê?oÈG}ÇÄeóg >®P˜ƒÄ3 0R¬f�YuãýÍëm¯cì­c²@ÿ¥€±ý‚ímá±W¬Æ î_Zî­x­Ž_¼ž¹°ÔåìÛ ¢B¡¾ÐÇûU¶êFvSmXY¿æy«rŸ,½’uÀjUA•W«_(ê~©µo¿ìU¨òªß»{+nø}”¢4+ØT×WŸßöùwï8çé°ÿ.ɼ¬ FÓ†÷×}¡ª¨y?{žùü© ¬°ßb&QÜ/[ÖS³AZƒó­µ�;×û'a8†3ù™l[ϪþPëT á¹^`ÕoøjÍnðg ¬Mçy¿h(ô®c,°æówWˆóþâ ®£d€S-&ŸÏ¢u·Ý§‘Ö$Âö½sÿ«Xgs}¯/ã¡§ßã qÛñV±šäíÙÅÿ|ë!Ÿغ>Új ·š/«GÜÎõûî5<\뿺¢uÕ@k °Ù£ Í™B;tî§È¿—©eˆxù}2ÕOº^˜nÕµ…çW t—¹BT÷ÉÆckïš¶·-^™ƒ¢€¥½.<ß>ÖÞgm¼ùñô6óª¯o ä¡¡Æ[×GÉúó;µÖÚßÿöß @LIhÚH)à«c¬_'Œ±,ÖÖϤÿíŸÿæ_Ý�1Æ»¹<¼M (ë�™=ÿ]Ca±ºÞ·–ÆS×U:”M̱ör<_ÿúåúKL±?û7ò¼û‹—rìhÈŠEe$|cs~z,Cl(R,µõ~ÛpõøéÀB F då zk»•ñ±&ë€*6”â#S¤ðó{¡Ÿ @CfŽb:i`GÕ·fñÚDú!÷brlíÛ¾ìüjyûÔµžbÜÏòðÞL¶­ ¶½L9u¿øúV`l/c2ðC¨Ê¸ªÖïÞÌÏ­÷]ª<”*@Íï.Ǥœõùóµ0ýªk¼û)îªõUKo[ަŽÉu_Ÿ_‡Ü‹©™ëªýŠ9…×ó~Sž x=ù±/ç^ õó3³fxÅÌKÕ¾j¿x&O£†k~®™pªv® ¾º ‹½ÉǦ‹¸ ³ù¶ÏXḬÖÚóeÚ/Ô +ÏhÔóÂ|¹yl¶~ÿöRßù9h…Ì6¦WUæq¹8ÝÏXŠe†¢b…ÙóÇb¬°Õz’ï¥V0[En™ ଜµõw Äù›ÌBõØ]¡¶ßAFBÞþÕvÞ �]ëtpfæêýWë(Õûn4U¹¿ ð¹÷tµü­í­¥_(îdßÏ\ñüèç…x¾ùÔw½ªGÙ×U†J·©½M²ùÁ×£ögóË€¸‰!fb‡-0¬î |) ªZ”ÕrZkƒ!öîÕµáìc»WÊ%¢¤¾k­”ÎÞï×cŽ©˜e¯ÇÈøB ós lbš_\< Wq,1å[~5–G'¹‘}„ôý:Ö‹·Î,Qu;16Aì{Þûž7.¾]U…¡_lj£¾êŸWÁǵd@Øg—Ÿ·$gqÞÊ=*[DÇNË€°X‘îc¤Øô¨€\I³8ØvÕûgíüªd±òØ4kãRaÛ÷’sr~u¾Qý’¥Ïî×;Vmw̨P¢záù¬_WX[Ÿwõ¹f‚óò*�v/ gûþ)¦‡Šù–Å~Ú;OÝÿ»sJÎמçÅÍ_öýó.‘\çåüZ€°UŒ Œ#oH¡æùêûtDµú㺲³Œ­ãDL'’^ÍK¸îÖó«Ý'ŒþË�#¶þ>’ë(|J÷Ö¥·­ÿez?ìþÂè¡k¿UÁ˜_ä|—á’ïbžã¡]d;múãë¿•Kk‚á5Wÿ] s ¯ã¸Q±ÂìóÏ¿ÛÌõý|Ç9ŽC[¯¡€šËÅXRhé˜qÄ*‰cïÙvúý$öz_kó²ŠÙ±_Ñv„ÿ&Ž/æì½]#f±m²vz…+Ž•O•£dm=3dî$øv(&K ËÙª8¿Šïëà¾>kûœ<þ7z\‰¤b jqf•ë‘X>Ußkš¿A¿í]ÖömY~=âr¯¯ýQ>Ëý¾ºßâé×cÏÅ€z=ö *G‡¬=vžË]wúï4«Gûîêʹ׾:Å�³ÿªÎ½29ÓW¿ª_²ïJ<¿Ô]¸fb�¢ ˜º Fb™ÿ�£õ˜ÊS °Ï•rªò®µv¢† Ãp4VÌñw¯éb‹žéÅc(ƒìCkíËS °çû†õ°r[xö Àõuãt ¿VØÆ­ YA �]’Ä š™¹oð½¨àÕ‘K¦Xàõô×c€îœlhã7³�fõ©ºˆŒÊïõUíEËÙ §îç&»‘Å 3{yÌ“·ß¶>Çdá¤ßÞ/šÁ„åþªÔÿç’Ü…b|>s!³»É—[*k…å˜ßæòõýâöeósYór² A]qßW)~NÉùj9êþ[-«ý‘•·wAž=ï*€ÈïsL®¯ô8?òòªê²ÕôY9ûeÛ†´cíy_^ç%tņ«õþ¥D¥¸NTójfÁ¯×5±‡‚xÞÏÔÆ‘0ׇ•ñÏ*=/eŒ›~¿ÈL1Ö.$]•éƒç»ÁÝíß3ÆìyßOÈã@J.•}ÑPH\^˜_eû²ë4Rl̯ñÿ4•?3È&é€Ös2ß= òyô§þžòý•ò¸`ÿÙ:nÍ SV™bÆ*¤QA}MgóE»rT†Ùú}Û¼¬@ë Üͧßu¿ºdL.û_-Ç3{°œì¾{}±hWqÕþ‰ß ϨÉêSŸP gû ©…éuýªýT�²óyû°Ùwºº/É€D¬ŸJÇŸûA¤Ëê•÷£ª €ª>__îê¾t›aâ!Mý±ºÿ³²å»Å˱ýµª6díËä3ß ¸äâŸgn‚ªã|½ÊL®¿7YûªòÖûPT!.Ãóm�]ß°ó`§ê±UÞ9&Ø—æ‡WÆX?¾Éw�,ý`Òÿ!ì¸3ÃØýg î‹(ç‹(·A9¯ç]¬² lœn2,ÜŽ¯Ç­ Z CÉ,;ûÆô&c0ŸÇ>¿´V¥RŽžìFY3Rê°r±ÃÊòÒÇNSíV±$j¢-?càp©0+î”…¥µ¤Ž]Cý\¢™`9‰ó¼¿ŽB¡é7ÎØîÌ‘/¼/i¾½ý´O2b¶=¯mßë÷õ±vâþR�>·cº ËD‡.™…7LPé/Åñå¯g�XKò­ZªV]Ò©údÿÙ|”Õ§%å5(/?ÞùB;cð倰’ðÜ¥ú~o½^—m–y~þÞhC‡ ^šcùù¿›ñy=Þ2C¨³1¼b㪯¿Ô:O1ž¢õ“Z?2¥UÃ2k–IËì€F{=ßïc¦5ˆCÀB1\X©u=¯? ‡‹¹3œ?»}„mŸ-c…ÍÿY;Ôu[NÀÐuáý<º<´Ì¯ \¿8�,Ãø"1Á:Pf\ b»b¤"ob´ÌÕv›®¯îû80­Ü,Æßµ<s©;<‰t[]\YQŒ0Ttmgˆ­Aû÷0°í©)¯â_‰wåÅ%*&NVîµ}ñay\Äýâë‘õÚX•Y§bÚ¨ú @– [=3dóBMr—iÕzg€ ŒŠac땪ªÝšyJÊkI:U|ÿV 2yûµ(�‡—ŸîgQöG–®*UýAõ:ßZu?»õþíå>*=?¯å}‘ºOMƒ­šÞ×G½÷Õùg¯¾.<}Ì7L·Ê¨\«×by_I„&†W—�à2ùÈ}ºlexQà,`’©cZ?î2quž1Ãnòc`)F؇—rP6»>|iz½ÞC¾WyøŽ»^|¶±Ð€eU ó‡pÞŽ ÂåÅE‡ÝØ ={±·Æ"cT,ùl6¼Ñ¿Ê Sõˆ$wÙ“2c¢æ.Eò……R°zfŒœ‹½§äضϟWA´­¯RØÖ{—`á_cƽ­dÀ{Åqìú*w!fÇWÃ'wuWe¤TógýgÿW¥æØEß×ç«°—ä?ëÇì=U媘Lùû¤˜<|ìûÑŽ/5Žu½ßË墺αKñùúvØúª˜Lê}¬ÏÏq>ÿ\2àœßÇÏ/1cl««ÂŸ{>ÖRe ªvÄÀkæÂ¿ÿª_«.�óõÈÛȺË_Û®£›‡4ðÌAøS.ñðzö|ùÿ,Êâcr¯«N�4øôÜ¥õ)1`òí°@ÑÙœoÿ}zÉ\ëq†‘g�¹Ç&~"å'lýZq%1Õ†ç›( B—{„}ÚÎ¡Ž­Ë�GÌä›b„=Ïï‰}~òhþkß‘~ßù{‚ãHõ{ä~½~ö9œÌ?:*.O•d†ÄŒƒ 0íÁòâtÕ!ºe1Ô7R]èq¥dã´îÊ)6\Ê,X^ÕàªçC¡-¯£‰§S1÷3Ib—]þ>™g„˜ âë[SÈoe8¬¯obCºì}Éc"ð —xç.Èb…4æ?ˆççûƒKk‘·‡·ok ²½�ƺAf\nx­¶«ål÷ªìoõÜjŒÃq\ÔîC+ctåÏ/cn­ ïƒ\'¼µØç\øÔw¯÷r÷êsJã[\_Ý€)rýHG]N±ÉZRŽäh}¦ò°~“ìs”î¼ó 4u¦º¾L�˜u‰¨c‹E@˜OgË}_Hë*p­øðcŠq Î[&ösÁ1:wå1O,UƒGA–ûõ lto ýQd(gØpªúñólÿDŽ+ïØçüøP[ËÙxá®6ÎK=æ›'ªt¿ùúrËNdÞŒ~ˆ-Í\‰ú·â’ò—8ÄŠåJË»T€£uÁèµê‡z•9T-Û[“­ ZÕ*}M°ž?+¯#'¾_€SåÛ÷o1ô¼”Ïo¬<å2-æüýãþבÑiÿñ}R1±Ž"=Öë"óÅõÌÆ_ÕU¨r]úóË6Ëþº‹BTñyPÄ9£°§·ÿ£Üsxý×"jéë¹"Ÿ÷€Í SDk³Dëê{§ß‹,6•®/zè }f¦Æé0<;¦×�Æüz¶êÚ¯ó~冸®û€“¶ØœÒŠç‰FÎ#à5·c6$œ ç|‡æ ñ˜æ×£av]Z—†Xï'pHÚù1ú°VIˆëëÝg°ïH€YñÌÍG‘Î>?¿oº§ý”‹Z·¨ùm}Ý#( ˜iî|ö‰g¸x“ÀÖuÁ*�¡ÓÕþ_S<WûÙ§ëã’vÜzWvÛÚ“+^c¦Ž:VŠçºËBuœ ¾ëL°)�`Häí».¬O¶õ/;#6ëךb<wñ·¿ ”®ºJÍ©5@7—Ú{¥ûµÖ_9“³ €n44Ó6c†®ösXÛªÇZÍ¿VnÎÀŒß£.y 9žþê¾/-ÌWà}{jróƒâj"tYhηÆ)"ŸEþì:È`+´ïs’Ïœ×€Ø €u ª3·fy?[ÝUâ @ÿíå|ÿç€Ùî8vå8ä¹îŽ1ÖØ˜Ù †WÍÍ.9æ`γ ïz¶�Œ62l#Ƀ +5]á7üèêæ©1 Ñá *È€·C€•7+<™EpÝ’P[x¡…ðª+æb¦ªÐgÛ §vEÝ xq`M)²W]5ú`ñQ?¼½(FGÖO¶]ž¡¢,®m9Šé‚õ«~ ëÌ‹ÌÒ¬Ö÷–ê8ØëúM©!T9Uò^àB13Å÷gj¼­1±4 ËËÞ— XŽÛëóñûV™‰Õù¦ pfù·2¹²þÚ.{™}Y{׿ÅÕ.D9#I¿¿|>ÂûòsÏs[ÅÇâïn2“jéþzUüºP1¡X;*ï-cvy@>Wˆáº'tfC,[_?Ï>Šÿ¹ýL*±iuùš)Éö ÃN1§9 †í‰ê ³ü· 1›¹½¦-³ýtt÷µ@˜¹ý5•‡®ÃvZ lᯠëpÿàÍõâ¢çiŒ¶6?'ߎÈ~½^V¢÷ƒÕ?3TQóZÆ@RǼƳð•Èþq†Óß}Þ²{­ ²ö*Å_ÉDoåÚÌ>ßë²B±º®‰û¯ÊXÛ®8¯îßâýcæB­ÞŽZ»¯åók®)»d®öòò±œU`+–,öUæúQãÌÅc}§ÆE•±Xí· ˜Àr‘ñÃëŸÇ¼â²µ¿|¬ÌUá÷©Çj¼wûö»ê|`äßçz?d�TÖ.xÛÿª+Ûíûð¸>ëbû%éŸ èR® ?Ãq—Ï,Ø�õY\ÿ ÷U@™ÞTûZ’Ϝ׀ŠŠõ¥b|ͱÉ,`…@ØwðÌ®C׊]Þ7ïr1c¤Õø}#wÀ.ü/á†r¶T€Ñ “ì­™Ó¯·æ7ü³Åk¿ncje.}?*@×›_ïõŠ\ÜÅšÞ"6ëW\ü$êg UÅçlY¼"9Ó£z3P¼Â:»ÿÚÂö×ç Lz1p¥ ^”K¯Øåƒ~yù9ƒcÛd=Ýšì}Þ«�Éê}s—xµòªõË�½ÕóÇâù¬¼ê<U7dXë§{Í ¿V¦ÐýeÍÕ±žÉ¥° ò5“nˆf$ÏÇUÀw+Cô­¤nˆa —†Ä Í‹Ûxf®kV³v ÁX«³dób;Ò2·C~´;rA×ëç¿×«édÖa[æñ (ˆ\êûd@e' y)½_‰mV1ä÷7,vû2Åž(ü ™_S»L °fb…Óþ°À’gÀâóä.ëÇ>ŠÔ×1ÂØóˆö9³‚ƾ'gpU‰ã`Õ k{lj“OÏß�ÞèùÌåá:0ËXKéÔq]s�™Qqþ<&ÕVFÇÚºCk¼Ý™Ëª{)žU;ê@ Ö‡·oµ¾ñ}¯Ç6{›þËÿ>[,õ÷um\Wc[í•Ü%hÆ„©Ž·Œi×Ë©µk;£s­ßòXS™Añ½\Ìq¦–Ê—3´b�¦¥ù³zgíYå²Q1]cƒËƒœ¿9ƒw¼«ÌÏXòyL çbþ½Rs9»ÝÀ º<DÀlbX)†X‹®1Àjƒ­Ä#RÊg±,ö×Ç ¤îʰgsŒ¯Îë�ׇVÌ‹ –ÅF¡.3¬ËÏ$ã–•·ôc³A¡3d<úð¬ÄÇc¢â‰C5+$ŽÓÐ* ÆP¹Ö‹,içzVc‘e@SÜ/Êr¸‹QÖÿŸDz[ÿ`ùrfˆn,93.Η-mù^ñ©£ü¾ÞûŸ‡Eä²èvž{rÕõ–»¶Ó–ø||(Wxë€ë[33~]ãã­€7U~ z+` ‹õ±µüU€í^é¼T7ÕrÖ,Àª@Šf©ù83hˆ™ÂGQºöô1ðT{8#ì×ö~û~ª 2‹3€O‹Ø?]ÎòùŽ®cÅ{¶nQý¦]6æ\«L•gÓ ©±NåNýø ùÞN8a×™3`jÇ“tÅÍ ÝfÉ�:îÂæg´·óƒñÕÓÙUÜ£†¿Ïê©!JU„=°uêʾ¤‘q330¿ùÓ3¿Ñ0.c„±}ꬳÏëô²ï<»ëPÎçå•Ò èºóÙ=eÕò{H¶B±1Á²Rö®›º‚]4y}Wèe ˺K?L_SXúzV³ZyÙóÍ™7k’Åʘ.¨ÚʨÃô]¡šõ_U/€ÀÚ€>ñÑuUŽ®ç>{*fà^€<wM˜2m½*Ò3ÆÆ¬Î—è¢T×+¾í±6`¸P•·3Ú¼A Ï×gõ¹éë[%vyMÒùq„ÌõïÎþXs8fåYYeP®Šf:Æóíö˜¡—‡¨BÆVgrµù¿¶1ÖëÑÿKé‰lÍ×ZkíÝó—öéõèc%‹dˆÍ‚L¯îZñ–]** .s±øÝ+63Óf ÎÖÇúŠ'Á–‡*èÉü Ú¼Q94»q;L1ÇÔÆqÞ΂b\58Ž}ý[`Ë»†ër¦€×¼™7ôÇæ]óUc¢U¾ùø÷Þž]ïŒØhiëÛ18P¦Žc×8{+¢\ž4Ñnþ¯e6ŸÚø+ÍE. ÛKyûÛÿë’š¢¡ÎP@«u5³û¨Éó™"p[„{¥ûïC¶m«ùßê=üõ¼ßÕ wÕð j9í£Q¿ SºÊ¥k»lÌ+äð|Ð^·|ÿu¼Ï ¸©ÆäÓ (åÒŽÿý̾ÃC1¸æï4cæÏç#Ñ£½\Æz:W|" ‡ýÄc}áý‡ÁÎ „EL|s·2~À¤Ž#yã½óLò™éslœq4þOr_ „­s™"‚Å�»Nû¾²bc€ �æèò±ÂŒ‹Ã'ï ÷iÔUb£éÃp  ™c5ã8 ù€­{àû"üXËí+QdññQŸ—+L1?âüºM¡§¥Ú5`¿¾{|qÇØ¾{»@äû¶ñ\mº”eÀÃs«ÊÜñ u®ˆÔŒ 5fƒª±’3¡:þ¯Éz¯îÒ«Ú¿k.õ¯É:5wÇÇY)¡¹X^õ¾Xî}€u†NÍE\8ªûe÷W�'Ÿç}¾3³"ó'8ªï×:`¾ú>©vÞÇð×ßx~ª©êzUª ¶jò÷A»ª­î·³ùXéÈϘk\üxÝûÞÚûUç_ÍŒ®­¢^ °ªÆÞ"À[Y¬°LVÓ÷v}N®cûm ±‡÷í[Èó þ‡|Çóù÷Í wyøÝKúïh9C<`¦„zÊÅâ “­3ÃÌÿ ¦<ÄÈë2oP¯°d¾¾2Äø -*ç KÅE ÞŸ·­èâ}Í[‰CЖ"—-9Â6\Ì"snÛ b,ûju‚Îê«\°¬S™#‹Õˆ±¡‚hóûV?xJ1¨)ìO$ÿQ,$sl|ß_ÚeV.1³ì"Çÿ kFY6®Ñ]1TÿòóÊXÝåfö~T©óo­hÿu(ò¹zþZÊÝZmL®º!í Š{T z «f`Í›Š©³êJ³žîç}oÖçÿ øâÏû(¿_œÖ’ïÖeA>$cRU�žÈ�…Çxµ×3À-²ˆž=4—ë¥ Alûg >\7>’ûTÆbX±zbû.düd l}½ç‚ÌcTßhß1îÍåt`«Ñó Z‰{Ã2f#�� �IDATåv`Œ0ÃüR@¯'Êéuü±qýí÷OVØ~$îž+…ÏM¼b4cä’íÃìyþ]Íb‰zአjŒ›q\uêÚ.nRÖ]"Žçz¡¥ßàñÖN \x& 2]8PQgzÄ®ûº‚-Û“  ÌÝ/–Nuݦî·uý¹jЗ1CöºLãâc5Šé¹xEsÌÌ™¶^ú}Wã|íùç øø9ùq›U‰ †•¬Ç4ªê·ð}ó)Æêª‹Õªë׌9³Î@\ÕÓñþÌczi½Y¥¼T]GVÇeM/s•ó`ü=Éõ9Õ÷€ß_Ïïã+î=_מ§2©»ÜÌ 02ƒ‚Ö²:�–ItM®3‡¡‹F’ŽºV Ê¡é& Öÿ]cÀ×M:P¦d»ËÆ » sYxK÷eŽi‡Úu"?ÿƒa¢1ù8€¯‡Hq bNe–¡7ÁàÑxÞÇ"›7„‡6\-f±¯¶º*œa³«k¡ÚÄFœ»Ø™™fê~�IÖ®òóÊ¢;Ÿ ŸÄu¦Øñ’[±ç¨bp° ØŠëŸ^/øã˜m~|ÌõÓÌ®è=6ïêv¶ºD Œ_ŸÔDÇòy®8é¹ÂÖ[ôf–¾J1¢€7ÅHTL9u¿¸¸Èq½ºð]¸ßFV7‚{ek¹ký“»Ž\ÝÈÄ ì‹oµz¶d<úï L2{ŠÙÀv>Ö¿#¿¤ìwÉýóü…1~úù9ÆŽª»:Þ øæóSô½W'‘XW~õvdë „ñṵ̀ ]0Ï�Dµ>Y;¬¡˜bÃüÕ^ÍŒ³.O‹ÀŽM§�-­ ¼„ûšQÞð|Ñó©u8__غŠíåïÿ$€¯Ø3FÎØ³ç[ú!@¬b ãxYÛç(†äMf…¡rKw×ë÷WemUQŒ¯,Ô€YàkÞLMy/.=oϽ]6ë*q?Ø@ü|[.÷LÿëÀj|Ÿ«TLb?ÔÊó¢€¹ªâSµgëþNhûzÜw¡‚ êõÊöAÙ¾Ä2G½j 4tÑWeæ í ÃzVc´Õ€j?î•Um·U?m5`óYÕÅŠb’aý2‰¿Éd«^ߣ Ò†#Õq‰ùWy«†§Y}@Ä÷qU5Þê�Zõ<Î/Y;ký§ß‡ °Ê˜]Ÿ£ôèz1cle÷C—ð ëC�´Pæb{ÀÔ·ÀÜúׇ(—‹*fØ €õØcÃÅ¡w‘¨\'ªXcLz Œ™ X�Œ™tê&G‘Ï¥ô|Œ úq<|õ?Nÿíõz ÞHk5È´ºýw…ÀIl�Oiqàì,ÑF[mLûË4¨€AWŒØócJaÿúöžÌÆ{¸~ÄàÞ^"fžrÙÒû±²åŠšì8#KyëÂ3såÈë#\é¤.y©-L"KýÛöAEÅ=–€Rƒc®ÈŠú5�#S`g.ÍTû°wqÇXº”Ë\\bþsr~+ÀÆß«ŒA™‰r}™13Æ‹j? s…Vé]¿(=&íÊ,ÀÔx9Bùþ}äÇU9ŠùOuÿ<$›—3ÀÅl>ëßó£ûn£ŒþäÌžÌò¶¶ñŒÞWÅøÇïwE±Ÿ3úNRáÎ×!'±¾DC™“[Oµ6º àë±¹þ¦[Ôì<7Hâéѣą´×º²D—z'·~¬®ó"`§& X`ë¿ë‹ÞÊ»’/{3åÓýEàÚÝ�`O`¨øD]Øûrãþ‰tì{×–øü3ƒ¼Š+Á!gºS®qæóxÎ×b³"œ¯uºFó)A†€f"e’›–ÌÿGxÃ3×â{EyÓA UJax/ƒ®ªÏs@D?g\(—|û RsW‘UæCÕ¥"WdVcèd€a•¡åËÃtèrq+@ªÕñž¹†ÌÚª~Yù<½®çMê1ëªýÊÇAÎ�ÌôQXn<]å{Xk—oˆ÷²¦Ðý¢Ž×˜g«±¦å~áíË]>6šnÕ•eÖΜIYk>^”cF}n0Qâ2æo?ŸÕß#üNV¿KªÞ  Â˜aUù ù�KÅ&kI~t…€šb‚׉­µ[ ±[Føx?_èúöåúÍåà�Æ>…ÀWt<Ÿï婨_èrq¼l¹ß9†˜rÍ8møÑB](>€eà³Þ€kW öüQl°†K >=§›]CàF¶µmÁBc [¯0B×779™&S�48Î6Ò™k•mlµØØ¤tÅGÿéN °9A¿d ³“S°q—D[Ÿ‹fðeû¹ß¼ËPßO±bàœ�f5j°¶ÀG…' §Pá§¶Åz£»Q±÷úýdma¯95j?2n” 1ä)æÙ%Ùh{y<ŽºxàÛaëuLVñ¦¢ˆŽ®çŒ ¯PžÛ‘‰w}™Ï_ó}ê–¢ªý¨ Wíoæ8sÙéÇ92ÃȖÇ\ŸÙò@oDÉ‚W¹HÕòK1×D)+.¸,“ ßS[Ž ùxÑ€òj¯)Ù¸F�,ZǨv3 /^Üz]dÛõ…1v+öƒÎ,Ü÷ ^* ùØÃƒZ7öØõl¿ïɬÿæçÀÊ×uñõô×£| 0 /è\Óò‘áu©�/Ô•aû*4H|Î×Gþ¹al04àbëVæ‚“1sæòº«Æ¹žYL *›L¿6ï³ï䚇 ü?…ÿ™"Ü3œVE­èùŠ™`jÜÝÛpn0Pº1VH׋[]3Ååi…qµÜ©Ç�«2h¶º ;/åÓÌl=ú=â úìùz ÄÖOÇ¢ÚÆðÉD)Ì3לuC£*p™Õ#Îç%äÖß%|Ô<ÕXn$Ù÷ù Ç-—|¼e ­}¢bVéú{Àçqý=\Uûö@T](ªúœ’ÿª¬d5CÅCq~®ÖK?ÏÚ{©¿‹qþ"�‰±Âšg`U¨~2¸Cˤ+�h™(†Ø7Q&â:±µÖb7€èÛöáèb Àl0É>šôß¶/é0¦„Å&ûB]àš™`_^ÿ@Æ](€ 9 Û/Ƨ}¶G±>õÕu.=ÙÌ$S>üm0l+¸ažï›¹†Œ6zØP_OV1ÀVVÁp†ÿußû«®KXì#)צC‹êøù_ÊNÕ>�Íé0–FÅÂ^1îZpŒõóïÉ*¯sKYfWWGYN¯?W´åÝ  ã÷­ÆpùõK̘É�¢í %~ŸÌ"Y31pçó7“ïâÆ*Hq|Å�Ö¥X¾îïÚFPûܵ›jTÌ9Í <‰ó`¤ú—ŸÇrG?Õž·¼k€juÞȘnUÀò—’ª ,ÍÜêrǸBW‘s>«*wµ™+ÔbC–íýÇì]<ÐÇ×Z¯ Cj�´/OÕCc]¬ëhõ<ê±ÉÖ%tr¶Žaë@k å qj.u½£õy\1¦Wt%w%éÐpï&ܵ{Tß&\ 6ˆÝÜ„ËD%8ùúÞ{2ˆ<# K[å*uExz Pf#è$¾¾Ur&.llµX¶õ_¼|º ºâ‚�X›ewÓ펯çiBèRû©ÊÐýǯg1{2&¡ð]åù÷}_ש}®óØF˜.”bÆT#ï=«§Vc Ú»¼Û»­!xß~œõ òÃïçËQéW„ÚúRÇ`«Þ‡×7OgÇAÎX«½Ïêùå®üð>5}QTi ³:/Ö¾k¹@Ü_z~ˆ¿³ù|§Ú·6€eu>ÀïVÍ Á¿·ö}Îcƒ¡Ø~<¸ùBÕ¯A¾ê}÷}×rW½ê¼}¯óõTæ*ÑœWL«. ȪÆôê‚�ÙÄä¢Ì/ÔQæ™j§cˆµÖ:ÐôéÐú¶µñßZë€Õ'qƒOð¿î:…åÿ×Ñeã�æ~01Íf™½ÿ�Ì2À§Ë“Þ°eÀXaƒçmÑq#ú4GKÏqݺ2™]¦0×8ž_¤êF 7 L†‹A¯¸™U³"{>¯7¤UÅVí8RäUYŒ©„A¸çô£\»AÖé礿3—NZ"ד±£ÍdÓŠïUÉ,Í=ÃÇ*Jó¬XÌ “š«ÈålÛ`üú\8®Ö³Ú?q9Yl%¼ŸrM‡ùÐ¥ŠyÂß?ÏXâõ8Š TÐjqèñõ@f“mÏjùCaœ‹<½k@TsÏ‘øy*àú’lH²ú¨ã.ï3Šfp©ëü{¦Ç5*¶ùûÈ�£fÒcyû]‡ñòkåe.üp0·³æšÛ–{™ÚÍ3(' ¸džì:Å®sØz'bÚôòÙ:+3`Ê\â5s³+g®s>·ß3‘ü¸ µ¢~ŽbGÍë{¶/¸N†qQ ä‘ίèøúÿøºÏÀ˜^Ó} Ðõ8öGÔbìJÏb\× ¨Ôº>Z×®ÄlÓÂæâðö\Æu6¾€Y«o§_w �ì=zX©˜dŠšC1]þE±-¼Àqw¨ö1{¿Ó¹…xÆøá þUf„g–U]jíkgLd€ÆÛIUAßÂëu�÷m˜Y #¯àWíEˆUY QÁ}/€çU~ìe°]«O–~hÈ\ æÂŸÅ5¯½ÿZ¿T]ùùzfùâñ§bååªô\ê WUÏêý·Ôñø<Èu“­_¨eǵçï]ãV g8°†ãöêæUo›?¿ïVÃÿø½ÓÀá&†âÃW8jɱq‰H$db5 ¼ÑrŸäå)׋P§ê¥\*¶Öl ±.ŸÄ¿­à åÀº.üØêòÊ®;S¬½þ£ËDuHxñ€ȺË06ß`]Üõ~ÞºPô–›öØ.åð5\*αfA—™"&ë'L× hilcDµ—V^A`}þ[àìlؾ-Š­Ë=cbV” Å—m߬@R1Ùzz.ë €¨ê®y?0×c[м=ƒ¡±«=˜1E„wÉëë]íe XΰÑ!Á#§Úÿ­J¼PPýUí§Œñ¥ïwËÃúgŒN_åË�ŬÇlSŒ.Û¾–Žß5ɺ+A•_µó×ÍÜÊÛcÏWÆê{1"\ݯµþ]Ô†5s¹—v}´¶AÉÑsºÕuú(μÎÖ1 ˆcŸalTdè[CŸ±NAàËÍ à«p^¸aPöÞŽùµ3ûÜt?a Óy/€¡R{Yû¯-²Æ¿õŠ€ûËÇ »Àºr<)¾ÿ¸¼ìw €öÀ�ê'¾ïƒ @Æï—Éx>ü¹ñr}L7+™+ÒŠp×ñ€íâ-ôÏ¢œõïÎ<NêÌÌxÝᥠ(`{ùñºTw$G¸Ú°{­Œ3ÆNÖþ® ‹j¹Bç÷ùøºªê2ê öK§�¯‡4Ý6—êG¿ª ߨÒ}`Ö>Åôz+—rÊ¥£ •"7f|eÌ·!–é¡d«kQ;H1WÖççêûl%g¶ÅíªÖKß�·Î Ú0ŽzfL²°ÙûÞdã²Z¯j9[™Âº«üXÇÐR!Ê�u0­ rfïZ¿o¦š‡ÕrÖÖ_/òü#wmØ…¸8¬J@}“7v¬€°‚˜r& 0lï»V‘�°z¦ÖÃ{›¾gS,²OK�Xk@cL1À½a†Í�ÙQnfá9 *Ü'Åa&æºaýÈb d>ú0vuç»åèÑ1Åf—+8nÍoЫ¾ñc‹E¯ ºYhž Å,ú-°1\òÌÏm˜2ÅOÿÏMEMÅõg‚iÅð#ý÷†'(/€|¿Úvòñ.'£í¤ê´´V®‘¬«M.ÌŽJ±}PtŒv=sѧKP¡ÆGUq«b e²îâð×"¿VࢶÐ:n[èö+¦V @«ž÷ã°êÓ{µ=ÿmËÞ÷2wQx“ÜA3²¢r=s cDv‰™}­)PÍEFk«Šn\{ÙÂ̘ó¡Ë=u_ e‰z£É]z([÷ ƒ³[°|™Kfì‡ùø1LÏ]h3 Qõg_/qÀûó&GgÇÛÍ$jÏì¡á¶¿Ðülõúq®ÚubrÝÒù/µÿ˜Òá> U¿”bÈÀã†n˜Åõ–ÝGô}AļÞâº^¥G…§v!eÓÍíÊÞ—œGæ[¾¬~§ãó¾ÝVÖc¡ìýÞ{¥ZsE«,Í3WpY,¢ÌÐO)�µË(ÌgÏWc¿Uû+ÙwÈ\Œ¯**×\«ÕÇ¿R+`ÑJý>JQ\âÖD1£4 ª€·*€£Ú—_U°«öÕe+°·ÊpZeôÅí­Æ°B ŸKPÈ€Œ:31î§|Üd [ep‰šU{zºL¶ø[’½^5&g>ÿnÛÿûù–Ï_èÎÖeöü5™|?eߟ8ÿ!mGvÿ.4ÖVàâðsr>sQ˜aŠIöÈGï§�½bù†Ø&™\-v1 ²‡÷íÓ«¬µ†@ÛH@U Íב16Ÿ·å|÷zÌK(^Á0m”žÁr7†Ï°GŸúÆ•ºAa¢ãxl}ìÆÖZ„^[la:ç¯J–>²xõ€)?ÂÂn”ó,žÈÑEãžvÄ÷éõ®åË6êGøŸL¨ ŠÛ“-üQ!æ‹ àœ]Ffv£mî7fÙš)v÷ÇâÊ\¤e€ÿ ©ØZÞ¥/wÄnR®ðj¢]à­åSòÏ'Ú/%µ…ÝýÔ51sðíÚõ߀Õe;³0.o¯Zïèžÿ™^Ïb¹áwLÍgpEƒ�ÅlRL‰fr¦oM€RyNÜ b}ýÀ\*·é¸jÐQcÌ¡a ~4óì±±qeÛ™kÀ*C =Ìå÷uâì  ¬úuãL­½áIæÂ1;ßZ좼ZV.®Ÿ,³Ë»XçûƒÌdªGaÇÂrNÊ9‰ýAf�Ò{#vEYo·o à®ê¬"Î3…rEme¼1—«­Uæ5Âk Ë\ÁT;Ö�Ñ>'†oå qÔ³ÚO*}ïå2+ ½+(¥¶ Hï:ª‰|½¾«À‘bºqÃŒº Ƚ�Xù¹Â:S˜o½oÆ€;$ý”3=V:U?¼ùXþÚ>¹ÎŒÚ«ÈG&g ”*cÍŠfþÄýuHÊÃïHÆhÉý¾¾k@P=›Çêû‘,±‹Õ<¢öªÀÄCN÷—’}®õs_eœmÝÇoeNöûWظ¾Uæ[Î`¾— _Õ®µñ»ýû‡ù2@iÕ¢’6ݦ ®—\+ª˜dªý÷�ľ}ùÿ4ÿ#sìùKûb•eå ©ºVDÙ ¬y¦XÌ8“#wYá™Jö<•%W"O‰E¦Úà©`×3cl¾Þ]*6sþBËÁ ˵°áÆúÖ-­‚£—‡ÌºYÑÃ]a—wm”O) “)@Tý°œÖ|l <€ºZԊ̱Ñ}$×uýõ‚V)Œæ~\qÅÅb7à}V\3>çó ñªbààŠŒx#|qÿ\P!]O¯ë;§S1'VÚÕ§zýÞòëa¶ýÿòsȽž·”n�ÛpˆÊÓ–þg¸nœšPgXÍ÷a.-ù¼¯,�y»™¨õj�°.ã{Zû~qæô\nÌ8_e^dëJ¯`™¿ãž™\´Ø¿Šq6§«ˆb‚¡d®í¬kMÞn¿>Çv+O'±~\÷Œ03ÀPôت]_ËA` ×ç£e|p,¾w>&2i¯ñ€ñ(\(Vbk±yG­ÿ#Я›¢^uí ê¥ëÝ]ÏÏéNqˆ–Ñ Ž·)Žö®ë†!ÓÂ3ÞÖ¤Î$R_¼Z‹«¹· œ#æ›úÞ)�‰[Î+†Šé’“™¥»— @P�Y͇F2yÜ΃¸6ÞV]ØùúqÉ?.3FÞª‹ÈU…nìzËW®sÀVÝÏë®ãç-¬KãûnbZ2/°X’³èØGUEÿóÇáÁ]ßÇúsÃñž[Þ93YÕË÷Ól5¦™¿¿À×ø »µÜkq¾ÐÀ¬z?j.«ß©­.QׯgéVóóq‹íT1ûÔ÷@­×g 1¹J�ÕÂýÔud–¡„çUL2•�b_Ú^ù6¹þiN71Æ>µLª.{: Íç{{‘islg¹±m/éìù3l<ÏX8·L²If`$2m�4+¹ÍxtÞ»º.y?X—,mÊÏ|åÏ’J™%1¯ÏÙm”Yl‡ãëFÐ÷ ¼”Ŷ—ÌÕ³ˆFFT—‹¸1Éæúy‹~´`ýu°ùšwn1Æ]&z&Ú,™ËÖö¹WûÏËV‹â5Ùfá§c•e–ØÊ¥Yÿ_gZ¨v)Èœ¯ªÀ®ZüV¸­ »¼ÝÛÒm•_ÐøÖí¹W9[[ñ×´6_õƘEC Í@=¹òø}Oò<?ë� ®òù+D¢þSç£~Žò+ ×e#ú^eÌ5ß/Op]ÃÖ•¦=ów|Öèù<•kBÞŽ\Ö˜ìö_µ=Ì"hð¤\?¯Åšã ¯+)¯µ³w¬/(³�ËhY{iÑ=ß^¯Ûþ½Ìý<íL>ŒŒç{ya¬ä'ê C»–DQÀgÿŸÇñ¸~¦óæ–ußw(…›õ °¤}‹T�Åí®±× Á”¢zÕ•ÞuùËËWð ì­×9÷N¶)ór³üUæ‹UPg±£²rªí^-_ƒ÷a´T]Ãy�ÁJö<5CP‘UYc¸Êý¯s× Uà=NŸÅdÛú¾^“ö×É9`Öï»È\•Œq§»Êñ‰ùûñZ?Un%Øè˜u lÅëY}Ôû Ö ¼_ªíÆò뱸b€Û—ÌÖ¸Þš™—µ;ès�oŸa{î±ú¾ªr¶1×2¹ŠqÄ Ë�0•ÿ¸þMt}C½°>™+G#€3éÞµ—_í}˜B±€ev=¼·@Yg†M1ź«Å‘­Xü}€ÆÎÏËk¶Aö¼�azóHóy×6ÉÆ´�ÀLù.8²Œ°Š`l‚Öl¬±¹¼ÈòoÞpîñA½ôz~>—ÖÄóò.úÐy»®]åU]²¬º¨±÷ã1G2E RŸ`ì6|a¼ÆÀÕœ¯™|xÞÇ‚PíÅú+Fþ# •?‹Šu–=/ÖžÙ2?‹Ugû!ë?ÕžLQ‹LØØe˜v±c¯#Ã-ô/rae¨�Ý ÔiBYÚü(ZA‹éTÞGî+®êZhµ«€âQŒ³U¦§?™œÃr|ìœ?Ócß^Îh˜] 2—`,vb#é²öÌ×kó8ÊxŸ3h{]•µ¶né_ua¨€È£]Ÿ™ÿj?eß7ty<ßσœŽ€®kƒ=o—oOó«‰c5NÐu¶í/|-#l‚œáüèîj;—  ]Œãúÿm¬«{‹æûõ12¼ü“/x*0�2¸šˆuü$®O‚®Ý'É_6f)Û]ZV=Üï»+ÊÆóãz3ƒŠìó6I´Þõû‘Z{ö+Ú¹h�Lµ�…¯¸.-ÛÉðRî½ÞR. ïTT×ýJñ®˜7*¿RˆÆ.ó~XUdW]Ú¡¨û¨vóö#SÂ3wj ÌU ÆÇ¤Áv¬1¦ÖcYe z¬OÖ¾*#©úÞlfôûÀ%B9£Ó¿ØOƒ ¬¶Ç÷ß*(šñ9*Eþ!׊<úo­ÝÙ8^g̪~PL¨&ÎW V¿'ê}‹÷‡c\eÏ9î¯C2ÿÖ¥ œñûdß¿¼ßÔ}×ÊË÷vÅXu©ZºZ¬µ6X_I�êsR.eF®£«Å,_v?*÷ïþáùã_=?O±·nò¾­KÕµ¡å*±3Éš¼Ž÷Ë�4R¯?ýò_ßýE's94»(ÂàÎÖ¢WMˆ™%ÀÉÅkcÛ-2ض@).PÐ¥ Ïo7î‡W™]ph#¨÷íx¸zÁò¹ElÞ<ßÄu–VCd.rlmذ®¢|ÿ›ç×¶ |û¶l¬gÀâ18å£+¢l<y …÷‹bœÕÞt æÏ÷ã“ißJ?ÌÂڣʵ÷ç‚�’ïǬ?î•.vMâûëÏôõûõr΢ÜU‰->¢Ÿ2×rÞ%–íá¢ûÑ«rVÆUt]Õw{ùê}ÌÚÅŸ—O_¯þ|¿¿eÞ «·¬|ÙöªúÕ]³nS|õöh@뾊NÕ_z~ßöÊÆa5}ô~¡SMb†UÞ^;¾3×–Õû±v2ftäúnUø:L¸ SÈ”1—×ôóŒõìÐ$V]7ÎçµW78;†—g€ÙõRwI~}É×^ËëåGS~œ‰ç`öd@]³7ØW<y†½_&+1Ã*ïqÕ0iE2C¨ ò®·ìuÕ¾L²õA5}u}W·4çý£‡Õ–T}^!õÏË«[þ¿Íw6tݸzݧ۫˜]•lß·ÆpíYe`ðûøþ{ÛuU½bY[ŸÃ½ùÛö»ëã¼V¾r»ú\| It˜õK­ÔsEÀâZÔ·l}ÿê�~ ˆ­>_}¿3”£ô÷iïz}÷Í+Ûç©Ú:a{ÿ÷ú)—˜±~hŒ½Ï+«O&ñýõ¸Ú*q9Õúúí?ÿÏÿø/þéosW…w”‘ûQ «p=ËÖGåûíŸÿæ¯ßýÍÍeâ hÊ€°ŠKÅJŒ¯€}Ë�,d”5”µ—XdæúGø·éªŒ³\1΂‹Ï®9°à´\U±žž—&x>¾ÔFëÉ€°~þÚj€Ô¬0@�Ìeë±Ç2WŠ*x}%ø<ÄFxµÔƘGr?³¢L\µ³¢Èª*Ä£qÒZÄ4:EÜÜŽpDWÚ•Ž²¼à®¼4£Ë÷wƒ„õ+sÕƒõ[Ì}¾žõ¿bްt5æÚYô·º/·ÐÇ~Ê%þ°k€‰§.OÇûgó[óèodÚØze.ç4í‰rì¸õ@Pé—1ô¡è(½�� �IDAT²þR�º ò1„Týy¿(—¤:ŸÍ‘õŸ“fžq×~ŠaŘB¶ýÜâs¨>—ÜR6þNdŒ0uߺdŒZöÝeëÖÑq•ÉkÚû;—_ùþô8oúy€—ç™ä³ëB¨âwެý»ßXlÒª+ê^ÌÀ(Šñ†ýri'WoÆDŸù}eÌJæ"»¹t5Q1 ¼ Ä1ÃY Ë_óz÷¶Î€W›þfd¾_Õ1aÍw¡®×ŸÀ¥»•ðñï.ðÍãÏïÂü{‚Ó1:ôûÀÛ“êw³Ï{¹b=Wˆ©/iÖÅôºÀÕ#-í­b…ùaýX1ªî+ù}/¹D*¸*Ë€½Zþj¬Í0CÙÇ0¨ÆÂÑíj¦_óE3 jŒ½Cº.©1®ÉsÑŠómý6´s¢Ê«'ß¼ž1;âþÖ.ÓÖ€† óŒdÖ�&hûù{«G %q>Ϫ2[)Ý¡8n3›gðdû+Ũͪ<Þ®<âVÃÊx|k lq•½?Ê…¥f )©Žƒû�…ogcû_$Åí…uËL¡kÃo•*ðVpݘ¹^ÜÃÌÕãïþÝ?üË?þÕósë@SÆÃó[e“¬»Zü8\,¶àëAܧ§›®Ûš.¿ßÿOÿßü×wýalÙpU-úZS“¹‚zf$Eå6ˆEV»?--MÛØ<ÑóÊ¢ÕöÌl1{;¶@Û˜�F¹™‚ÇÖ«ž.f åÌdΊ"dÒ fËF®ú|3ÀrÅR<w]ã“ 8´ý§•¶=0®‰^ð[Kó“P°m&«ÌœJ?GÌ€öZ*Z3ÑL@•®ÖU‹ÃU ÄÞnT[`ßÏmY½Ûk9*–Pwµ?^Od!€‡ïUw)ŘYiÑdz½séçóGñ¼.éóâóä:ãOÍ“(hpÛé﯀ŒÉ{?�J1qcÑéª ðh\ÎýƘtÕïÕê|‡ý7?/çk §³Àx¬(5¿’õg¸Î®ûjLhß_&²®W.|ýf9ƒ’#Éßšn·OO⾺]Õq­ïZ³ëMfèÅÎsÆW>òùzÙ»&å×‰Ïø<˜<&̯öÒÿjý3³ï‹õ 1êÉ=1T¾5ÆZmWÁÈQÎr{\Ÿ«þÊÛÓåþ†ª«ýRkqüÄWõ{o÷¶H¿ßz8+oo}ÖòiKuÎLé²iPÍ¿¹¤ýú½ÇÉ6†Ö½˜Q¹â»Æ€y;FÝ>¦Ï½F÷“êxºw=bæfòðzz†Wîñ*ºÿÞ~\gxez‡lq_Éú¿^ß·‘ÕyÂç[üÏ¥üù|Ð’|kíi"=¾÷.çóýûßþã¿þ§¿m­ÕV÷bj-¥ï�™Ô²ë«23Ĭ|Ç#ÖO·"1“ì[Çüj”9ÖàúÈß &YvÿªBaõ¼•Ý@ñ–™¶~Ú¢ñ 6¼EFÀLyö~UEnfˆa0ñÁ»„Š TX`9¢}FÖbaÄÁì=SE+à ÂÞªZlg±-VbÕó³`½cc¹(Å´g¤a¿£ÅŽz.ª=@³–ì¨(åL9£fþWÍ‘‹1ìW<®¹zÓL:~_¥Àäåª~c�ñVF$O¯˜‚ZÁjÏWï«ÆŽ„y†hÃ… Â|¿<’û ³u¤ç@Òò£ËÉax+# *:÷ûB„8~+ýÜàú xðzeŠŽUK³}ÇÑ÷Q Wv=cìõô³5š¯ª eŸÎ§Š‚±²xÿœ÷£5Ì |».»Èõ™ýÞ3 çÅùŸ=—ªkÏUf½êÕ_£kÔËÝp`ü[@߬Ù{âÏo"<àuëÁÁüjÓñHg]ÏY[¯‹;FA ë \ÓuåÉ¡»@|ë‹çh=€ H „“ôÈ$î†þ;=”¨~Û\|f nyŠ‹Y£ÖÝ[D»¶õË]g ²˜IQe~mÂøÌß™_Ù:U­‡·2Â|lþ׌—}Œ¨ü{TeêÔÖ³Y,¤¬þÙ}µëPÎLÙCœåÏf±ÂUå×õ\]ÿe“ŒTgnÄ×3 LÝ×3Ö€ƒ*³§Éy:{jLÊê}ï/Š)…ãb+C¦Æ ǪýXÏŒ‰YcÖåã·ÆèËcªúÅåæùÜ¿:ïsÉbêö!�\}¯Ö Ëëób–¯º.CÆ]¶nËúOåÛú¾Ùôùû¤�»*#Q•× þªœÏ­mb€}ùÞ«ÞŸ0ݪ ±0ý»BXBF˜bm—OíCkÏ_^]*~jí…ÖÏOÇJ:@ö¼¥>+–©JñíòçPñ6»äR.zf™²U1z:êbñ®cú˜¡t ƒá"ñ ®·)ßáå|Ow%åÌÇsë[> n­¥ qÅ–V α0F묂eÊÑMø{~~U küç®>G½çöU\fÍíÕåå wPÎí¹2 àÊîÏe� €Œ'Q?Ùþ©)ü”mE1½rßjL$=·Z4¯3³ûÖÞûl¼œe>öþû|ùBˆÏkP ÐÇ•Úfñ€îŸ¬^üþª>Ø?Y?Vë¡™Wüz<n5`ëËWŒÔ¸\[{ÿÙüŒÿF;¦g®'³úaªï"¹‹> `±üü¼g¢‚ߺÌF Îͳ‡êO»®·+þêÂpc^²ãM3ã°~½ý“„Ì㑹<D Œu¦ûS¯LÍ <Ëø:šõ⌥k™^uWßÙ™®ËÌz|O ˜_ú~ñwÏ·1_*×ÇG—?µ>ÅŽ#ïêî ÇUÑ kë$+>6)ÿîUÖÉXO{Ì®UFIsùÖœ7ŽyÀ^oűPJõnZ²Ø%zÿXZ¼‚¬ºÿØçÂî r™"N¥Sí‹ë­\=éòV×ù½}Y;Pîp¬+†«ëôL¡z“Ãâº{«K¯«{OjýPê1|²òì{œõ‡¯ïÖñ¸:n×€îêwJ+òkÇ0ÞçU@Û{=î›Õ·÷STe’Î8<¸õDfÀ¢úcõ|\o ôxÃòm÷Ý÷\±¬ŸïÏÕ÷B“ªþk†EZVKÛ>ünæõ¯ƒ]¾i­µçc`èá+d©|Sz„­º8ü ÷ï÷ý<_ÚÑÄu#3 öIüsfÖøWÀÙé 1 lÔkºÞ´ �Ãzc»nRùàd¡Xq4ŽgEióÀ+\xºŠLŠ‚¾qVŒ1c™ŠÀ˜Ú¨7oÉÚ˜ë«ààQ?®SñØ =Ýøg¹s ‡hC®p¢þc€RÅb;b 1W`Lñ€€§fÂX—i[Ú5_Ï,wWcÀÌLd D.u.bAá-‘O «Z)EªTNBA‹ÏpÇâÉ�¯=–µYÌ >.Ö”UÛ¥e1LÖŒ1ó`kyœI˜—“3«õÉ7Ê5F”¿ ©úne"S´Z__ÎV`¡:2QL,“iýžy`é±ÕFª~ì<»?sÉ`ˬò@uƒó é]*™^ø]ð ·s¢¨GF$ol½7·s°¨¦SÀØ~ë® {ûízªyÁÖ¯³‹MÎ�÷óGö¯ÚÙZÉÒóù˜µÞE"['ä—Ô¿9¼þìKoåQç7ëmržk p´’Íÿð͘ÒÚP+3Њû¯ãür2Àg—n07Çâ˜ßƒ9½2ã÷çRá›)ÎÚÎó¾æu½‹~Ï2gßÙûr£{;?Œ×%òýºµw«ÏÖúØzaú\A½ 0Ô˜9ã*®÷¨‡ý¯×g+ÀUeÚU§¬¾Y½TþLñ]gu—‘qý.]¦HVåôà3€5«ßZ?å±ý²÷fÕ5ÙÚ¼ àÛ¿cµñèŒIfÿ«ûÒCy~±ùð¾˜_1³òr©2¹úÆtRõY÷\ÁëY›µagå1»¶Ÿ|ž®Æ°ÌPª\ÌW÷ÿkí÷ç†[õv[ñãï³ø7òü£c’…ÀVOßr Ë�m °êÀW[,s™¨b¦µ°©0ÄjòbétñqkžùÅ™`ŸÜ±È>Íù ³Ì^?¿l”·x¦ˆ\ ¡¬™t¹‚I±BöüºQÎ,Qƒ˜ è’Ó?x@-l1VBs×3×2³&Àm¶ðe lŸ-ÇKu#œ¹hœûSÅ´™cäÌ ; \ Ý#Mw6þ¹7Qq¹‹!ïÆœdŠÀŠ3FhQÛÄõTŠNîŠë©D4þµ Y|蚇+°ÓCYØ+`l…12÷ï<îžšV÷­ÙsYq©úIK¶ô. ã|™¬n¨·ºèË%S8òûg1~Ô÷*“Ü"zÀx“Yq_í—HÐP%çYyjž›çu¶NXmr}xû?ï|o”kBÏtW€ªJÇ]ôeŠ}Œáió“çpzNòµy6ʇRÀ˜ä®Çzøù„1j/òºO}<r@á\T?Ô\[cìYÌß «º+ÄÛH¼+î#<¯‘ÿÊmðÿHÓÅõ~ê‘a’¾^ŽžïÇ“xŸš|{:Û: {Á ­¾GXïhœ\żÂ,Øo@ÙPÄ® «ßÇšäóB¬ ÚïÑ ÷WK®¯r³2 «ÖÙùºØþÃý<*R‡â¼™|Û™Q±h@R)æbE£jßj½²ru{WUŦ4úùL‹÷Ù¶~ƘJ €Ìò{]¥m+÷PÇÞe¨R$ÇÀ±ve¹höåfûnžÏßwµ¾«‚ã3“s—ƒ«ÏYÍ ã<¹jภÜV™Ùñ{3y;>A¦qÝãIÜþšAƒ.'^_(†´/ï¾ë“­€pØ©ò·ÝŠi·/kçÖØõù]I‰¡UˆÑõY‡Œ±Éõáç(¹Ækâ<æ£€Û ˆq&žæÿ÷Žö)Ì€Ð>&Ç“—ˆ (ûÔEf7TWøðãF9’•”Ú(Ý¿À4F3c8sNb œ[ó®qCnþ­…ëEô‡ßPa …¨é ¿!{l#ÈùÕ÷Šî*g}#\a„õóÊu&*”àŠL¼>[²Ï÷C Ã׳|a;·ÆT`íTÎèbKÉGrÌ€¹Šâ7î'¥¸Ï\à©ñ²ºo2=w1æe�PíYÉ)úÙqäjLÕ‡Ê8¾²˜b 8Æó !jŸbxöûìSÈ阕`Ü^êUtX»Ö øB?bHaUÒEùçz«qž¹$­æS‚ #¸U¸xÿˆi1®8C¯ÊÌóÿœì7ˆ±‚ÞÖ{0¼l9øÀv¡â~ô¯zï›;¿ÊlÉ$r8Ú9bëÍõ`® -`a¿K~©˜z§×üŒñ£\€VÚÅúÏ_E~¶qŸ]!úëÕ72΢u樟_™gòäcó’Ø`Ô59öƒYg#•½ŸOô¼fþÙ^8Éõ* ¾/5�4¦”1*píÿ`*ÔcCl]ÇfýÒšŽ™¨ûƒ¯3•‚ÃÇÆâéë̯håWiñå¥Tî*qý{½ ”¹Ê-Ó«–òµzd Ü­�K•1¡³­À_  XuyUçY}tl¦šBçTŒfõÙ®ë•&™Ë±½®Û²Øb뱡ìùUWaõû¨þŠÏº µ—¿á«ú‹ëßÊ}=Sh øßÚN}¿­ÀÏV†ÚVfRÖî}Ì+oX± ¸ÅÌÊ­.}?Åíòã÷$þW™Ç¦ßïâ™vY¿¨çÇ] ëûÅíòëZÕ(PB`¨à1¤2W‰ßˆó›„Ä3õ L±„!ö£’2¹K_ÀÔ?™ëŠVaŒí•‰aÖ´cÌÏõÁÏf£ÝZ®hÞ#Ì‚3K ËëcŒ“8?Úÿ¨/d„=ÅußÀÀã `v“\±`-q»BÃZüóŒ¹R€šMwë.ÖWŸ¯1ä¸bÿ(òíkjÇ«0©zyU—F™«ž,½êjµfн_ ¡¦ƒ!ÀòifÙBh|áXõGt¿º¢ 2/Éý3@G© sRÈôãrLò÷úF@gVêòÔ¼ÂÆaæH(º¯r†åÖ\ø z ʉú3ú×#òðÁô“:{óùš;oˆÃrØ}™ Bîºo+²ª°;Eøœ.f\iQ JÆ<BÀ @VcÌ®sÚ¿J”k7ÅpÎò×;>› -@…ó×Ìdkmþî{WĽýxþ©yÆ;`¢æ§è=ŒŽcÐM$=¿ï˜AÉß÷⎭Œõ&–ÿ´» ×É¥ü¼¿Ïâü`lV”£•Õ¦—|<õûVæçŠÌŠ»]1—‡ö|÷�’ËŠÁý÷ž§ËeM¡·® U²bò¡¯V žÖûƒ»ó€h—L‘UUpñ|šaVUÜ+ ¨ªÐDcÌt«ÆDSíZw–IMÑ]–ªLŸ=nùy=uºm’«L ¥ ÅòîÃŒÄvT™c÷D뀄bÀeÀ7¸ÈÇGˆæï§µ0ó1œÐ•bm\ìï×2`€ýSÐr –—«c„e.oÕ}¶=÷ª¡‡—Õï_ƒvÔÞ»üùÇ Ôús¯ ¿ë寺PDìöò_¯ãùá ÖAõù. ¹•¹.ì�ZQFËošYVÎð¾Ð+nïZ/¨78o¼òØchCfØ—×óŸèyu\‘‰aöðRþ+³Ì]¾ [øÍÑ:R¼M"álYÍ\æÝääí±Åwu{n2¼KE”G�Ô°…JÁ‚®kXúhÅL3½¡<Ëãü~ÚEëG¶q¯X”¯3hÎN!83.ÓD›)Žg^ã¹ú >»ÿ“T¤eö,]Õc4£~FÀ¬—„÷]ÇŠ8;…¢ýA­Yz+W~˜O/tâ~Aî/Îäh4½¼š‹ÈÈž9vWŒ+€LærRåëÇØ!ÀËò5ržåÃú)S¨^íϹ>PX±$WÀfEQËÆƒ"#�rŽ ÊæGõÿž‘÷?*ªóuH<¯žA‘®^]ÐUÙ9g Òšlu¬U|ûvÅ@é|¿ªâ¾æRíœüt·ñƒó9~ŸùFšYsÿþ±®µ/î?î&Uà¦5nÑɘ_ʃ^Y€J3ýyz/ñ~\ZÓ±w©Ç„Ì€‡Ïãp©ï¯ˆQëûèeï~¯ð;¨˜`,=“(× wë±×ÝQ¬àêû1áŽn]x¢éü|–¹œRŒ¢}Œší ¥l8¾¤ºÐÔû]ÖÚ—)Ðê.èö14¶Љ°ê’J1(Uýj䪼k’n•Q²èÑõÞ+5ÆBÕÒkDú(~¼Ê˘‘ ¸Åúà1j÷»°«2*Wß똑“¹Ô ͽóN&€[uM˜ÍDQýcÏoe¦êvdïe÷m4_=Vg�úzg@ÙÖñYý®ðó~ÞXcòj f/д–¾~>­Ȭ¶GVV®¢=Ú•)þTÇEkM3¸bq¡t¦UÈ#÷ÍhßÀ1­7a¶•Ú£ÄÇû*Í“1Éb ìË+sì&ïm¬¯”Q6iµXcFœ‹E5±]Ý€ö/ÖÞX™X—8hŽ.rü¼f!}ó9¥Š§ B]¨~ìRÎærfWг%ñÌc.¯À0ë÷¹‚‚]5v‰6ìU—‹˜^¹,âýä:Lâ!Ü(Eô<>¡Us¥v– ¡ˆI—·?v¹¨ÚÅÊÕÝ æ®þ8C]CÎýÒÿ­[•›)f« ²µXÎŒ‹@Æ" D)Ñ5(“‡@Ñ{[ú3м½óý¸BS÷ÓcžÅ‚‹Ò÷ëGȯê¯ò+†T…±6,1žg�Fª|+g™~nOîkÿœ¼¯X³˜·‘ r¦óQÞ®XñvtѨ xrýÇò±÷Û•6« ;Å8RåÆß1»> .ß?j¼0�KÍ—ðö�©íWÿ½Éú£0¢(ÅüˆÕu[/ͱ»ú±ªz>U_{<f¦*£ »‚ö†×ôß1zýIjͰyÃ[o?Ÿ0¨¹\¶Ž`€—’Œ)¥çõj0ÎcݬHbóÝ^ExŒGS\Ö,‰õq3íßã¹"nžå+Š~¾î8t¯T­›T]žyO0÷ªß¾ü:¶ÊV×]U@dÛý€S¾Vc¡XÉ™U†ÛjÿÔî«c‘Åýž¹>Õ®!ÕqÏ·æêRµO1r×Õ~¬s[™8Q?TL{&ögµ=Ø/µöß�¬=WÝ. sÀD»xãõZ<¸d±äð»Z­ŸÖ sÑßï­L1Ì¿6?çýÃë—5Ø^UžŽ©™¹ºÝ:l3É̪Á“bf̺x>Ë\±Â|õüã6ׄã*`QׄÍ]ß$×ñ>”‘6S mŠ%Fev™È%CÚüu˜)€l¸\ b…MéÇÿB¬1)• ó¶!·–{‡d@ûØç¢beS࣢ë«ÚÁijkͨÑP¦ˆÃvLB]ÅtæXaã).ÂóVÐÕâòÛ­ßUp¼ô`œÍŒ²FޱT;2—Cñ¸Š]çy…ôˆÍÒ]+ÍãdüŸaœZ…‡gèx –[ ãj»±]-I7‹bÈ)aÀSôªô¨°Ÿ]€ÙþåL¿¨Øo±eyøÕÕò3ñóˆmW´{€tÆ«Ì9@Ö‘s˜.¨ze®²2À«Ay«ãw®GôaÀW ­(ÈP‚ ÛñÏЀˆã¬?9#3sõéÕ<Vgdó÷üïÅ)ýn`yØÎ[»r_ô±Í¯Š±Žã¤ ›7Ù<Ç +¶)äuzõýT(¼8~ÇøQï9c‚Íýljtåkÿg „ÍŸQûªý¨ú‹õ‡gî]ùs=ƺ٧ϾóÈããã8T(†ñõÆØéš ÖÏO�ÙYÔ?¾ºxC˜ù¹z¦aïý½BÓŒ‰Ïû3ۮͷƒ£ëË8Ÿc~u€´—ÓÏ·©¿"Wå[æ}¶n@`qþŸß·FÓ58Þª¸³××]#f+•cáì¸Reܯ2ÅPÁˆÏý žƒßwטuÅ`¬ˆ¿#ÉÖSÂö|]á_ÕŠ)ý„õ™Øn ­2Ûx{4 ‘­9c>î/[?ý<×�à*s©êªL—»V<¸ç¯€?uïKsExUñƒ±Ô]çqQ J ¨ç™Ýg�­ËÍ$Ü«ã¯êz/ŸÖhši=ï}À\UöÇÄÊúg°µù®â»¬ô嫱õÔzð­j[¿ïþ{Vk_ÞÙ÷G­Î­Q@Hdæ|àâ°_ÏÊÃëÆÕbË™c(ÕôØ#äy†X•j†®×%cšÝä=¤ÿúÏåK+1ÅÊ¢>€×6\'Þ\x uÚR½ë—sIQ‹¢­‘ö|~ZØŸ^íÆÛ3N2×a"î6Z$¶X‰q¦b–Q±é�æÏ?’thñÌúávݺZìÐŒa¾ÊF¿æº ógÀ¦b(‚òÖ[]‘â“VqèÜŒæÇ+·°ÚЧˆ!‚¢˜+º?=@ ˜2£Î+ž4s¬™rΠ(Õ [ÎHåØ~8‹ñ¦ÒÙøÊî«æ¼W jÉ*ƒ5øµ+Éx¼àøF…µ¿®Ú‡íbåë˜D-)Ƕӗ« &8ó²fzqó€¶3«ó]nñU3A¦­2<P@ضç}l#nô‡r@/SÀÏéf@˜1ü¹äcRåLݪdózÙ¤JþQï3ïçÁ(AÀËÎGWÏLÌ …2FT–_TYù3SþÐbÈ)ô-Ì›~uäxžõÌ0þÜ/­yÃ+#·%ëU,ÇÞ÷üŒÓïV (ó2[×( …ŠdëÕ>.XÏÚºcÞ7ÝÆƒšóul4Nò˜’vŸsLD5†ÅVfת«Dß²ÌD¥»>T€×Žï%T @t>‚®$q?nÓù|{]Úòê ®5Wb:vRV¿U ÈJ³DÝW3ÂTýxéqŸy¼È$T’t\r×W Æû­êâ]æL¸­’¹Läõ¸ŸÏV` ¬j •ƒœk@º¾o °Ë\Û®3Ìø{u•ïïªëµÌp`•Éy¿„1 œßG}7xÕëµ&‡ä¿ÚnÍDUïõ^‰ëkú~f 0Uï*àzo©2z× /ª÷Ó̵p>Z`jU3# ïÛë£\9âýƒúÿ¥ú`yïdÊÅñV&Y›˜`\>Ñãá*ѺRŒ\*naŠE)°f c–|àÂ×.ü[³ÌÊ…¸Ñ,ù”‚ÝëûÖ,­@ë ‚’E2ZÚ> E4^§åOL¯ç‹º`ÆwuÅ͵a°õ› ×?]1s1ùz}f@mV<©ó= >^c ­h¼Ü™AÖÿ9°ÓÓYEíl årÅ/WÀèç|¢ £¨?Tû³ô™…<2½jõ° /“j~Ï-à6ž‹ê,êÂdÂv"P3ÃÎá¼ég8>|Œ"¤j�Ã/3C„È•Ù|¿x\a¬$Ï Šûáäò«ûØúäåóÿ–œ÷÷EF'>^Á‚ãG >wì׬žØØ¾€UãÆ g¶z€ß ãyÅ o[taÈú«5ÍЊ\>Æ€½Í¯\àVójþß'Š‰Ã $.0~1–Ò¥q×…³«Q" 0÷#k¯wy7Î7ržoõ½œ×7Èt÷ëdÐßä01èí:ùÏßÀhæûÁ|Ñp½h_d<>ˆ÷C¹ðÎÖ¥M%~c?¢©õczá¸Ë¤ÊÌò1fê0¼Éáåúl <{Úˆb*l*LëæŽq=¤˜`JjßÍL!w(¦ŸßŸXùµÒºf%fÒÕ]e%[+Zq]UÔ+ŵºÍ’ß+ƪÌ1,7f ­³[™6ý!XOÆíQÈʽ�� �IDATýÒŠåpÉbîR…hù‘é€@žÕy rIVw½üÞcRµ›)§ ÜTå*¿/öþ°¸PñvæýX-Ÿä÷ǽ€¸ªx¦/W›6½gÚó댳 Ð]eTfíÀ~±ý³êRïº\ÕU&cf˜‚õàŒÚ<ÿ£,—{}/·ܨòãr2ƒ{/ªòyñ¼Å �¯Œe€[vÿÏ,Ýs­µb_=×\¯éÓYy߆龼ž·é¾�cìKk"|}«\*جB÷à>|j!Û™fC¶1/n¢6ê“gYΜAfÎI( U>ÝΩtµØ™bÊ¢×´ìI\ïŠT¬X…Œ·-µŠ |iK [>elÃ;+¢¯ÿ<¦ÆìªsÕ‚¾âjJ)îúó�·¼çö6&Xý=�„é¼=³€n~ÕµT–N öoÅÒ;Ë7_�9C ÛÅ�>ß~ Œt'ñ<ÇsS€WÖ–áz–ŠuTPÆÌ7[?V^–ûߊv=‚@IÌPÒ¾©±Ÿù÷ ÛŸ»øÃzdÌA[?lWæZJ¹ËŒªßí8ðíR�¯eb©t–áæç?T€Ç¢bM]Ä|§€s×3C¤âK1½Ø¸Í\µ±óxõ¾âûß^úËUȤµé}lÖî"ØŽ· yo#h:ÖãLÈU&WU¢ïxæÊùvÞ2Ü»Z“ól_!`††C3€6¤î|m28zëRêz{Êo ®PFË­B(&gÐZ×îšúß?\…²uB6¯T˜ÌQ»ìú”3Àî{ÌçMæR1®G.l£÷à^»ÿV`üéµB#ŠmOé…åÜ?XÆ4à(JáVgàÜ«ÞUf‘b œDº5¦‹®WïÕU�( s—vY;ª�WÀnA¥ŸÇ*3"sÙàúÚ|¦�Í4Åå]“þ[¯GÜ~%×ô=È€&ÅЪ1@ëíŠ]»å àÚ8ÊbF­º0Í]“ÚþòíáåT™a‡¤¾¿Tÿñö©ãœ1‹ƒZ~-[óÕuL•9¼‘Žrù³}¸¿^‰ŸkÎpSåeß*À_Ïc„Õú¥•Ë©•Ÿök† uÏ~›b޵"€¶ [ë±TŸw­ àëLJà)ƪ.sÁûÄ�¦›b·c›ï}{;áŠA;Qû~…ñÙm3Loe1<ן¹&dŠ&Ì7ê™M$CQÉ-ç‡ ›Gp•ø$˜aO8CKß,6Ä$Ú²Ò*¼Ëû<í–ӻд̵«d¨ ÅÄ)oÞ”b-'«–Ä–„ ZïÂ0f$œ\9J±ÇÆ×̤@—‚=]MÑåÇmÆ0Â~âù›<n…ëLVêZã1¡›eš¡¥zfym«J¦åŒQ~¢ãŸ·ãc´Ó»î´é,ð>ÇÈkp~n_ÆÈ¹Èy8cbòãq¡™u¬>s;�iëéE)ö«�¯o½=q½ò§ý>ú~á‚¶¿ð}ŒŸ.sµ8+À#ƒ”6ÝGr CßKfÀÀ˜§ð] euݱuÞ³ãØ¯—nõæŒÎÞžpyf#ö·]×ôò½b?r1Ǿ{ü:J¯W¾o‘ÂýÉœ·#ëJ¾¨OôX48RÐE¸B{¾L®Iý)ƒëI¸ÚVÌÕÚ¸Ö.†™aXtÿ6¥÷®bµdž²óŒÙ®ÿVQ13ÂnÇ–æï—3o³zG×#C)+|²ÝEÛ6†D&¹B¯Õ+–Ч€5‰-Õ=àdÇ“vÅ—Y¾ÇõÑ °ŒÑKUÁ¯ƒZ~U¯j,&Ý/¼Ÿ®ËãxŠöؾu&å¾÷RÅ|RëØüïwŨ¤6OUû§Î`‹û-wuÉÛ«Ÿm htÁêÓo5|¨åÏbÅe®õ<ʼnùsäÀ>ºVÌ™?ØÎ ØÙÊ\ÍúC–Þç~ ꟽÏUf¯­/¾/9ãouüfù3f\ö݈ Zê ·Õû[ñýXò«ÌcõÞ©ëØ¾L8@xM¿;ö~øìÒ]~Ãβz=ŒÝE¤Ê�[•% í]ž¤c¯M�ü×åSñ<d0óÀ?²eÁ]GUð§`#ÞxFŠU—o*S\(W‹ýß»j;…ŠÜ8ëX?¿lXÑ•"¦fõ}‚`é¨y.« +´øs¹Ðþ>tÍ\×[Ó™6[ns ìXt%ç«Ç™"5v•-X‘It6ŠË6•À€�y  ®ý:*¨ PŠud\`û¸â)ï¯U—bQùJaŽçÑž¹VcÀÓ¬xÎ\€Í2b"àùy`£5ÿ\[S�½ºß(î7Íå€[.'ñÞ!“.›ç5Ž·›ß÷Ø”"2fPÎŒ?¼OÏ?ÿ_6/ØäçŠÍ1n9 2§‹cgò|ø¾ Àes¹×š>l~B9¶ìùúz)y òõúh×ojþÏ߃HQ¯ &ƒfN?Cd#•Í?³Ë_ ”u Í»ªäÌäú|®úUg�GœÿÖ5ÈHï ôë‹aÏÁÖ¨]Gè‡ñÄÖ\ñétSúÎ�3 ¯@pý–ÏÇ}Æ@Ö€½O'ù]dßcºŽÎ×Y½fƒ’Ùï6Ð5¢ýg >Å´Uý­$›£ýF_åwdÍY·ŸßÓç±brÓˆøcñaXÎ>XM34Ð+Ì뮢ª’j5@!“õ|±Å{ƼAvÕûä Ѫ¬È\€›ö¹#}•q“Õ‹¹‹1«È¾Â®à®1êãiÕå_ (ÍÚQUܪöÖcì¬*È·2 Õ}c o=&˜J§䘯 ¬=¬ÝxýàŽc@² l×ë_­ïšÔª«çUºø»—=kÀºbHmeØ^a¾Þþ>ïcRçßA,g•1¼O¿±yÈËñàI] v!̱0=¦Ëbõëä>4Ø$«·¹_sMú¶”ìGñ¿]†Ç5ÀLÉÊF ê’­µ9ö½…\æ·ûäWõñékíh©b”[FãÆÝ¾ð]8+®ævèújzªŠ)6]W ”0–ÄS­·ÜþÏ=0×ÃÇÜx2éÐ¥¢²¨–Û‘â"úGŒÓù¹?U¯žgLŒjúÊû‰å[F•Ù[1Kn×y=™«0ÎèÈ-¢³öÄÀ‰î¿LaÆ€nç®Þn¢™2\Ñ5òéyuŸK«Tó¼)F °ÀéÉ]·‚åûçÕ¿ ÎÀNÔ²rð¾C4ô–ç†Ö|ìÀÑNÏœ™Ó{E22θÂc4áx€TÌÈy'–Q”•£ÒE±¡œW@ôœÎ3 ½¬2Â×Ê9'@ºÌæËÔÃ~†,mŒÇÁE@™3äü¸šû›1ôÐТú<[^õû¼n{LÊa�~¿qtåÛu„5€1p/åØuÆÕ™\ >èjZÅÃõ 2]^þÛëà‘–¯ –…¡ÔM8Ð_÷†0jþµë4Ô°Ì�å ®gíVõ®ÉP ÜÖžÑ~J!¢,Áu=V |Zóï«^Çáú!¼ÖäãÂ?( ØÊZX½Þ° Mµ «Õ…+:•kDB@IM±ªÓšé³zß^^ƬÂôØ/x^üxñ…ýI¬ ]^Ùy~]3Ôìû‹ŠëÌ–¶¨_>O¨ç¹S¢ŸÕõZÖÎXὪPßšn¯š¬ªù±?ð:ï—Cy(Ù6þâ{¬úCß/sM¿W«@r>¿eý¢‘Êå`Õµæ)¼^eâ®ÆÔ«xÒºõSÌ´\•:óo+£²ú>ªu㪋Q¼OfX“Õ‹×3‹á¥ÛÅÛ·:Ox�:kOöü>·Vbr…’ÅìêÌ´‰¡Öÿ«ÀÊ]])¾�0¿~ZŒ!†ù3•Û³Oâø[óïcŽÝä=ÄÓ¬Ú+*‡° àüAcZ¶a`®ƒ<€¤'¦­–Ís~¥°žÛÌbžY¼Úúž¤‚Îö*&Bj;Æž€16¥3È b”=åL5Ò¯CIã|¬(¸Õd0Âø–÷@Ê{"åÏåÌãboÑ8¹¶õqTÒ*–åÛg(Òû¸ó̰›Ø˜Èø˜*(9'Š+¯PšïÏ,5WpU@MÇ ªXäW,Ð+ ÊÈcÌDÌ‹¹^‘«²¨^Ì?bÈû õ1)Já?Ïè¢J1¿p\òù·$æ 2>2à@•ï…­¯ênâ]b¢‹:5¾À”ª<ÝÜO3ð’1µùïåU] î5@ˆßÓsšŽ15õøª¹nžŸ/?Œ‘É\^úyùôzlÛwró Þ1ã[KÆ0ª|U,.t¡ 2±ú÷ ¤æã™iŽ .û€U>£°ú¼1<ÀWf˜¤˜Ò>æW¿2Å8`46¤ÓëÒxLRÆFà•­3«0sâ÷ ëÇßÍ„Á‹ý|pyÃ<Uïìû¼rÞ*­Æ(©YtgŠ| !ãH§8Áë=`S]Ì¿’uWˆ3¤ÿs€¢ÊpÑL[]-êò¸«0åÒ™ÊÒüZ?Cøýª t¥ðÊcûÔ˜ùsæ..×¥Z_Ûy ˜5f”bºRl­ÝjÞ\ÕVÕãc†Ž.gßü§òy�¸êZnMð½\ehi`U•—à|Þò² °_i‡÷³Œ.?¯¬2ïó}=yùÊ�c5–Ÿ*Û1ŸÆw?«wÌäZÔÖ™^q{õxTç¹ú>òûeãÜõœ¶º¦ÅãÚºhh«¦SLißžUÀMÉ*ð„Œ1<_À¾aÿÃ,<ŸÅN{ø»ÿõ¿üÇ?þÕó³Æ|–C,U±‹é†p&Xž¾µÖÚŸ½ÿ“¿x÷Í+1fMm».|£˜½È6–R“nCR¥žúò»T-9c†Ìè?–Ž1K˜BüLШX¶À¡Þ˜+ �].’ü¨€éé¨kFd€ÅrÅ•RT5w]õüÍøè,Ä­â¬3ÓŽæz¿ï`¢M?zÀÖ÷§ÐnxN4] òù§ãÞºÒÒ®P¸ë-T´ãûæiö}Ÿ]¢+ëŸfê}*÷—꿵ûngºTÆÅRš@sßãˆ)Ê�¾È²}uÜFíÆr#—Õö³ó¨ÈUõ÷ã½Æ4Œê/ÏDæïÝ kë<soÙÛ Rð»xc ]{ŽyéãÚ Ìó“bÜÌ÷õ†%¹‹Òê÷â߉Рƒkª*åÍßåÙÕà­œÁàê=~;L.ÿfÙï5à´×òz~\§ðõ‹¯'öCƒ"®” Ħc}QÀ+~ÎuÀ¿³·ÖzF˜b ²zDóäVÆxMbE@Î8û Ë@\¯Öo­­|¿ûþ씤SíÛæò¦ªXÝ.w5瑏뻎zpÀÊïCƒaÕ•\¾/ŽÊ9HÅÚ6—vè 2Wfåõtµzù~ÏÊáÀb=FU\mÿóoÅô5Áúêt¶þ©Ø:ùyuß­íÈžó6׆õrªãÆ–“ÇÜ:޳~Ü—ï}êïa—j?½•Ä ñkºÎªÎÇûÚ³ÕuåÛ‡Õö©~ŠË­Ï=ÝÞqsŸïYµÜúõ{I<ÿ’cUßj:}~Sûÿþ·ÿø/þéo×;¡Iƒ,KW(­Ï,—‰iöò/1Í~ûç¿ùëw3»L쌰ŸdS¿5éœe½AØ!CL_W÷­w~ƒ`-Ž×a‡ºdܘâ̽àTŠrî²ï¬~KÙ梋¥CE¦·[Æzj&L,>¿Tì<‰cDqƒ®§ôJaåe]…Ì®Çð_+ÄZ󮇢c�a7àÌöÃlá:+ú˜K˜9ý•(Ìøý­èX ¹Kª˜1a´žYä-[fWZ3³'r‘5\%Ååi×cþ}DWvœq¦™G Êcý…LÖ¾.œ™™3_¶¦Qùƒ‡Ý‡?7Ř÷YaÚ] çWÃǤ<Æ0kAº–\gý’Ìa¬*‚+ÀÛÜ^–®2>ªŒ­·ÂÃÛ3¤¹âŸëcãÀûxŽÜ•èpíiמië7Â}þ›ë‡®NÕúkÅ•n•Yœ½ÿ™ “ë©éïK÷(Ê™ÿÀt|ýþ#g¶fÕö’Þþ7¹nx"å±þ³í»¼üø'÷TéÕÓ&Ø$fÕÌú)¨†ŒñÎç)týj=.›j‡TÖãºÊäærÿ(Cá83 n>éç~fã{Ï{ƒÀMÝ<¬jñõKìÂ)så”[üf-Éœ^««w_ÂPñ£A±Ëºzì¥ÕzÅŠxå*H+òk£š9–½wµv¬[´s´ï÷­Lœª+?P¸Z/å ®‰ü±E|îrŒ×ß·+SP¢‚¸ÚŸ5©2·2órªók/ù8Ícý(Æ 2kŒO”·7tP÷©¹rCWžÎŠq÷Oæ‚ö Æ;Î_YoðdÀÇšè÷õ^ã¡Ê¼Q€Q ˆÒïV— ¨ïåeß›*sL¹Våï÷AŽËêw·*üûŸå?,Ž‹,”QàªǹÁE­_Öó`ªàJñ›JºB9Š9V*_åk‚A†�Û; €½ÈOð?šöÉþ#ÃL�d «2Æêò©x¾¶ò¾éùÿ=˜c]b ט’Ê\Þa93 Qq}WuÍTÀºDŠRkÙï™2ÜuÝ €å"J˜/Sü.”ž¡žPÃëŒÍ€s©øDÏû6º@z‚òg—GdÀÅ#*úzúPë–í ðêÀ n«� >®ÓÂǃÈ™K7¯ð.™"{œ×1õæñ6,¤ý8æ ._ï~_[ß~~üGýç]«Uû³;'+'+OÕçÞ@G¦xVí\í—è¼b>m¢²þ©”WTŒ‡í¼£"S@g㥿¯¼ž Ò�ºšgS%Tèûë8³ –s˜¾[©PëüÎÚt1³‘ÍU "Èæ|×–gf°Ìê9Ý,ã»ÆŸ ¸f÷¡!C,Žžäc~z€kahê­b±*1.¦½A‘qQý˜Q±¿´Kã­Œ¿¹|¶^Åñ\]¯T¾O*æëü^Ùq Ü3Œ£ó˺íDïWwÍl¥âòq¥þW]Ø¨ãªø|™é ýUÍ1ÁZ±œ\,¤úoÕò¾Î©ºÊRÀ\æêHí÷¹bÍ3 �§\<ªë{]U…à¸_L°UæW–O=µö¢(—’Þu¯ßÖX`u—fÛ™ùs\U4×^˯L‰¨ÞãЯǒZíêûaû¥úÞil ˆ°Ç-9Vó¼7 ·ç3tù<“ÍkÏOõ_ý|µ¼j½ø|’1ïÔ*f ÈÎcÉa~|[@¶:ä€`œ>åYû^`;÷3:×î‡@iý{m œäs%ýtZMo=o€® SõT® @†�Û`ˆýŠû ÎÿîàzM×c²«€¡•0ÈÃL÷cRŽO÷-üW],Zñö·ü¸Ë½6Šu„8³À/Ô¼ñ}ß*�£jAW0,¶Â¬cým7ô>ƃí?oq¯€Ã�0£®}ZËâ)PÐ¥P3ÿYn¬èÕ5©(†®¯ 7k±õb”X†*ìðz%Ç �àóÛ¥¦p?ËúDýyiçPé]óYÀwâ# «¹ë^¡mëí-蟦ûÌ1Õcăž)2#ÆàÎî9Õ€P¿àáÏ›3ùØÿÜŽ¹<5V «çcƇ—U HåSõQ.ËÖ\ki@¸…ç×¹µ÷×_·ãÝ—íûá]r†gÂEŠOû=ôå·fç¹^³KV%s¡}ówv6ðõõóÏíX¤¨÷{u\c>¶Þéç³HÈðÂï›ÚÐ^ D.æü\ÆàFÆØÌäVŒòþ¯ fT?¢ANð©X¬]ñõ,æùg^²X¸'×þ»2—Ï\·f™ßó43ìÊæß HŸ‡Áÿn]!bîà:?bî¬ÌŸ™! Þ÷øuËïû§Êã’¹¶ÉV£œêN®Ö#iy`ì(þ-å^z†ÀšE¿V´ZÅ[‹G1Ð|짳ȯ€²X±¬úKÇhBEöI\Ïú³ ì ÄŒ¹u %3„iâzVŽjÏêû^UèÞ$c¨xÅ´bfíèéÕ8ãã¶Þî¬]Õö¯IÝÀ Ê á² ¯ VÛUïÅø‰™@U†Ö/3È}hH°°\ûT™ayl+^¾®ê?ïÜ×€»a tß÷QÓÕvªúfïÉê÷jë8ËRkz~äåÖ¿WYû«÷Årì¸Afm=ܹµê‹ŒàD®‡.'1�ZO·�Ø!í2L³çóŒºTœ\&Š;½ž€ë'Å +7!feÀ×WIº¯\º~¿j=ù§6‚cì~̱mH¶²ð¸N/ÎMq3^<ËR¹÷‹…€ }«³Â6Ú\!ÇËó€WfAHÏ ø7ǃÀ�^¨ˆ" /cqÝ<`&ûq™+${ÿ£»Žé¬ë&¼_ƒó–6/QÑ83ÃTL•ù™+H¼ÄØñöª?ë–Þ«é­‹E~“Ž/Èf¤79½*Йb|V¬·é]>ŽÑ´@0€ ŸW.ßÐÞöSƒrü¼dË‹]š ±.£š,7W(Ôh¹ëÖGñŸ)`Qª ¬˜ùäqý½â$2•Kϓȇ r>ÿ*2jèêÔw¹åcÎõöŒ=[?,3 `¼÷ƒÊª¾ÜÃ<(€ØÖ³HGL+z<dóíÜ¿¾Þ±à÷H¹ä 2bàθºNßG_É÷´—kïwÏ©dšE©GË+xÔtóÌ÷þÿ0¯|^Q†Gƒ)©¾w*=“Ùu72­ÊHŸö*­·œgìx>Á8T1:l¿ÍÇŒ!6Žïm!÷‡ÞïœE~ï‚uMªŠ›( L‹ Wù¾)'1×ëÇÈ»ŸAeÜ/ã:7¨Tç½ì}~™µÑôºÞü~±ÔL¤}.Ž´…~Õud ¨¨zU]†Uß_[þ!-'Ò2†ŠÚðxÍò?(Ö€DÝŸÊ�b+pTdzü{™Šª<çø¿‚}›M¿µ¿j�g„ÅÀúº‹½ø:Žo°°Zîšä.õº AÅÚû“»tT÷Ÿ¿úþgóW.UWª«Ïƒ3KµAÉ*pYõ~ÙÇpÕíÎô7{6~ß|½´z?¬oôUüUæu(_IFV—ÎÌR® ûyË‹ºd Òc¾U†Y­Ý÷?þ—ÿøÇ¿z~^Îù»—ÿŸ�(ëL2uÞ1Çî,U„Q»jT 2¬÷'q^]ç@Üûb¬3&^þ?n.¡=¼¿ý?¹Õc:þ4c;§ëy¿dõ¬¶ãCkíýKº/Óqù?¼¤ûéæó]Æõï^þx©×w %nǯå|„c+ãüÜ]/Ýo³Ìíý Λü/õzþ·ëá;{ŸçÜu“ÓOíùäïÇs=¾~¾=‡?@ú¯_ÿ�ý5ŸŸÇÕ×¢¿š(g.ouüªû|é3ù”“o­=üåK/ÿ{{_s¾0Ç¿IÿýëùÛñïçvå|Ïêõð—·|ÏÿÞöGχíéå¶v«O¿^øËöýkºç±ÞmÔoºïï¡ë¾©çïçòûq¿¿©mïHÿñ%¿O<¾úáá/§û÷1õÆûœÏÞ§çå-Œ3S¬Ï$fœ|„óüs4å}|ynv<™óÓ¸5ÏÁÔÇ_£ãäû9ýTÞ_á½™ÒMãâ{—¿×·Aú~|Ñz4ÿ¾özMãÔôóTî÷.6¯ l—VÓµ Ÿ·¿ÊÿØZûÃËwäkø¾¼~W¦ïÏ|ü5¦{€ïøô= Û3åûø’¯Ÿ7Çm×zŽ®‹TºÖâõTO?»Ž©ˆÊÏmº/pöýË}¿´Lù¸ž›¯·f×[ìx–}Ï%ß'|x¹þ±µç/._k Öé^®¤×·ËÜNì—­íËûWåßæÁ£ËvWû/Rݯ¢a'ÄÚþÝËéŸ^þ__Ò½C9¿³¥¦¡ ¶K· E3¨É‚•Óü É=_ù6KDÅ”Põƒ½ßKªÁëÛ°¬ÆúfõÜÛ*?=?µGÕ÷Þå÷c•N•·Ú/ÕôY{ZRNÖoªMœÏÞß0=ö·*¯šnAJ÷kÞmϤÈÍž –³šnS{ªÒÛÑšœJåWçÝ Ï5ë§êøÝ*øþ¼É<^è3?µÆßçêü_H·k|-|‡Vû!Ì×åŽë†~={ß³y²úýR÷[Ç7µ3Õù?,gu}Gæçl^mÏ®ïÕoÿü7ýîoö�b]~WM¸•I¦ÊI$Æ£ìGYN|¡ðôLá•»0ëRUp5¿±î€WÀ°}ïí†vʧï¯ê)´¶J†¼bç;Pœü`Î7P |™€+®Ð뀒ÐjýÿƒÈ7êÉú[J¾@¹ €Sí«=™˜ò&Åc¦�mþc»)6g ìë—üëdzâ±çïå}„üm:nS9³d÷s÷oùó_Q�ïî÷VJŒâžä õIàæ)«À72•g÷¨ÈÇú@î”c%L¨r‚ú‘ûÐþ5å Ö|}‚z«ö�û‹ŒxÿVIGž¯¿o\: UGí5¿íÇQ¿©¼ ÀêÀO›ïö©Ç”Î�£½ÿZ³À¹ošÌ¸ &|Þ¡¾k€zܵÍçãûÖWïÓDyLæùøœÿجAÅ œ½@|­µöXµ9Ÿªù®�¬O†(Õï@kÀb�FèAYû.tùÁ]·¢ÖCh€ã14è¹µçÓÞžï=Y?©~XlãהּÚ˺ Ìð|?~x¸ž¿X€«1Cº{¬‡+RƸÁ ,?½œ¯îŸ°ÝöøÇ—ã¯Ä¾ wc]Ô¾U�`Uùé^õ{ dW4F¡–¾™ÂãŽÀU¦èV îUYUÐí½ï^Àdï}Vö¡B©ËV ¤ª0^¨ŸRtg@˜êÓØð�� �IDATŸ%`,Pà®sô|vœI¦h �ÂMý±ëóoÅô[ûÕòîˆVÌ&Êéíh/íØÚoªÌ}7(âÃûî¨wéýWùw�J! p¯ç°(ÀòK²¨ÙúÝzk 6»ß[}o·æ¯Ž3õþ¬Îóª>]öº”ÚÓeƒáÑÒóÄþQß½ßþùoþÕ»¿™]&n•Ÿà_¦ëÌ1We±QÂó*Ý¢ëEÍ ³çýõOâ?›î ü+A ,K]ÿÿ(³×ZÔR•�aŸX>c±Ú¨pػџ3pÄbðé ”ay|S�p å÷$}?¶íùáõ¯³úz‹è®²÷õó�߬¸˜ÿ?4«8«�*³ÂÈ*ž@Ø„âîá»Fe:Ͻ±rZ<nÿ�Œ¶W êå|?Fæ×^êñÊèéºB´ŸïåtŨ¨'_ŒÍõËÂê}(†…~Eù(Ž90òýëñ$]á¯�¤ °ñ�Oo�LÜä÷ÿ÷¢Ýˆ#b€œ 0ù~þï�–¹ÞÄÿSo ö~ €(ÏP›ÊA ¬1` }¶ž¦ÿH»Ë7ÕW1­y7€¥©Ú \MÏgzÎÈHûÞÕ×ÖcäŸÊ™úë÷¯ý41ȦþB í÷¬|Ó¯Í<ç.!“f¬~‘Iˆ²ú=Uõ^©Ç é>ˆ|lÿÃ4ÿ–æ91OKf�_ø]{­Â>N÷{½NêIûá™Hó÷½Góþû–Zó†0]"æOf°cÇÇw¯ÿíåÿƒùÿ!ù.tx¿Ó?a³!k/2Þü:Tÿâ~Èú Å(°3šõüßÎçÛ_¬®«ë€Ê}ü¾¥`„á~Gµ§Ê ãǸ‘Þ „õý£¼va?%ÿo$¨¨h Ð 5Š1ö +ŸHIÑJÒÓë$ö|UÅ_V/êÂ8ä~ô˜ä[­W¿µÿÔùÏI:L¯ú#Sà«tý|é> ýTêßÂ85вB¹(E@™´·‰óazröÆ`QŠÆIA¨UàŠ2^Hºªâ» èªûeõ ¼ç«÷©¶ëMÚC€5O•˜Š“‚{+¤Ô¾€-ËÎKî>;é›è_¤ ( =hÁDÞKu?5gïïRoMW¸öŽ#Ò/«ùKí#ó~ã“öwæ’0ˆ¦ÚUú.éÒ|ßÓ†J6›Áw”®Óö3ÄRÉ\C sløÂûdRÝ0m îF$v)86ìŸàØæS–¿‘ÜK1Ö^€®Y‘‡cß¾žO»Nü0¬=LyßJPÕ¢—]× 2Ûï¥K´hþ]Y¦d¼\_ïž.c¢aûZË-È{~ÆkP.K�* S¬±üÂ’Ÿ¹j\bB)ÙËõ™‰Ö­ ` ]4Î�>—¹\d¦±ôÙ{»Ê´P骀Ûj>Å`iÂe"êêqõ=Ÿ˜LÈÂúMé¾Oúã÷PNÈ< ÀØ”.pYiú ë‡@c€&ÆþLù ò÷òã÷š>×~Ý0Ç,�4\ú¦ ©Ö#ô»w­E@iÌ fýS•ê÷«Ýù|õzk± B%s:dl±òð~sýf…~ÜÚ˜o�‹¥§íÀy_õWÁµáêqkŒIcûS¹4Œ¤²Î›×;[˱�–7±ë å*Ú2à;p–­+Ð¥4öï&X&}:W“ †XkΕø´¾õbU¹3leßÐÛÕ¦ö~YdråÇÛd7l«+ÄL`ûÓ®Væ­ð Pª@«º¦©2Wd+#kÉòú \áíjÇVÙÁÚÛÏKŒ‘¶½_–~,Üo+³g•1²jÉÞ Û’î ˜B»,ô ²•‰SßV™Eʵ"ʽ\›Ý…á¹aþüU¼¿¦"mwaÞ¿w;JÏ ÇëÂûz/šY¿ÜŵñB?îu-ºõ~÷”9¹ê‚±úžÖcwqíxÇ~yS&ü†õiiœ÷çñ?ü_7†ØÃÿóÿZ@Œ ÆÛäw/ÿ?‰ó ®#0†>Ö¥îUQÀWÆ$Û.™E$e6Ý=\(¾1 ÆFxr-óPM Ê»+à¦GEKkœqu“ï^™f1@5\ýØtÚÅPƒë±%÷w²¢~Síb±Íªå3E—Œi†å JYì›üA¾ùºrµõ*“l¾þugšAþ¯'¦BÔ!p1Ðägé°üù�·Uq¾êbjpS²µ^A€d�) X!@6MF&ÆStñgÒÆ½5 ca=”Ûšcò¡ËAS.gþ! Fc³ pÔ›—Ðu¦IgŽk†[Ò­¾OÕrö2C*�}¥½È¸¥óâtlæ/0$@ƒˆWf-º.Äó­Åóüd(1—ïÚ`� êõOkèª===–S™×´kDtí¯Ûö|'Æ‹vX1̨¸tDFW´îbÀ˜’­A9Ï_nëÙ‡÷ÎU¢Iÿðþ5}l—Dã"^o×c�kÝå!J“Ùž¯*þ\®Q~‚|¿Ãó?»T™2(«ŠíŸ XªºÖ E)«® [KW¿´â‰2üv�˜Õþ¼+ �t]ÞÊ…^i¼ŠÏêýWû¡W]–î}o—\õŠÉU£÷GY„.Ö¶ÆÆZu5—¹Ûc¯*÷„ª@ð]dÃüó&Šú ®‚7Õï \Ì® ÕÿWä…ò·>Ç{jôvµ—veç÷~÷·Ê›�JÕëA}ºl[ÛýÝ_­?wÝeâ+ v7 åwpüS’®_ï�Ùkú¾©ZöeL³Eà %Òšóu_ݪc+šéÃ7°uËP-|ã®`(ó ]1>ƒK ’/ BþüÅkYðrÝž.[1`f2tuädÕþG†š’:0VU1€o´Ç»fZUüVº0Ó¢tB1+7̇×'¦ZkC�¯_ÿØn âÓ1ÐX=çr££ÛŒe[è-ɇ²÷>ÕòW‚¬œ½�|­Ì•�GÊœ*0ƒ(0ˆ€R\ßì~Ȫ29ù}ï;«‰ëÕöVë½C_º¿ØC`½Çر­0V#žïå!�Ö¬¯'µás@¦´#Ø”£b}=g±®¶3s ¦Ö=݃,—1ŽfÆUn@Ó%c¾g 0t%¯WVb­JÌðêâ×¶Ý*6X_·~š×­&æî=^JP¨€Ãpõcûk56ò½˜_]î|)ƒÉªÇ`|ýîå_·äüÞÖ¬»ZUì7HŸÉ¦˜IÓõ­Œ¥Ìâý^–éÕûÿ\å–î·;ë1kè} ãîMG“ë¸RŒ“…óY;–d‡Br5æ‹J÷VŠ÷_À¹³5ˆ·T¿�.œ·î[ê®ïyËÇÛÖrJ† Y{ ®D—€½ŒÙV�´ïÅè{+ÆÛ[̓oò>o¸~×÷ c¨ë’]ïñál¼7q}«leRW’bºfß9ˆ½ÃŒwG<‚ÿ,ÝëqÀ”öÌ÷ûNYe†!£ì«Ôþ*Æc‘áñ— 2s¢5µ¡ÿ4§{† 8‰IfÚ?dßÎ …&bôt¤_|»W(*ÿŠô|ܰ›X…#ZDÏ18ú|„yE‹ålµBÎÇDÁÿLø±i³ g÷• ¶™a$ícÇ4–(r[Šâ¯…B·c˜b µfs=:°õuWhC{™ëF”M»xœc°Eýñ‡$ý\¯½Lu¬òg guÿ­ŠË­Ìœô_3 ‚óÓ,lq!èï¯Ú¡ÚƒåUÆc¥ÜIy«÷ɾÑøcã»:~Ô{׊ç³öP&*õà²öu^ ]»þ�þ}Þêó›bvµé:ÖW2½ˆáÂÇù|ï»Â &ú¿7Ó³§C˜Z§Í†"[ ò˜XI¬Ï@ìuŒÊ/4Ìòë½8ÆZÅ%d­¾^öŒžÚtÌË3ëÒžßÄ�ûÐþ¿ö¾&æÖãH«Ža„çjbÇqì N¢xg1Ž#'ö¹ß$÷ÞH,F‚ßo‹Y±‰ B"A$„V,`s%,¢Abü3‰¿ïرcÛ#ä(? '×ñŒ¸1¡ç°8Ýçí~ºžªê~ßso§6çô_uUõïÛÕUÝXˆõ/Ö~-î#c­¼‹eÞw½.êÛï©£® 7©7ÏÞ¼öÂ^|Ø›IÕ/Å›!ê@øL#òŠrPÂÞ–0ñ ÖÃÞº0Þ*ªøVLÔ7T”·V¢`¬�zߨPÏq¢oØ0|ÊE ¿ªX”‹¾É‚aµi¡ƒoC>¬^3?†íå¤zŠïÀqô +–Î,ŠBoÔÌ_^9ƒ_óí%ƒ_Ö>ÞKê<f¼‡ó’9oC,=_Íê÷Fþ‹_ñû'Z^^ÖÊ.1±ßzrˆZlc¿füu)üd~?P×É(_ ÞÞ~†íÒKŠ!åCã¨Ø'˜|ãÒÛ—˜r@:ú¾e)Ayò`®Mú ˆÎ7l¾Cz{ç/u?Àúõê­ï|\&âB`úÂ\Öéwãį!}ïb‘Y€-lÆn4"Ìw½è¹XÜAk©ãùì¿â”oãsÓ•Y˜U`xã¶P°U 2|ÃAqK²ˆ¥†öæTxrfõîàj*÷t*‡7¸¹bG¿1î»Xôä"P.*¯´~&rÝò$– ÊÛf¡|QŽÌÕW‚K ³,(ÐR¬äwo©QÐÁôÑEÙ©Lã?s…¦p#”å÷|Bz#ß‚NÍÂÕ£¥÷Z$1uýØ«œë’A¯%h¯¥ŸWߨ«ÌüÖV=¥=ýODzɲøÔèb ²KD!߸‚•z7Š/b‰ÚÌs8ß¡EW(Ÿ8ýb –û°æjÎsˆë?‚ÞžÞúÛZnÕ® ‘oövZôí³«Àgßr•\Êóko´öŽë@¹ …–_Ïhù¶V{†ÁsuˆùNhù>ÏB˱ôŒ~çìM0¿AO#Ä a#·¢®¸zÞ¨Ë/ÃÒF4ü®Ž7„0^Hú\èuÑ(‘|½.ò:,–²ôè‚v‹Â¡Þœ'ÿA\Æe˜!¯Q׉,êêpË„¨… ³Ü²LÊmà­À¥\Ñ1úqQëñÙ] ê]ÀÝ*˜e™¥ôŸQK3)ñŽÒ Þ®[º¼ Ñ~5ƒÞ ]íÞ1?™|u¸¬èœ;Žnƒ gä'ÄLJî¹ë«•…˜¢1Wo.  ü€ › '~ á}~vs°7Þs'ý½è‡©ýÊ,ÄNàM2íƒýTÁ£}€/íòE9P,nÜæƒ ä{R€ùT<µåZÌòNƒëN¸Œ·(ʃ6¼I<Å_UñMåŸÞã¯]q‹±ú€YŒù.¥*÷4´ƒ#®:™eT––v¬>TLž)–]êÁ ,3 3 Ûv€ – ϳz‹i JK­J¡Tp‹(à €»´ºJЫv7Þ5…VŽgo¡‚.Z¨0¹?_üŽZ$EaŽåÃWþF-ë¤3}Ô…`Ä‚]õiòa|±ð©ó+t%•‹fq©AÎÇøÄ·Ÿ‡ùçyPá›\ûzÀà%ÅòI³,}-©�OI_Ÿ*õ5óNôM¯¢¼Ö>¥"Ìk—ëJþ3¥<ö/k¼•–^Z½Öz‚–Þxfžö¤èB—„9ýò3K°ŒÇ¾ Ã\ ¢âìéf]µäåY.¡\Ëz{/6ÔaÕ¢+¿ñUå+Ê£‚«P„1K²É£=Ÿô}W0 “¥]íâ)ʸËCÏþ2<v>fáå}/‰“Ï¢Øj\#â›_ðý·‡ß[×v˜EDòêUË7uñ�BÅ_äï½Ù>tÑ6ðUô` éšF»V7ß½Þ 'O.&¿–R*þ¢ïÂuˆŽöéµTÁ|u™èÑp=˜Åç,…–G?ãûµáêtV=B,°~ƒÓ2U)¯Ê ù ÷Z.²sÛK¯¥‰q5ã�Üœ¯:U:<>fX¼Œ‚yáÀàÛTT–‹âà ÍgÞø°XŒZª³ð¨âÏã#ÿŽÎ/C|‹£`Ÿ«_ñøñú_qQË…,DZüûª<„ÿÞÛpXnÿ†˜‚ØCh6àRJ ëô»Ÿ5É¿r'ðáäÝ4$ù.¦øóU~;,ìf%¿q9÷j]-©Îh¼¤xQãEI¾2fñpeo)v]´ÇÌÕ7# ŽËCÄ‚�ÒÆ•¿šÒ{o·.‘þ¾·G°üÓ‰lÙÆÞ áò)ùGüZÔú“‡ëÓ ¤HÀ7À<—^HǪuu¥*Ð<{“ŒÐs‰Xj …ÍóÌB#s­v rì-¢’þJžðæÚžn&Gà7Ó­)H"ŠŸò­µ^ «Hº¥XÃzôZ.X¤•rÐ,›r>Ë’*ê³” síéõF*|*E4ðµïÿ†KT¯ÿŠð·ºJ<%~j¡Uä»NêS祀%•*_¥žÌgÔ¢kuÑëÓ\²üÖxiß^ªñ·À×A}–R¸N£Âìiu?p¦X†!?¥BO“Ã\ú„Â@Wû»¬Ø~ñIÝ?o->k¸’ø~fQ¾Û·gý~¯•oùèÖã9Ÿ‘üž§ ÏrÌ=8s..nÒïÀõ!ÂÚÁ³‘CªÐ0\h ¤‹VÞ(·È{¯>´·Ê†Þ’ê(¿ÔÍòCY–EßЙeÉÕñ–J× ëêë’K€Î¥TKY…`î›9L>Ò)ÿ,}Tyxo0ùyËæ�– !K™Àl•Þkq³ …™÷†Ð_à-CïbBÔ‚Y•§Q_Ôu¢Ê ž ï€|<9EÓ©¯·³ôCYvÈÁÛ ñÉ ×’é�r3åÐû¶Y`?²hQ¾k–bÏ:Í>É€ÏÑ™�<øÍFkS—gQF\.žC|ôfäòŠÃ+N<*¼ôG¶Ø¥ ëµÐ°óOb§RÞèmo®*.+(n&«å—Ë""zÓÓÙgÎü–ñOI×¼ÒZžá¯ws»>°koÎ_…ƒ>ÿƸ&Wö&¾Ñ¢½q2ª8°ZÏ ‹ ”¿fQÕð«XtH*§ö#ö¦S„a<¼”éi,}ˆÅ°—3há"¢¼¡VX²HQïóŠk9åM¤âW=èVV{jo#Ur(øËùKy1Ë4Ë’(+Êß’_F·ßÈ_¡ã´øÕÚQ“ZöíßœRêW-a\hr+ ÐNÿš%QŽ·ê+Aã‡Ñ…ô”Šmlïüæ_ãJ0çGK2BŸ(ãQ^̧Æ+ü3ËSt•(eëqè9S,ÏÊz˜e0Û Å’f©uJòkOìmK_1ÄÞü|š®kú…½ÎŠü¹¾œ—®[Šio•ázˆò(å®Ñ]Óï[¼Îƒj_¶O9Œ® ÑB,+Îr|õX/=QW%xõàE(ŒŸðÔûÕ³°¥‚í™âœ¸Dd–_ÞwÌl‹0òݵN¿ùbä&‡ ’6Nx&°3¼é®Ü õnÚ›7d£EÑ÷x7š»*¸ÍÊ{oG0>GߦPñ X"¨T›Ü£²Xˆº|Tèê²ÌSâ»\Ôõö§èÓJ><ëzCÈã?ª@ @ôÍ»!:õö*ÂÌ·lx¨pZ�¼·½Ìù; ”C¯kÙ¨Bé ðÃÒC–7üj^3ÞÂ4Ëò@º˜… *˜¥ZÒ™r Xn3<]–MÒ¶‹g1ìáUa2¸î(‘&ËÇ!W¥^>ï"OÇþñ10dŠ%`ÔÒ+ žÅ«)Ü'(ûÖž½¯¬ü\Ë<u¼Ü!ÈØ@c<ú_ÔG-ýpYc>¦ð"&7Àeº\ô\(z˜­œF?xërÌÅâ(È¢ÀSï?p`€7z³ëDõC¹p™xeF<·¶üæ­�=À¶,(ÎH:ºÚÉ[åW>(ó\Õ–VWé¯^þjs�Xóáøåx|;iì7ó­¹²bò´\9Õò«å¤œj 7ij?ðR,LÌ6åM2Th1EZˆ¨ñè²°8 GWeª+?<p/üOK<ÅIGYŸÖ¿P¡P*bPáQþfK´RQ#¢(Ò K2ÍâéÖ¯ÈõT¸B­¤Sã³´È+(î¬7¨Ð5¦Æ¦Èd®/ËöB9KQ(øKEQٯʷ¬ÐeÒe)fžß¶.EKy_º/|SK þägòA…ÖóÈw¡¨­~A¾ZzÔÂTï­?£žëV:Ò/þú§Íç'¢¯g½Lñ€6švKèØzݺ®-µÛò§N|ya„½j)®4E!-=jÉÙ£¨À IÕ>Mw…(V¾®¿b_˜* ÿmaÍ2‘w}¨ï·[Åpmá6w_^ì;ì¢fñ½®÷€ßS$¼IAüõ<„°ø…A9@VN×2ùwô­šÐe‡B¨÷`£÷@ÊsQh^Ì5è7!àÁ&*wÕÂÀ“‡!<ò=W`]r*n~{ÐëÚrô¦¸Ù¿!…R_u~¥¼¥Çð÷Ê©÷ [=ù7ê*môFˆŽòì ¶K~†¢‚¹è ÑË¡x®ÅŸgB`L30-?ęǣ Òèù.ž'\Ϊ*âð‰ #?£'ªØRß´—XŸ1î—zk.óÁ ^¾è<¤ÆäæYÜõ®{™Ï¨¼<>¾!Ë5Ã5!Öç)tU>zÇ©‘]_»èó\ØöôÕ[7ÞùJr™˜ 0]84ÚG1±n ˜©jÈ—µ ëô»¡'‹1O¡µ+Å(D],gaÆ\¢Ä\ÍœÀ‡ù ͯƒö(}gQP\ì¨|ã£êEyõ-ÕãÒ®„"ø|—N:ÞRfáÅr¨è™Às…ªÓMw,® ð€Qû„¥sþ³Üì›ÙS¼çÒÈJ„-VÝÀ\¨!½Šâ-Ãu’_J¼WmªMH;n(–+ÑüšÅ^£(AÄÒNSÄTòú/AþÒ•d•OêvT •® ±<kwä_³Ø¹éëLÑû*”ÅðµWD.-º÷ø 9Ví•ÿŠtªÊ n¬KFw¼€Š¿è¸(çÑ!VyFOMÑ‚ó^}Ñ¢½@P] ´0Á8_ZôF]‰zë æ«å¥»,´ÞöÄôZ~Wa}žÞ-­'ÌÝ—x®bkùMû¤Úb_D¤~³+[ü_W] "L^Ê…&eÿÆßÌ=”ËÃHü”^ï—Oè…´¹®Òkˆ~GÄßBNÐû]ÅÒ¾F¾ã6‹HÇCñ嘫.¶:\½Íue×座àññK¹*u­—é2£? +¿E\3Ü0ŸK¿y@Šòï(Ü®þ¤BÇ8XŠ_–Îè ¹˜‹Ö3à²pÈ%Y‘.#õ\µ†ÞœY�fõ3ÃB¸‹¯~ÀêYŠIô,íR­kþ™±ŽB.$Å_÷G÷£qn•¢é^Óeç€ PtíÑçFåÎú§gñí×½û7”“×~—ED>tÏ]-»Ldw™È*媊ô}iÃÆËà|@mϲl¦"̳‹*Èx¼§èÂx1ó3Ë)¼ÑUÐøM/ÕB,ÃiŸ`«RÑw*º‹ú -ìäzU› ™ŽB ââHDWèœJÌ…`ì I?�<Sahi–Ë׌h©†rñ-μôÑSÝr¬”Z$ °ƒ\M¦@[®ÀD‰·"•m¦«6ï ¼I¶ÿEÅ‘b)†t©hÉf¸¤<…zDÁ¿·¸R\-–ñš%â­^xKj¯hטٵdYæJ][^B:½ù ·K¿òv[V`UMLá„–K½×Ey3Nˆ" ùÀþ¢(ÐÊþ§Y^™–’Š¥¥©°5ú×)ÁrA(¼¿šò’V‘©ÎkdܳyI›Ï4WzH¿6±|%D8|ž ÎWÒ*¸®ËÕÀ]×ëÔÄW-ïÖ¥¡N»Â]zrD9y`Y¶¶ðLIçöLW„!Þê"ÑuÀw*å[`S|.‡žN!ý´Å×-6N"åÊ_ ŸZ|‰»_ö.®]!ñ5xoza¾&œ¾hyô¨Á<lrÙ£ÇÆûÎ"c‡Ó¢Á¸QÍ<¤t]@ÝK¡ó +`Ià¹VŒÞìe7ÜgYVõ©|xòìxâÁt¡¥ÜÔïu ¨†–8½‚Bò‡Â½.œ˜Ea!gÊÙ{øÍtì—žeÇMxµ| >z É\ÀaþP=l>è°t òöL…Ϙg¼ñ:¨U‹ð ˜¥°i$ øRäÁ,ÝØÁ{¯",ê¢ÛÕ“[¯"¸×U%ÖWÑÙÁ÷< ˆZÊš|ˆ3oK\ŽÌå©9.;\‡ÖUOÀñF-‡T…òo)zû½Ðþ!ꊔáU橹 Æ YƒOÆË×{1$¶¾uãW’…XHÇìxÔ5dB½ ¯ß¬ÓïÞEûÐÃü Y’e@… ÇAµ€’øãÜÌ‚¬Îwâ(Ô¦›²-âf¯/¾2þtR mÏvD«“ÝÍç|€ƒo\d0_B.·ÄWÀÕ–aúMxï­¹ò ±ëj8㹚ʣXkQ&¯+Ö0_ë²ËÂ(˜Ž–Ñ›äÌ‚¬Ä‹ŠÍëbßLÐïY€høÄÂë½åÅYŠ%éºMøA¦ªødø—|#–VÚ[O§nÊY¡bÓ™e“ba§Ê]Q†ÇÄ…¤eé*oÔßeyÅ×›?j‘dž¼GÁâK³àÊñy~ŠXrõX&Eå«·ÔÒ˳õ"CëêW³ðjçÑÚUቂ'7V/âËõtZ�ò±rcù£ûõÂQ±R]X+ü_ Ürª‡ß¸…|ìbÊ©µüŠî/=üº|z=Lx®Q!FY€ ºœß¤ßu{fËû¾U¾ƒÍïã¡ëFñ–+ìÆy×A{ô&{Tn7úC,d¥%�� �IDAT13ä4×’€õ›ƒZ uð³T}CxX¿uuåY¶a½‹–.˜;•›÷!K®€«G¦Èfr`–‚bá›!/Æç\‹ U®y ùŒ¦«t\pÉAY·–¶ÐctÍïÊ8Wù]z= ÄGÓCùfX²Eçõ.ËÉŽõõ»[m‰’S˜*–¨KÓ?·1˜;ÞG-†ý¦%žAgï:TñÏøýÐ=w}õŽQ»Ld!‚¹¦ê¦‰æó|—|›öÁ›On&æüTqæ¹�ÁxVÎ臭£®Y¢ôÖ ³éf,W„ý¦‚~Ðy*ù¬&K¬Ê’,>rËF³\4ÎQ,2 ³2-"Š ®xA˱ ­bì´ 3þ®:ô0E;pÕ-ÞNö§­Â°äËs¥i‡œ¿”ŸõöN$Æ™¼4Wf½¶#7ñ#€Š IafycºnT\CzòdéL1']W}&~ã-9±Êya”£aØ¥Ø~Âë)dàÕ+¢¿íXÆ{ãRsÍŠå…Ä3K,mœŠ’/ã³.@Dæ)ÍåëYÀ¥mT¹æzwJ¯¡^GZEßtñBíÂ.å”ù@ º[áêáéÀ«¸†V8ÙB,_’Ö²KÊr«“½WµoÊ®,БCD®|=Z®üLæyfˆ)ç^„>Zúû†¹žؤß5„—ó»Ó8€^ú@Jͨ·.:èEyÌ}»ËÝ*WƒKÁ¡òL¹Î}ÒB–; =ðŽºRêRøÈ¸"¯ëmÃÂɧãf®ëª¥øYnø\ZA0‹¯^Å»ÁB¨o£b`î¼uMÙEÏ.„ú‹1N{-¶çŽÇÞu´wþ8Ô‡^yxùf]ì9Àº?z‘¦W¡5wžœµßc–byîvõ³KÞ y¶r™Ø¼!†ˆ;‡ëš0½›� Ü˱ k¿!é§\øCr&ô0÷*Äz-Ëj˜„žqóéÞ›f˃};ì(ô–bÕMê"^•Gu@U??ç É; -óå7Rvaî[oÖäðIØE•n™ÆßBóß:+WóÛÚ¬—/ƒw#Þsù˜éõßHÑ-Q4~#–$üíºå,–5—|]dŠÂHRºXéE>Õ•d‡åܨ"ˆ)W|Ë+à“áð±|bò°è`–RV¿·Òÿ–ÂçQ¬‡)´¯Ö…té·fQË/à±Zx!bºÁ\î–òkפ-¾tK:½Ÿ÷¯{e¯ãUQ"{ËöÉÒ]R¸È_½V€¯º¢Þžu_¸šÇ¯¦¨¶äµüjÓôZ¾a¹>yy ³Å<…¸B\§èƒ6š/ª+` )ž}h‡:¼ƒ“Þ·)|;ÌK?ˆ¥ÒRoq,À÷Rt/•²Ñ›ÓCõŠïæºd:”‚+ÊO/ý‹(‚o¤DéQË'¾ÐAdTÑÙAã·K!ÙÁg/Ì=*÷l}˰”%×½€q(KèƒðsëRh/`ùÚe1t€õ¾÷âDô¢É¡Æí¢ãšåÔ·´Å|Wû1…³qqé˜{áKÕQ…Ø\A,-HãfŽjÉvËa~7‹1LRnâ<èb1ûôOéÑ!ª(;¼"M‡ö Iw©è»æ‹Ã­uÉXâJHöoi\—òñù ÆèŒ»hœå"¯´ƒØ´–_z½µ‚m:*¶¼XÐR ß8ãñzy<(fŠŽ«]ý6jÙáYø1K Ÿå-Ë MñáYBZ SVŽYÀÉ þ(}ZY!ý.ž‹ÂS<¤k|÷T{ý/êâÏZ/<§ž%ã‡Ylõ(®4Å™íZÖÇ#Uyf¹‹€® ÛyŽÍ_˜^÷§Ú¢–¹¼Í® O‹bËÒÍš´7Òtù,§€Pì÷^˜a–ê•Å—®ÞðRèk-½F!2¿"´íŒûHÝC»h5ÁRÆ]‹+¾<ñì»ÆQ€õ††ood:˜îŸqpµèâÛ`™Ö ½7ñ£7ŒïEÒ{Ÿ 0\æ Ä„îèÁá ÅKH^ìà å8À_´üÒ áèî¢o½,Xþ–¸>mŸWssËgzg)D0ÿ.Òo3CÑzh‚s]!.µ®ÎRÌÌpA¥7C×>¤ƒ®ÑyËSPÉíKàAo¿íåo®kÂQyÌÝ å¥#Š'JGv™xG�5wQŸ”¬|H`^=¸(ØVùx¯6éwÝP^P6éYaæJ*fñöñï”—Wo½Ï˜¿ìí± ü`/¯-9ˆœxÐ$éwR„åøL_è-ŸZžÛ~¼?OQu…W·tî0ÿ¹ýÑÕÕIs ›Bñ­—ÚB€»\œðœªñS˜üÙÔø6sÙÈ,Ì&º<K,_*༛ô'ÿ‰ÖÚ5ËÌBãŒÄ‹´ý§<¸ÖÊYãÜ'ž…‡6.™¼Døx‰¸¸³àºˆœ)®«ßm­Ð蹮ᕘâÆS4i¿Œ p^ÏrFyGYe½Ø¬þ^ÊóDt…II'¦3úPž9qEÍUW¾5æJô*Ywtƒ¥BÿzF¼O«Š*䣵$nçOT„•í£½ÑU¶7*ʘÓ’g¯ c„ëjXÝgmãóÅ3P.ï;ð-¯ ì¢ÓTŽír¾¥.Yz ˜‚«uMûÐ\ŽÁ'¬ã?'õ œ;aºßÎß ìž§`ñ'<ØyLP€… °¹hÑÑ‹·Â ßã3Ë岓2ÌÇÑz•tvñõY¯æ ÔÃøöð˜|ày*v”s‹Ë€×tÙg¸ò ñ_ÐwÙƒ…F>|]ô°üLAÇ=j;(‰TE&¦{aF§Òî ?CíSï¼rONçy¦¢Y¨ÅY×Á­á²+$'oýRøõèêj'åœUå‹yCz‹pïúiö7c¾ŽÊÕëÉ-êŠQ•KGûb½—#åŠyÊt™huÞp%ŠrPÓ =„ÇwToáÕ«†…÷›.þy¬K)þ:áÅ›.e;èŽîM¾£tïìBYh~¸Cx m|„hX£H|ƒ‰>.Ù„[u¨7d1ØDÃða¹,?<ñC¡Ó’,{\[Hü|…Bô@d¨8³ñNí±ƒ,§Á²o©Tøè|«7²u¾®ìO+üW�ßT.ã=…p†^—sу0ïm›ˆÅHû‹Š.,g[L°ìéàp¯Âok)¡[N0þbúU¢`{š(òÚp}yU¥æ¹¼[Ð]›±ö¨!rÐy]xÿ(§NzV\0WŒ%}–E‰�>”¾)e)N-‹4¦`dtj (͵à C|K‰õ‡’o [üx.>Ërèê/¢(F:‘>œGPa¦½á§ÉG ŸæòPŠt.tѪ+Æý·ÒtK2ÄÃßRD…zÞº0”*þj£Pµ,ó|} 4¤Ÿ OaüEÅÞ/+Ïä©Ã3P¾}›K&…V†J±U\¬r§Ø¨û¬âM/)ë5/ڌ쓼‹;ñ õþp²ôÒ/Lq|lß½�Vç[Üe¡ƒÏ­'ú¶¤¯Q˜!°ø™ÀÞüÀƒ¼8©ÜxGð µú]Uù•TOQ¦Xzô)QÞÛH£.‚<`õšŠE~ÞMô®™¥VƒPìÇÑ~¨^TVÀ{šÂ¬/ °5/X»Qþ<ðƇêbа¸‹ž/!½,¬Æ³s-!çuì@°H)Ø 91z™‚®Ë…V £; ª«.…Ÿ –ºPoÈ¥«?wXìôÒÂÛ‘2`õ£ËXéWôuAÀb‡Õ½° $ŸXù„+0ÌuQ±0 Y‚±}¶ƒ‚·×Ò]3`ë Êw‘Ϭ߀¨ç9o¾Œ*žCQP)ýr7éò\öê,Z£’Tþ‹ý³êrZ‚ ·ÕÏëóÞ?lß뀹. jÆ×)ÿf–*­*§ãg®°ÞQ@ºXOS¿÷ø´gAæ=‚ à}°¦“Çû: jâ‹7¸fݸü‹pÀxîÄãdÎw^„¯¥ô§¤¾Q|-ý h¨ãc.¸4¸á§:Ëõæ/뉺RÃxô“4ŽÎŠñu ò?%ÊìêJ͇2®Uùã¶Ksß&Ìô¬®Ôõß =Ÿ=e{`¾,gµ&ügH¯%žQ‹PËå5’ÎÆU‰/ç‹ÐåñQÊOsX¦[Š?‹ÿ\Ï™Ôí„üFÚU““¥»&­|#ô«õoŸÙÉÁoæøuðKÂo­ãæøÆñèí ¢ã¬~À·o·Älj‡oûL].ѽoŸ”ÎæS ظî]X9Ïh=‘úÏ!|‘¬÷Ó:ÿ´±Ù \Mù$X®Up. öAÜë’c†Ë¬C¹ô©í‡™%×­~ã‹Í›ô»æ;x7‘Žº]Öð}Çðâ÷g‹§—ï^—A‡v=6êb0zÚÃ?Æ÷:ýnH8ί~ÿ°ñ®!¼ Ëkúä:2P®76M¹QþçÁº“ž6¿¯wi~ÆÚËOáØüçkÞ<ÖÖ7uëò×®Q~l¼K“5Á»!ù6Žü¢|óóY»ž¸¼zéÇ|Æ\à­!vã–_f?ÙÊÇ;ܡו(Ü—¬·Œžuúõçñ辨ïÂÏTn”n[.KéqüúqÍzïŸßõwïøç;…Ø“BltÁË„F'HQý„ Ìø‚t9”¯¥§ àƒsvýѲ™ 2ÌwûÁ3G× ,_Q×+³l½s;àoµ”á‹Äµ?hÓaêºb­¤kéƒÅ¥"EôÝò`ß{sÈS œ(Ã9¾:ðÍåÈoqð­Ñµuå§Ð“ã—:˜¿V†|Œ.~OAQ*:ʃ}מ Zýeû3F/KGW©øÁrQ³¦HÔS0ú™Г_Яï0 ¢e&Ÿâ•W½¢•÷úy¡¯Ê)ë7*Ê‘5Ìè%tióU9iòÀ~ÚÓ~ž‚Y‚x攋]éUØÕ뱦€ªa:øa2ØbæÈg�ØÛ8Þ aB7ªÙ[3 ,û¡}Ãë` ° Á‹0g~Xcþô»†ð¡�ë›âÙ[<°b ‹Ã°´ô.}t#ÿþA!Ò»Ô˜w�¯ãmé‰Éc*×{ ‡°Ìþ|>X¾EÞ4‘¨„ó1Ö/½qÈë)¶¤ûà[燴/£ ðøÇ7wž›ëqn½Ë(X¹u÷zÐ7Ÿ° üÀ8ª°ëSX®¡Ü¦û¼7V¿//O>£õÄêW /±‹7½ôøtö^ì¹µ (Ÿ~V®o~oùî[ú/ôô*òm>âr½(p¨ù6qþæÑëù¤û«ïü‡÷þ‘i!f ö‰z¡É#”ã-Ÿãk</4ù/«x8ý½&Ûc°N¿›( ·ÏVñ9,9†3lÕ<>æ~øûe½0:©Ð{¹WQ¶ˆ"͆ú ‹IÞh¡ƒé\KñOøÎ÷ù¯¨ù3\,ð_KåËúÚ7<¦ðµ*ìPJgz LÑeå¿ù{è;_A%"ÍÁ³fq–óå°wð®*|”ƒ±¨\UË—  ³>f¡†x_&±g%þ‹ Ϲ¡˜°Ú-0­ƒÐzÜíà-A.Íø>Ët&O¤)J¼= ïy°ýúŠ~ÅU;D]Š+j»*ýÓT)ãƒõïjœ"€¢Ü£–TÑ Š÷ –bKS3ËCz/ôÀa-¿¼õL‡ó¦¼NÇEcݽ–ʳù¦®ç лA—.22ÌuÉ~kÁU”±ý:ƒ-á ÷ÿ öß }³Õ’7$|»`úžcß’â/§ø±ƒïþô>èý¾e|ö×S×÷Äþ;8ÆŸ‡/Nÿèù�ž;à÷¼w.¡×ßæ;ì|õùí{( «C÷k»Þ¶ÿòç}ï{ñŒþ¥æeÁO^ÿ—Pz–RÈέoéÝè|¢—{Îç[zzr‹ZæÎë§ýç³½r\¶§ý@c»Øø£ùýyýöÌ·ì|ûPóUï8A:üýÛ² Ïùóà²óÑøøðöaµ\Ûð\9ôÊ)6o<A÷wÑ~‚ æ¿÷§wý;þ©ÈêçŸ}góÞ?îq™¸úÂŽ ís;‚RXR8Ã)þ…?¼@gü ž¥€MhMý·ÖÞìÿ1ÿR7vz]_,Ëߺ ‹Ew4?‚éK6 èz6¥û¾rŸL¿_湞”ÝÁÌ×Ä:(»BÊ=SÑyù'þêA<È›™Ïåê°4ù'¼O&¼™Ž'!“㨜ËrS¸”›†¯<øbõb<Ö£Ñqé{:V—wí³}¶j׋ãû<—ÏátPvʧƒµ‹Ûgu¼ Ͼüêò.½ÈŸóåø²œ{Ч@¨½sý¹Þ€\ÌôÀŬùüšÃW®'*7Äç‹Ðx0ø´ú¯%Ï ¯wC‘_”¾Ÿ(Gï×H¹(9ß“>,¿µ×±r*çuL·#O wáv.vûF\¿±õûg†9ós?LëI]Ÿ‚ëÒ/’õ¯,ÿd«Îç.\©ÊÏ—C?õ*İÔþ3¶Ü@xÝ™>Šgþ…»¾ä\ÿÂôæŸ ûï±ü½™–ú.$߯árˆ'ŠŸ}Gg9ôÒ‰ùów{Æ—¿Ëá;AøÀ¤“ߦ]{å‚tù馴ŸDù™K7a¼¿ÃhK7v®øçÒéöÏóOÇÿÂrlê=P¿Á|t^÷ÆûÌy5ZžÖëÈÒÑY.Ü °ßtÏïA>5¯yôá:çÁl…À\¹Žâ!ók§zÇÃBëÞh?è¿@ùµŽ1”סúß\ùÌžg½|Ž>©é7K­ï5Üûâ]OÜñODV?ÿ[ïü·÷¾:ò†˜71Î]À¼e|<ù)ïæ„uúÝ„K|!•{® o¤ækMÊMðIŽäŸ+"·í uúö…X¹�ôš¸êåÚAû cÄîV¹ŠuúÝìÓ)êµ”þI·ÊO®m¦øk)~‡OwÙÚBü`ié·dô›þ5hýáš´–6{|«ËÉ’ãÙ*?Ö>p,\þ0ß Os0®ô_KñOå(ºeNPAô•ô‹…/Ó§”Ïéú[o—ëø‚äóUéÿ tÉÕ૪ד‹@¿©tbÿ+ò©ò5Údzhóú· H§×ØnŠkË1]¦)š4þò|ÑcqmYDjóV¾Ä‹‹Xàu¤÷àݤßõ>=÷§zünöåÐUwwZÏеÒåjÄumŒ¾Å9Lá‰r‰¾•õÐÖãÁ¬›¸Ñý%îKYyijíÿpóöÛú>}Ó”Û…×ËÂkïûLÐlÀ‡/ûNs&¬þ¥aôàaÏRõ â —‹´÷ÊÃS„,¥(èï¢ìm:÷èUàê 3Ûw—á<y¡÷ Ì;Xsò‡õÏÞú–jw§_6òº»ëLç‹*ÎnÕ<0ï¡Úy°ß6Š£¥Ï]=únµÂb´ÞC)’À£ãkTÁ;|1'³/ÜÂn»Fñgº=EcÎç(vÂüõ*†/â[¼\/ôŽ»Üûµ÷ÿ÷;¾"²úùþÓ‡Þû—•Bìsé÷[€Å›é«Çy/ÖùVïòñQø„£tšñHOA·É—AÆðÃM€m¾Ï§ éu<÷A–Û‹FðÒev9Tða¼Ókà ºçäË"ò‚|A¾NòíÒE¾nà}!å{‚äC|Räð ÊÄûåþú¼5þÕz‡»©ë[­Shƒù#¸-ºÙ‚Ò!¿Þt+¿µ�DñFð=QäËé_‡ôàÁÕs©Ÿ}!寲©>ø€-ÆKI_t>ÒÆå—Sü×+ºZºsº$ºu<bí<á-éš =ÀürŠ×ñð{å1ž•c©Ï‘ò>¿5½Ï‘ôè¸iÇŸžÿ9h·/À¼ƒreózœ.Kž¹¿?AÆCÆSÆkóä4NqüHÂËåùe©Ç‘Ö~¸>¼ 6ÿO(ùÄȯÍÅ‚mê?+§l(Ö¥býX­wto7;zWë]¹i²×¯Ejf­»3Á»ðe}àÔë”=®´q«åoãÅ)_Û'b|ÿ÷‰ì¤ëûêèþ¼Æ;µÓçI¼Táå¡úþÙ¾¸ ¯߇%…¥ gXA{äò2þ]*N~³<£sú¥³œ …|Á·@ý‹´—÷®äC`ç ½í¶´¼Tz£ü2<ì¼ExWÃì|F¡OÊòñ‚ÐËgïùÑíjçEÏË¢ùfœ«1¼Cå3 ôƒŒgZ”~˜Ã¡sÅŽú”é _´ýŒõb©ñÂ䉰ôúîñòé:^€ÿè|Í/V¹Þ}žkýËe9-=ßöž÷c»õÊÕÄ»�”ystŸêéFÛeh=ëÈw¨~¢÷ÞO½ÿûwü‘Õ/þþŸ¾ûÞ¿­bÏwUû™ôûR“rÉÁw)•>•åâËð’, H7KÏõ?ŸÂ—|Ô€Ï:éßqòíÓW©mËò­È@ÍùôôU¢kû½ôÊãχßK¿ß&a»\®ÿ;´üïA¹oCùo«xX;yíw8°'œ‘¥/Uå>'ßHá/A=ß0ëÿ\…ïÅ”_S~©Â׆1ŸüÄ3"xÙÒû8ᣔח ¼&—Ç!^;h,Û˽Hæ‹}yœ¶ßªäÐ`¦ü+ùÊþ…ü”å*(è«ä¿ªû™l¿UÇã¼V„1…·¨'çÿFY>ׇñ^½?¢ÕWÈ»„½3~El9 ô»ŒG¡O­WH»½C¿yÚïq¥>­_ éeýZ?+ù¬ðô àøÌõXãç×ȼÛ;?yóâ7f–ÓÃÓ‡@ß<ê}Àµ_‚zvóÕ·R?ùÜ^žµÜíz¦vð?jþoÝÁ]Yox἟ùlÚ·}šÞþ*Ct?&"Ó>1ºoìM_}v7n·ßÙç6Ûϲ}3ËGæAÞb–»]€ß?ù{©ý~ò¾«l˜¾·ìïÄ‰Žœ>úÊê÷¾Ÿëú¢t³òýÀ¾CGåaã?ü÷x ØÏÆå„xkðùm§Þ~ÀøœÛOúøŽžµùËÒÿ’KÇaø÷êaò蟗êoÑö˜7_EåßÏ—wΦóÕÎSKõKo=br@ºj<KÏ£HG;nr¼7ïÇÖµx:“cŒ.>~GÛ·o¼°}ÎK­O¸¯YúÆ¿?¾çÎWBʳýYTÏPãÁñ÷’Ó_°–_ïìq°ÜzéÕ;¯\<ÿÒû(ÿÿÕûûŽ?YÝ8ÿ³ÿøÞsŠËÄGÓï+¯<šò¿ù'|<ça:-^–ßãÃNoåQÓý¨xÐãÌh6¬=ÛWôø"frnêp†é®s,ÿLøtúýng¾OË\ˆöȩ́ã©<ö§)ÞÆ‡íø ‰_ÂóÁê÷w¿Ûo*‰%</'<¥ø— ßSúyU>Óñr ?ÖÔDÇ?ÐçÍM;äòT>rñÂ^}¦œ±î4N¶ßÕã¶ßmëÕøÅòÿêÓ:}ïêÓœÏÕžõÊÕ¢[VßIÂw¶ý¦Ï_Qÿ_J?+ÓK<™_§?¨ôõìÓs8Ø¿N°]J|%)|²ý¦ÈêÓ”žFÐþ*«Oïóiý@£ÏjÏ¢ÿVx³¼­vŒŒ«H?ÐòïeSŒG®’ŽœŸ¥G矒ÞíwãüzóRt¾òðVá—Sø1Z¾žÿ3<6ÍÛ ß9Ìó’ÊÕx¤]GV¿/"/7å›}\UO±ž¥ø‹©|¿³À`;Ì‚bÿPáe¿¿Å}ýůïcdïêaû£Ùr©�÷…Ñ}"î;£ûÑ=à¾8ΠÇç}<îë½ð-ì'Øý£…è÷—¾Oã߃ùõúøwêX?äÇO-?N‡' •oÇ­žŸ}_p<=×_bòÃrH§¿ìúZ~êôWÂçÞyA,ýQJGŒ¯þú{¿£u¹ñ~¼ôx´ûï£á~Êðe¾úæ#~› îw¯J'/¿¬\0Ýk¶oé§ß«oLn:ó[%xýõãõu3.76N­W…#ç¶^þÑyhl~âëa¬zøýüQ¹ÙýËëoS¹ºÞbë¿ãóZßzâõ‡x¿‚•ë“ÿRëï£ÿ -×Ëï˜~etÝŸÇCüÞ³þ¿~ÇçEV¿üÃÿñð{¿Ønåá”ò:-ÓYÇòEËõB—ÑïóÕWO{ä^Ç? |¾¾µœ—®ñwÀê“uxûÚìôÇ´ø°|8,¯<’~_…ðràõg;ý“)ýµ&¾†×xüê‹»øí)ø=¼ƒÕc«/Šˆl_Vé’U’Ëv'¯]^]Õýà‘Ä÷«‰ïG¶/çp†]½XO ¿šÂ9ýË®ùX5ýq—Nä?"¹A|XNÅó©ôû=^Oޝäø)ÈŸË Êˆú”èÀò)ñ©ÞϤz_ªè˜Ê}&å×ï }ê1øÅü ŸÏTå¾'/¥ôÏ$y¼’gÎ/S~hÏTå¾—øúÔTÊWóû½=zz@�û»;@O.¿o—œ?Ë!‡¿½¼2_)Û]áƒÈû åäýÄïë5Çc!ˆ©j‡¶_7rEzÕñ&|¼Vüã ûÊËÄ£€7/9íâÖ ¥aÝÄù·Mß­i¾~ËMùwõ®ÛþÑ.ÿê‹"òȾx5ÕóHªçÕ„o_žÑçË{î:RÉÿµ„­û¯¹èvôrŸÞ~ ñÎ…W!Ü»¿{ÕI$˜ßxß â¤›ßM½û÷@_;Nß]õ÷ÿN;ô÷bÍÇÃ)¾ý>Œîïû¾¦úæòÇúžïaøÞŒË—}ׯ€ñÿ.樓¿öÁ>_àýuôœd4¾¼þ7z^r¸ñ«ããtêóÌèùÐüó£?ãô,%ïè|2zÇ=ǃçg8?0ˆñÕë§~¿ÍéóÎO¦Q#™�� ¾IDAT£rŽÎë$[Çãtôî›^vðÕü°óÕ×;ñEé߯{ÇÛØ:ï –Zwê³çoÞ›;GÇéèúÉËÍëçl_%MùÑþª—çü.¥ÿ™·N2 í|÷ý^»ãƒ"«?û¯¿úg¿þÄv+?ßMYþ$ýb؃]þ§ü><Ñ|5|<ý"S|ôò²Ç•òtb>Úru=oäshø]‘ÕC5Û7ôxW>0yÚüyí•ëâ°‚©gûºðPÊ÷F;ù÷ùr8•Çro@¹‡HùåÁŸºORú™ZNöåODäò°œ‰È÷›¥iŸH¿˜þ ¨§¥ mhjú Û#€Þü½`ÙDiíz"uûŸA¾(¯Ñý†ßÎ÷p ÷mEÞHrÏåÞ(è>!åêvH¯óOtéùÞHá‡èV¨½Mø©–I7òÛ–Ïùõñã»>ƒð‰ƒW§ÿõ=½gj¸•7ÖÃÆ!“ËÄ‹‰g8>Zú0ÿëûü=o�ßI;ãøÓà!ÛÆÖ®ä“áõÆi?2yü0zË0‚W¿>¶ãT«ïû)ü‰}®×Õþôý}zÝÞÓ:ßzÛrŽƒÃBt^oÊÁþ÷1{€}ÉC¤|Û×u<[]î£û»øwB/°ý¬¹/Þ&ùûêjŒûîmdü-CM÷$ïXúè÷^/Øòdß[Þwëråæ‚÷ýdW}äüO´=ƾ³§ö¯é‹—³û!â÷Ò‹s†mº#¼º¨ÊÕ“{ƓNj;ghëg|Û㣠Sy™rˆóÙð“ÚáOR;Øý×ÑñìÓ|ôMôÙý–—C¾¤Â×Ê¥¯_s¹é|{ãy¹v`åYÉõÆæ¿¶]l>ù¸÷øëãŸõ“øü‹ùbò‹¯?v½ø~!6ÏÇéˆÎLN{¼Ûó]|5/ùãª>^§‘Î(ß žjÝ[~ÿ‚üÕÀ÷…¶\Æçi¤7º?A~t>Gõ&ýã3*'›/~”£?Òãµ7–¯û›ƒïwþæ—WÿEdõ«ÿ¿þݯÿµâ2±ÍZåôûÓ&÷ÇÒ菱UŒVß©žŸ6õ|¬ÊŸéø©KW.7å-å·éaxõøöñBÊ1yZùÖÐÆ?9Þ„ðƒ&¾ ¬>¼ûÝþ$–!—C<,ä¾ýa_¾i7Ä“òezO¤ó'$Þ‚é¶÷80úX}–åµ*ÿ›‰Žo’Òu¿úpÊ÷y0á­ç‰R½ü}2ÑñšRïˆ<™•_OÉŸÖ_Iá× \âý0„Gú¾SøÍŠ^O%=uÿÈûɃU¸•Ã)ü&´ÃÔ®¸¾Ôá7Iþ7ƒtašêÿ$”c錾\Ζ'ÒÑò—û¹çMŠWÏ÷ -W×ÃÚ…¿V¾ŒN»}PVíý·,WÒ¥«Ý¦üµ\òø,ñÔóÙƒiܾ©âÿ‰ÔtMxÞ¬Òq¾þ0”Ìç8ßj|ˆŒÎ»-ÿÑrv¿}Ð,?ÍOõ:„ëKÉß.ÿ›jhë×AkÄs¹8ùÓ~ä'd¿B÷°Ïù î{Xø°Ð»Oôö‡,\€?Š”ûà7!\ÃOSþ�?æo¿»n Ltäöü¤c¼þýÿÛêò9ÿÞúà÷äóC3Ÿÿ]7ÁkP=~c߃üûÎ/@ùŸ6rFþbßå¾üj<­¼Äünnå—å†ßßu}í÷<Òý1’®÷—h>„ØyA†¨Ü|øȇ#¤3v¾àC«ŸÖíËꋎŸ˜ÎoNHoå‘ /—û»'7¿ÞŸãã˜ÉóEéŽñí×Û;ôñ?ųs7Þs¾_þ|¾¯$~âræøj:¦v|-Ñ]ŸÇÚýù’=^¶NëлžX|•íïÉK[gôúûçY¾ø<“ßüñ‹ø¼}PÝ¿ùú(Ðo9ôÌ×þ:Âöa1ù³õ ¾ïÑÇ—G?ÖëÍ#l¾ñöŸéçÇøþÃî/žæèyò>ZÛçxã‹ëƒØwÚ¯îüÛåï¬þžÈêËÿ¹ðëÿ—b?‘ûå#"rüLDDÞ–ûSÁ]øžz{ù{¾·¾6á¿Ò&?Nø>RÐ'PÞÃ'„/ý¹_~œèøH•_H9/½–Ï”^—{{ß÷ËðÁô{ÉŸÂ÷AηRú}UXH>qóÅèëMŸH7Æ3>‘ž·½÷…è»!²úè.ßöGÒ¶ÇòÐôûÕGw¿ÛU|Pz«rŒî)|•ªçg)ÜŒ‡ŠŽ[�]È÷ §œÂ·ïOjú½îKùßùß—ê èÛǃ¼sÛ÷ßLG»Ǔà>3ö{„û ýÞbñXoÎçà‹Ð{é5Þ{¿¿ØËq__–/ÒáÕ³ú诈ˆüÆGr³ÿÞ ùÑòýb_nû#=Eÿ½SB’GCWæ+ãSÇ¿ÐOïC¹†ð·rcíåÊ“õG"6Þ°ÿ á«YßÔqX/òø¯øÃq{#Õ[ÌG•\nÀxýàÄ_Uo±U|ãºÃ×í·`¾¬7ÕîG XùA¼úþêFŠÿ ÜŸøÚ‡+ü7šõñþÔ?«øÊíãÕrÅzWå?4°}_´ÜÔ¾öþ÷=xûB{Ýi÷CØ¿mèXσ ïoPyˆš_šñ[Ë톻ë€ßE%ô|ÏLßq9Ü~•ßgoÓïÇûS¾Ÿ¥|úw˜ÿ]—¿g%ñ£óü ý’èšêÃïá:üöþ;õg{<%Ÿ²—/§»¦s¯ñ£Éãõrú÷½Púç‚÷½Z÷!ýëí ¾{�o†·•s½|])·ƒÜ¬þ!RŸ«´ç(|œÕíÆúAÝ^Ÿ­üëþÇäÇê÷ä^—»'•ÓúO}nSÓëótèòdýW›7t>íz±ÿ´ý¥÷¼ì~5?ï÷}øÙ<1A;ßhråë€×oÚzë|þy 6Žxÿ÷æ[F윮凭O8nuú±>ïœT+‡ó‚οwî‰òÉ|0¾r¼=?Oóf;Ÿiüúýš“¶ç®ö¼ççô£‰O}™æ½Ì§Ö.|ݵûÑ="ûuIO¬½Øzx?ÙÿÔã–Ï»úy}.×Ê­ÆÃÛÕë7\þ`ø„¶ËRÕôêMtþž·q”ãõý«ŸíƒŸu}í>U�Ÿ8ó©?Éã/ßøKo¬þ‚ÈêÏïþ¿_ÜþÁv+"ªÂw¦ßw÷17Sü…3Å_¨Ò[¸ÊÕéï’|¬þ;÷)7Õøw ‘›òK ã@Ç/Óÿ¨ø8}¿Lù>P¥Lr±ðÞ¹§k—þ.•c-¿©ü÷Áo§ßÿ¹_Hᛡü-\¨ò‰Û?.ˆ 7CùïwôheõOí¨‡;¡ü»Mÿ¿@Ê ©Gäî~Ç”„'ç©þ»!ß;"ò¾ôÿWûô\_M÷û„ÁÍ}y©ðÕ Åß-"ï“›òŽR^ ÿß¶OMw+Ç2ç»òVúÝf¾ ÿŽŸ²ýJü帽»âãf¢¿m‡»¥„ €gjϺÜU.´åJüÐûË„'דù¬ñbý¹"ý¬ïNù½ö×ùmñ{åËr^ýBÒs|9¾#üFä2"§?æŸ%''Œ>M¾8ß±ñ‹ó¬×z¬öjÇñ„W+×â»Iâ/8ém>»žzžÌôÝIÇ¿½Þ´û¼žµóO-ç)ŸF“3ÖËùŒóq·“®Á´níøx_š_•æí),ê<÷>²Nÿ*ÐŽ=ý³—¯ |_]Ççz°MûÖ®7?Ûß±ýÜwÙàÍë¸Ïóö…ìýî§Ù>Ûß³zu¹LíØîGµïôÛ+‡}À,?õŸ’®^ykóÒŽ/^ý½vAÅë}öÈ£æSŸxº×Qžì»Y/W~ßæð |å|^Ê­… ÞºüTÿ/eú>ïá·,ÇÖ›Qz$áíùδú;Çhé‹Ñ¯ÅëãLç7w‘|¡÷Ûö¼éÇúY¨åTB9îØ¼ËÆq;_`<Î+ì{œÏ'ž¶ŸÄÚóNÒ8¾V>µÜõyéN¥}kyêò“@»Äè—Œno]ÏüdüÞù î[¦ò7>}>Eù•øj<µ<Øþ™_Þ™ð³y­ÄûK™æëö|S¯¯•ƒ·39GÏÏPþùbóøMº~žæÉå'0pÿtz´óo¬§ [ó«&G„è9vü4–ÎÇ›¾.ÄÛù&ìK¹<Øú32?¾ëÊAžv^Õë¯õ9÷y‰®'‘s`¯riçÿ(D÷+bî³Úýû>±çqÔÛ¤~õ[?þ‹ÿIþ°“³#áG8ÂŽp„#áG8ÂŽp„#áG8ÂŽp„#áG8ÂŽp„#áG8ÂŽp„#áG8ÂŽp„#áG8ÂoüqÚó)±����IEND®B`‚���������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/collect.png��������������������������������������������������0000644�0001750�0001750�00000001600�14517772113�017200� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��IDATxÚbŒ*î˜ÆÀÀÉ@:˜¾´§< €Xî?{™éÏðëÛg†/'‚ºÖlÛÇÀÆÅË0{ùF¥Y�Äòÿß?†=§¯1|{ÿŠÁÝÁ† ;Žœeàc�é€�ðåÛ†¯_¿3üûÿŸáÈ®85Û¸ù3|©cÿ7� €XþÿÿÇðíç/†o?~0üû÷ŸÁÊÅEÓî}.\º f½2‰AY„“áÓŸ¯ } �@@üeøõëÃÏŸ¿Á.Ø¿eŠgo=gˆÊ¨bxpa/˧t­6nXÃ�Ò�tÁ FF6†+7ï18ú„Á5ƒä^|YŰxj3Clv-ƒ‚˜ýæËO°� Ì$Vn†¶™Ëþþþ 7€‹™A€‘A‡“Až÷'Ãí· ¿ÿa`bdbà`a« Fcß”ÿœJHކšÌð—çßW†¸°@}Ev>1m†“÷¿2è >e¸uáÄ՗x¹ØUˆ‰á?ÄL,¬ ì<ü <"’ÌòÁ×Í‘A^œ™áówß~�ûä Q!>fW`¸ý, P�°±±5?>·á̓k Œ@'™X0X¨31‰ð2ˆð¼b`ý¶ŒÁHô/Ãç?| ÷¿þcþÏðçÏß4€�b'ÐVQ†'¿¿1Èi™€]óû÷o†¿?Þ1ˆ233°ÿåføûõ%ÿ ¼@×ò3J00ýùÄðïï€��A�¾ÿçÜÑ´ f%3;�ûòì�!��.�Éâ�.ü�ûÞ�ÿôì�ìÏ�üü�ð÷�ÕÛå�Ôâú°gM€.9 ‹7ÏŸƒÃäίï l,Ì ³X¢ô¾10þdøþAá矿 r3ì<θçÉÓ'ý�Ä‹O !Æh)—MVE×NXBÖ“‡ÏЉ‘œÐ@à×Ïï;¾~z?ïÆÙC›�n�6�4”H‰±šÔ; ~ Ôû À�ÃY4Íl¹2����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/mpitrace.png�������������������������������������������������0000644�0001750�0001750�00000001200�14517772113�017353� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��IDATxÚbÌ®hûÿóÇw†?þ0 vN†)핌ñññ1@¡Å .dDV@,?~ü`‘‘f°6Õg°±0…K9qšáèé‹ Ož<cˆŠŠkfÀ�ˆéÿ¿¿ ^ŽV eØä$Ã_Á4ˆÉÿüùs1ƒh†àààÿ@|#$84d�@�±€œ.,!Íàâ`Ͱ}÷†½îéê�É¿|ù²T@@ ¤aëÖ­ê¶¶¶^¼¼¼E>>~Œ�Äòãç†ÿŒ¬ ¢@Å~> ¿€¶°±³3ðñóƒÅAòGennÎÀÏÏßýÿÿÿ[ŒŒŒ/,--xxxj�ˆå'0 ~ýýÇÀÈÂÆÀ/,Šâ?8H¨éPÓ, Ð&8”?ÏÉÉ© €X~ÿúÅPZTÈ@€4©OÈ|{{{€�E‰1šÏbºB €ãââþ£Ç- äT¶L#�Äòû÷oœ6“F�ˆéû÷ïÏ€ñ“„Æ3˜OL –÷ï?LåææªöññaزeËPb¥:_X^‡` –ƒLµ±¶ýÇÉÅQçî\“F�ˆÂ¡9¨a³ãö&H÷§OŸJ9EtJ#�Ä4�E·ÿ?þ\zþüùY^¡‰ E1@�a�Š[ õšÚ¦€��3$Ce”v����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/heaptrace.png������������������������������������������������0000644�0001750�0001750�00000001016�14517772113�017510� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<�� IDATxÚbüÿÿ?%� €˜(�D±�D±�Ä‚.09—1H­€r# 4œŸ;ùÿJdõ�Ä� DîÏdâÿÿþ|cÆ¿y ÆGÖ@p/t¥2†ÿúͰ"·ã2ÓK‹/ f�òâŠ×3ü~½ŸA€Ÿ—ÁÑ-$¶¤¦ €À4'0†ÿJ¶í*ÞÁpvï$†ƒûv0€ø\ wþ|ºÊÀøï ówS g†ŸW€ô€ôcu$ØÏõý›þ|8˰cÓ*†³ç¯1Àø0ðãûw†Oî0¼|váû7 g.=‡ @�1}þÆ™ÚV|ëò1†[÷^1Àø(ÑÅÌÌÀÎÎÉÀÁÁÅÀÂÊ «*È�Ò @Lÿþ1Z(Éò0¼~vŸáñ³÷ /_}d�ñQšh�·�;·0;§  —8Ãß¿ �Ę,{‘éÛc=˜âŸl2·Ù=Q%& üã’½@Œ@Zˆ¹‘Ä¿¢ññ¯�ÄHif Š“2@�Ql�@€�·ê°iÎåwN����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/circleBlue.gif�����������������������������������������������0000644�0001750�0001750�00000000131�14517772113�017603� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � �€�wŒ­ÿÿÿ!þCreated with The GIMP�!ù ��,���� � ��Œ©kྞL²¢:~wƒ¾QX”1æ�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/warning.png��������������������������������������������������0000644�0001750�0001750�00000001133�14517772113�017221� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��íIDATxÚbüÿÿ?###6°s*à F? sƒDN¬{ДÏèj�ˆ‰Ø6™¡€—O<ÜÒ)—“—WÜÿ×ã)iØÔNþüelÐ2òg`ø÷›DÿÿÏX‹M@�a5`}/C¼œ"?ãÿ_ ÿÿý`�Ñ >H]-@�1a·©ANÅ„aÕÖ ¦‡À4ˆGW @,kc(PVÚtúÁ/>~ú ¦A|8HY=@�aðëCƒ‚’Ðé¿øþù?Á4ˆÉ#« æÔ2èh©ýþ›ˆõÔ8~u€h$’©ƒé ~þfhPR’†ø0ÖPdcà`û ¦ab y:˜€�‚0±˜¡À@G™Ÿáÿ_ÖQåd¸µËL#‹ƒÔÔƒôÜ€_Àx×T—A ‹7¾0D]ÓÈ�¤¤Ä °}Å<%&JüÌÌÌ È¸{îc†=Ç>€it9z>€�bðíûÏ UŒôP—£ÆÀÆö€¡"MH³¡ÈÔ=õ¨ €Àüþõ›ÿν *ÚŠ(Šô 9–OÅšÔï\½Ö@Œ Ü˜äËØ)-ÊPÆ@"xúš¡ €¡Ùdéà@€�Õ¿v|,Q����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/performanceAnalyzerSplash.gif��������������������������������0000644�0001750�0001750�00000067407�14517772113�022737� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a&çÿ���� A. Q j `  ƒ Ž '0=­\µÄ"$!Ö"$0&_ %6ìã$#k"'Möÿ!%‰+d'+=*+7+-*"(«%-ƒ,1C'.¡#4j'*Ò14@-4U4531004[,1—.5d04z25p38K*2Î15¼*3ÿ8?V:?Q3?p7=‰9?{>BN9Bi;Bd9?–;6ý:@¥EEG;@µBFY7Gx@G_8@éDJmCH–=EÛFMeDMuBHÌBQ€AGýNPcMQ]PSSLUoNSºOQÕOSßR[yGTÿPVÑP\‹W\u^\`X]pVaj^_l\a^YXòaa|Rb¨ZcWd“W\üZf‰]kšgj„gk~llwjj¯fpwbo’lonoqŒds¢ww•jzªh}Ÿltþo| y}€}~y}~Š{~“rÓ~€ rƒ±„‡§tŽ†È„‰xŒ»Œ˜{Šþº‰‹Ž¯Œ¤“Ã{—ÅŽ”»“•·ˆ˜Ã˜™¯™š¦ˆœÍ•™Áž˜šœ¾Œ£ÚŽ¡ý‘¥Ö¢£±ž£ÊŠ­®£¥Å¥¨¾™¬Þ–­å¦ªÒ®®»°°¨ ³å³±ÛŸ¶î³¶Ì··Ö¤»ó­¸þ¸»·¼¹ä»¼Ê©ÀùÀÀ·°ÄøªÇø¦ÌÎÄÁì”ÐôÂÂó–ÑöÆÆÝ¬Íö›Óñ¦ÐøºÊ÷´Ìø£Òò¤ÓóÈÈú¥Ôô¦ÕõËÌÙ­Óõ§ÖöµÒö¨×÷¼Ñ÷¬×ñ°ØÙ­ØóÑÑÈÎÎÿ®Ùô¯Úõ·ÙöÓÐü±Üö¾Ù÷¸Û÷ÏÔþ¹ÜøÇØöºÝù½Ýó±àÿ¾ÞôÕ×ûÙØãÀßö×ÙéÁà÷ÈßøÂáø¸ææ¹äÿÃâùÜÛúÆãôÅäûàßÔÈäõÏäöÊæ÷ÐåøãàøÒæùÞãùÓçúÔèûÖèôÀðð×éöÂðýäæ÷Ùê÷êèÚÚëøééóÛíùÜîúÇöüàïõòðáÍýüýûëcm¶!ù �ÿ�,����&�þ�c 8« Áƒ*\¸ÐVA[gé‚H±bE]3j̸ËÖ® C‚ìE²¤É“%}‘ôŲ¥Ë–Á|›I³fÍaÂåœY¬§ÏŸ@ƒ J貟G“.[Êt™3§NI*µªUgЬBÛʵ«×®Ò¤A¶¬ÙjhÓª]{­Úµ¶hßÊ{M[]»ÚòêÝË·¯ß¼Ü´qL¸pao†½!V̸±cÆá"‡37™²¹Ë•/kÞÌ™ó¹Î C6w®´éÓ¨S£FWšõ9×ëÎÅ^G»¶mÛírëÞÍÛ]»wîÜ.øðwÈ“+_þn`¬YÏJŸNýᬈ×-jŸhk£÷îwþéù±Wù]$Ë£4ù²½L—3eÚ,fs&΢øóëÊLéÒbþ5õSNuÕXm• ‚\-è•4Θ%á„Ò¬ea\Ò¥á\xÝõׇ `†%F˜bÜ<™7’)&™d¡Å(ãŒ4n¦Ú8®vãm·µƒ›¼¹›rÂGä‘Ì)GPuL6‰CÚEIÑDÞU‰‘xã‘§åz)­äÞ—0ÕGMÃs}û¥©¦PG!`SpRE•TÌ XÕWxváVdQXV5Vxá…p½åÖ†yÕåaˆŒîØ£‰X≈ V©Š*¾È"ŒšeVã§ ~&ê¨9ވΩ;ÆV= éjnþïüF$qÅWk’È-éä®NBÄ”¾vg%wi’y%¡·žJ½€ùeMòÕ·š<­iíšmØSœK=e ·vÚ™ç¸X™5–ŸÊ–[qmø–]ïÊ…W£ô F‰“Zj)¦Ž…³bd–yŠYgƒj0i7"\ª©®™V›l¬¶újÆ!G«‘ÃÝŠkrñêñtìEÃb$¬±Çޤ,—]zéì{õ3¦};•‰æµ8ã—í¶mÂY Võ®TzŽûU‚膨ҀªËV[îjXïÔ‘Ú;˜Õù>–b¦‘AÆiÁ�,vŒ —Ýk ˦vĬN¼[‘²ÇÆãú\tçýdþv#OYr±âŽòy,7{’³1EsMcâ$sγÉóÎzÛ­åÞÖ9tVí`Ò:áÓQËëá¢Sûé½ùn½ï¥ü²èb×0†=öí2ªv™Ù:¶–Úll¯¤Û½%GkÆEnl·ÞÌ'^ß~WékàY¢lÞy+£Ä,K; ßâ:õ¤SN‘—O”oú•€šÓ)nƒEç¹ è2-:»í–Î!ê©;Ê×Õ­K¥*µ5®mjS¶“QÁpW#Þ™ mª ˆ$âXÌ‚ÊË Þš÷±ˆ@ zÂúÛÉG8õp‰Y+éÞ³`ŸÅÑ'63Ÿ “²­É©ïgWi_¸ÄCùñé\þç’PÓìw¿üé^‰ê_½ ƒµÄP€˜je—@Ëtjl£¹]Ž–#âH‚£ n,h¤[a0ƒJâ`Þ>8¥¾ým#‚«yÒ“žìÎpˆûø—“iÉÐ|Ùê·.4¨ M+FÃS„ú„.´ê~…:”¡¢¦þ)ñ/÷ÂW‰PÅØyÍ_›b h²ˆEvÑ4§JÛl F1êÆx£7¦F½ð"¾z#–Hˆ;n{+„Ö|dÆ8Æýñ˜“K·px Þ)+^é\žè§´GB’]úCÔ¼.©:H€ž\Ñ¿(Êrî5çäªÒ¶*Ú°2bÞÛ|s$ŒÁr–Iþª%óB=*éòJ$¼ž/§î©0,¤ÉÌúh&dB®g<ÓVœÀ5 ª8sssÐç¨Y¿"ŽjÙä‹%¹©—�îk€(â—¿^ô¢+ºÔœ¡* M¹v¢Œµcuƺ§n´Ôç®<xË <�µá GPï±Ä…6©™CIÃAVE@ßÂh"– ú©im—$ݯ‘r³j«3iJ_;P®´vV9a*šêÈ‹¨rð‚§Sy¾*V²J^Æäf1|"G¨¼â'ߤD,]~DŽ[b* ñø²ÄÅL|Õ¢ÙT©š>eúŒ¢U©ÓE¯²Õ£-’ša]×XK—D’ŽÈQ�Ìþ' ÎÆ´t®•(íŠ#/þž£oŠTF3.¨AE,ÈDVT£µzc/ÙT÷ÄIJŠËlT÷ÙÈ¡o¢àºÜ!ŸÙCŠ…OŒ ÝYÂJ—ÕÆë]­u­½F[“ê+œRdiÀ@ƒ[ºz†·©Il†SWú¦?Õq kØä(—:Øi®s¥7ÂÁ%k ì9èA­¦bs|0쮚('v«sÚ\y·J¯&Í£“Äkå_ùzS­‹a mUJ»É´t3ýõ¯Òiš™>pa|Íinüê67– ^΃!ÌÏ_õS„XŠ.ö.,Y—åñº SC,bïh}SZþh ÍÒ‚…+/&"$³‰(EÙx¾ö=Lmmk[Nu*È3"¥Øtà¼Þ§´qå+³`ã 7ÊSfRȬ¥7"•—#ajJP&0¿'»7¡Y ˼ˆR@†¼ŠSFK4ònu~èm¤5aLgÓÉ÷CiÍóŽ=ùVý Y¦X4²)A úHx‰&`ãFƹEY9‘.GæO+…Ó×Ku ºá/ƒÏLg"µÎvQϪ9ÕÍÜႤ ?8ÿ~©u/%Ëjç[ö‰Y [JÙ)ÆŠ¡´‹ `ßZ•ˆfò<‡kFY^ðÑŒ¶B",jOX#ÂòH–´,MoºÛO3Mþ@­P3sÔâ–Ü›Œrê¡™Íì.m¹àüU°ª .ò–7|mmï×Þ¸u°Ão¯} p!J¦?ÛkR•páŠÁÇUð³ß!ñ½]çê ´ô•8ž2:²Œ{N…YÈc&Õ<.åi:3ª ôòþ,C´Z1¹T.Ô:rÖƒ*eV’ÆV“›Üu¦ÆùcÎø¸è4´“¾ôפò4«dÛ±“mà3Úê¸S?lÕ­³Ø‡P»Ú³°²LH]ÊVväa.&Ñ^ˆúD)ž­xá®î˜sµrž36)¹ó»öçß<©àÿãÊ$PàO ‘ËfSÈ»³À ÕL}¨O}óV¯8cEþФû·Á§YÇÝŒõC!·‰ •_u¼Ds34[ ï´àÝBs1"YëÝsØ__ûÆkD;C#UD6»Åx†Vl­„lNg+µòd™mØwEzG,Ýmà÷qìÁac'rv}tvè4„‚-‡ Bã>ïãfñçbbs©…s{×!}G5’x×I9Æo]ã"Þ€x/U€G§EËÇ[xeSˆ$ÑWA¹ñd?5XHU‡±XÀòFmuTzaw] F-dÂ](w‚nH¯wC/ "M1ƒ2øU÷ç4µvxØ�„o&"|{öIüU„F7JŒwͧWþÐ÷„¼XD}‚U…†}–Kϵu…,ÓuG×i&&ÒB>h˜jgnë“j)¦b2÷n oia(:GÛÔóe5|x"ÃÇgnõIž’‡g„¹ƒ;£Ahêt6®Ñ0{elJ¶Sô4+Ö׌v…—uZ·u'P§B O%vF&%Šç£-¤HH˜Zê&îo%:6¨ ‹Š²H_¬t?ØV³Óc†7ˆSˆ†ÈNªòN­$F±B…¨yÑÆF&BáÁuGzËâT‰Cr<a‚2S&gŽå&ŽVubs ¬æjò7ss¸^E„sRk•Ôs™ÄƒÇþI8€È‹ühþhˆ7ÕN™hɨlo3…ÈsO y…Ùáyntq§q‚£T¨=Ý“ 5Lö¡ác‚ÙY5tjhvnÎ ’ãMãr^'9ƒ4H(ïxƒ2´h(%€ùèg.0È—|ç[¿U`:ÕdÕˆ>• 9eD¥…[¨”‘™æu¿ÔÙX‘!˜z>‰†ê÷uCifŽ#ÙfrMŸS–ëxMùóŠû³–z¨k9v‹|FE¡tEry“tI×0´é0<il{©Œdôˆ€i… ÉIÉ…»daÈÒeQéeÖÕBy‘á–•Ìðz*HŠl×vZ…Žr’Kcìþˆ?¤)ò¨‡xöM÷¨š+ÕgDhNŠSÂXˆÇ(yL¦ˆoKöÔ›¸²y“È…ˆ©2וÀÔÙ%>äÃP È‘Dn+ø~.8’¶7–±&kg¹6È{ð%‹%R‹¶èƒø¨SéÙ@3%lÌç;;9AÈæ€ºŸCKY}½ù›Hyø‰˜^~â'•Ñb‘#X3“™•5´•ËÔ~)öva‰ŽÕHêB „Ò¦Ãs6öwjEªÙ/=æc6¹_°›":lAí4Š6”ãl/iDõ<Ÿgiáá”éqœhYÊy‘˜Ur=J™–©vXUHnÈ9Šä éE‡5øŽÝ9/þ9¨Dº¦g¨R4I t€¿H‹‡NwÙ|ÏׄÉS'¦ô‰0Цi*=]Hœ\¦ia÷ߦPe‚•> +XŠ)–瘊 Btšv¸’¼WV-yg’R²%¥mÅRVJ—YÚ@ëyd9âN= O®„©D‰<w}f”ö©Â)zÙ3PÅm¥ª£ã3>⳪? 㨧§Èf²ú§qo1¦–öö(´ˆ¡‡1¥}Ftè‹Yê©„—Î}ÍZ\cO¼Y”‚éyÕº…ZǤ v8º8213Åt~«êz¬ ^B*^.ˆ m†Ž]U¹wsLº–…ªƒh“Rê:ø%„qÙ‹ þŒú‹úª“ƨ*z™›®"”Í­+˜ y­˜¦ŸËb8ØÈaÿyYŒCuŠvω‚ë—§nw Ò =¤®ê¥{’² žá™g3Yž·E0aS— (©JøE h³ótO»©Ì±Ùq°ÛQ‰ 1Õø…¥‡œœ¨£æg•âÊrHáò-èV¤Ö)’Ì ˆ‹¸µ°¸¹ ®ð¸Û «0¹”[¹–{¹­Ð ë Û¹µ¸Âð ÌP!¼z¨~ÈkÂ:„@æ¡c{[zJ�Y©¸¦—7¦: ‰<£näXù ´_‡£ß󘞨YÕ2± {Láví§jk¶C^!’À ¸µà¸®p¹Öþ{½Ø›½Ú»½”«¹œ› ‰û ЃÞ$¯(tŠJEŒz¥‚X¬9I¢‡¶¬¸q¢ŠXëhøË¶T‡Xg ·$ƒŸÃYÓõ”Cû¦"85c•ª Ž)X±±Ç¼çšC̽Óû¸Ü{ÁœÁŒÁšÛ¸ˆû Ïp ¬c¾©©cQ$„_;ˆ/‹€¤R¶ëôx¶)¿m£¢‹XFϪ¿RÆ¿‹å¿Ñó\Yæ…nŠ· øm/4}ë&—¹L.—C\ ¼ÁPÅR<Å×û½¡ÂQšRµÕk×¾ý8húº¯ª„ˆ|ul@i\‡Ã9¬OD˜» ªtûXŒ‰mÚ2¥Z´6&&—´¡(H励þÎ� üÄT\Ȇ|順 ŒÅ諨A(¬Ä:—Á©¹³Jׯ Hˈ`„%”úKôð¡¬\!£»Û7£r¬TרŸÞr>f|ÄÇ>ªvS1ÈՋȸœËº\ÈœK ¬¡ù¨‹¼ºå´Â¹³ xhÀU¿ƒu¿dúÉB¥X·„%ÃKëaœvzpj´WY¼G,9K1È»<Îä\ÎS¬È¾ü \ÉÆGWÆ ³…V6²;ÃfLAÁÁÉ…•`R×› Ì©œ<L‰¡×}ÒUBw˘ ‡]Ÿv‘Q•ÀÆ›L�2ÁN|Ëæ\Ñ}Ñ̹¡Û $¬ûXÌ”Üï[ŒÊl©šÌˆŒfþÃÇ£ÆÊAlÌ\2jmñ³\œ‹é=qJ~ŽfývÀàÄ’‹ÑB=ÔD½èü Ý�W’|ž‰ŒdkWÉü¥2쀚\<Ð u·;¡¼¿jDn\iýT’Ê[‚=ÈÊ -vÞªÀÙ·?í A]Ôr=×tݽà«Î†'¶CöÎuUˆhsˆM‡¶7+7û|Ãô9ʵ„…1}Tá}s¼T¹iþ©ä7§ Ž?íÄu½ÙœÍÙœû ÚÐʼnÇ×£DÉ~}ɘŒŒˆ`ÄÕl,ÍˆÍÆh˜Vò³ÆÉ­Éىݙ'·ÀeöÓ¹×=ÜÄ=׊ŒÔH8hóº ³€L˜dKÝÂþ•Ï fy‡¡ìÒ]mÊÖÊØ4š˜`ˆPÛU ¦Àh÷ÖÅÞê½ÙŠ, Ýp„!*Ìí@Ä–—îY¿ŒFݘÕS—Ýȡ݉­}ÝzÄ™‰‹iz¦ê˜9MvéÛÇ„ÞëáN×ÇýÞM-Ò Ã¥Ž÷;#ÓW¿ ‡˶þ àÍsŸÜ·qÆ"Pu¬‰¸mªÚ(¼;Úæ×]?-Üžã:>Ô­àËîÎóÍ|b\Ò–zÆù¿Èßh´Õ[í›kÄ\ÝÃÃÂ-• ‚Š£ÇUù8—ýG¾ã`æD ¾?^Ì’äÿxˆSý#´›Æ¯-ÊpŽÝÿ-ÛÓŒÊÖü”Ûº‰o:†þUÙ8éåµ€ãb>è„^Ñ=þ ÉæôÜÈ(OU7,*°‚¥äKçþüäœjJÖiàAËÊ“­Ð.d3Ó"Ëùñå…žêªnѹ€ÜG×Âw‰J%ZäšLO¬ÝˆÆãÉ›ÚÏÿ Ê&¾O=ûO½»°nÀÞºÇ •3Á Ù«ÞìÎ^Ñdß±¿;ù¥&ú评$~ùÚLç¾¾Ooë©~˜kz‰Š •Û*Þp ± nÞœ&ËNÑÏ>ïô¾ËÑNˆF¦è2»#kÎæ@ÉÚ*=âo.Êß®FQ.åbM·Ž‘ç®=Ý­ÜUÖïõ^ñÙ; ‰N€€E€‚À Ÿ½¹@þ eÒʧ€ ¸ÌU͈˜J7 ÆÒLžÝ¿FPrðammØêé7-´+$z«åm?òF_¹¦ LßôM_G½­ná°ÕµI©ýNy ðØ¢»né½NðôÕãžðs[ÖÇÒóÀ;vY>L~äà>ñÓQ?÷«` eàôxßô}@÷ØëËÇ Õ+?»;õÌFXÿßßÏ5oKu.ìMÉðU~k?ÞäW†ï¨Î÷#÷yŸ÷ ùØÛãÝ`ÉL¦ÿšÏQ‡Ã¾Þ҉ʌuÒxT—Æu˜hÓ_gPÉÍ C  · ï ?ò‰ÐùyïÁ¯½­Nú«2Õîèöþœ©„y»Þí4¿ø‰Õ\ø¹œnÖ]wû“z"H†Ü%±=qãÇõ¦°ôÄßô‰pþÚ+úeÛ¥ÖePFé†Åë¾¾ÿ¿>TPBö�aK .‚ ´¥k—Â] >|ØKâDн|ù²x£FÁ8ú RäH‘Ɖ,–Rå-W«\¾„SæLš5mÞÄ™SçNž=}ÆtAèP¡(âÌA“㨟M>…šë™¹sU­^½ŠÕ­XÏ­VlØve×µ;[VíÚ²ïܽsûÖÝ\¸oẽ›Wï^¾}óÒð,Â… FLXàbÆ„œ!Dˆ½JÜU±âÆ9†þI²dÉ“ÁT«ÕêjÖ­]¿^í„èP'L_R‚[·ÏVÓºyε«Õu_Ç'‹–íòwíìÖÅkWîs¿Õ­~'8»`z‰½vÞ±.É &´µPáäÊ™ZάÙâ|Ïõ/ŠY:¤IÓÀjí0@´©“Ù†ê„@t©b~ à 9 “[n9wœƒ..ê¢ëÐ:éù‹Dîû.EðÄÏ<„Σ,ÆøÞ“o"Œ$²¤û@­üBb‰A!‡$’§D¼ Œ"—Ô-£ð*°Œ»à ™Û.-ñâëC¿Ü®S11YtñÅ„b2Íâ«GÎ:ãþñ£‘|ÜÏa‚d²O?‡ŒÉDþ$4ªg²ªJ«D½ª’,°®Ô°9.åâ2®Á;1Çì®ÌÃl™åÌðÒ<O!É’ñ²87ËhN;wüQ´=U+´V[_+IKnåu'©¼Ú*ÊâE+-H3œ‹:-)Å´ÙìžåEOCU,TòD}ŒÔ5Sè=8k¼ñ¢VsÔÑ#üJK­WLd-r@„´˜{ïÅÛÖµ$‘D IеQ ñ`œLé„à‚91Å'S\ ª ¸'vÝ…W^zóåx_[[y&J)â²ÊcÙò0Yé¼¼‹egŸÕËÄh§U Tl#õ¼m J³‰¾þ¥(Üqsô¨\ÓBò1¥tÕÅi”9P€8ê¡8©ÙâxÉifs’œ¬& ëÛ´˜mК ‰êÚ5'vÉ–Z¨"b{(±]¢n¢ŠðZ'§ÕŽIªÕ™Ñ¯J¾P9cOŽNåºV~9òÀ6=‘æÂ ½3sFˆÛã¼QΡë37V>™¾ À?„†_Ò[¨9\R=êÙoŠý‚ÛM ôÀ¶e¢D¶Àãx&SÉ•õ îv)÷Ý{‡øöÔWW~(×Q_åW⊫ªÑ±NV :È#w–ÄMÏŸ¹LP©Íüfò8϶çË€^utÏŠ.}¤Ó±¯)¨ê‘ÔL6A¬ÂR“ÞLþL±5¢Ð¹ÊõbbŠ9ü¯64éõg6—,€«x`à h“þ(ä_öžÔ½a™Ì,àkK˦Ó!—‘ï/0ÛŽÌÆd9ÌÝ,[œk“Œ,ó³U Í>øMhD Z¥&G2áú�KÈ_Êà M8aES”b( ç„âÁŠÿûÝ*¶X¶‹É£8”):q ‰ö´ãqÓ¡‹ ¿d>²rÓZßb®%ª4•‡g‘ý4:Øï3¢ñm2 ^ ‰à„%Ð5'ÔËcr”]õÀ(T^À„X_ÒÆ(Ê&°ü_[i èm&œDÒ'Cþ9Jˆ•R_št [h!µ,|“j™¥*%H¾ZÑ""ÉHG’ŠMž›_ý\E4’„¦­@fMê¶·}™BxD¹àLz9ÇŠÅdžXç²ø\Fp\Å;•ç{¨ŸCMò)·v T(ñLçKzã=gžl.~üc ADÍê`“SÚlß"Ñ?Tq~îÝœ,ù™Kc`'ӏЅ¢ &É À:‘ˆN^€ƒ1Á©ò<VEˆ!”àò 6B˜tÂO%æÕž:Õz®"¨Ò‚NJÊ”nkƒ©LpñŒãë,z¦_˜ÅÑëÒ£ÒR‘Í|ØÍœ9ĤªòYÉÅþÒÒ11¬4!êlVé’ «…íbØÙ$0k+ÃQ- [ºbh(ã(®*”ÁÆDŒ}û¥Ôl¹Š¨Ŧ2aìP:[X¡¦ÊË +z%¸pÈCÒœ&[ï¢)ì¼5›fºÜ@|?ž3œ ³Ñ8_Uºsþõ‰‚’ k#<ˆ1vHJ(u£¦…ªÆ_,£KZ)”ðÎbÝ… %¢fÝU|¬¬„.PäZ˜Nô{|Œ! eÍ ’·oµ=졾ŠtTÚBÏ7Á™Wù„‹3+ÍŸ_«PÁÉd«ÓýêrP^šp&Ò fq‡¤7Î$±HBï*R+”ÜÄE(ïŠ/07þ™,ôƒ»å|','µ™øý¥4ªÛ˜™/L9S€û·‘è¹k·†(ÎVɉt:úÏŽira€:T(4ñ¢i"Ýή"ÌXåpScYˆÍô%ãÍnMÎ<ÐÂĽ³Q’…u/_@Ë2±ï ùØe=./ýåèä<j%§h1Ôr2‹+DŸÑ¨ˆÉ%š„ÿ¬çÁÑ@X¥‰Qf2Ϥ“ H1L@Lß6Óäž`j¨‘Dãè"ɱ.árL>-ØMó¸hMkY4º%CçÖ¿ar+’¹Ãè%›i®?tÑÎPÕ3ÌHGV&H²ÜëZ¨ª¯­KvM”[¿ÄÆq~ɸ‰î™þÌy(y¦I«g¢}h©4)íP~úé~IìÞto`¸!aÏPeD´ä4µ[�&®Œ1°x€x*n1ØÚ6Âv}vÑDn§I±ïÐ;Þ:Ô 2¹ólè “Nî[€ç51ÄÒL;ˆ¹–Þ³A¯zr˜w<&߆ö2l"ûÅÈ2Sv`¼ô;ºf؂ߩ¢ŒÒQy¥y©Ï;¨A”¸ðò¶¼ç™ô9Ö¸ÆnNÔ=µš¬½µ3I9WmraxëIœ ×½öêjÐÏ8]0Jlb=f×\4£™­>Í1ˆÓ†üç†híÌçêÛö»|M˜×z™ Æ“7Lúìò™Èþø3{Q(|r›Œž&©¿@™ EÎg^&Ó˜-ÊždÃïEц\¶’ìègKš=SÇ+ÐÄ%:ÒmÜö`þ ÜÜA$±÷65Ÿ`ÏS7k›ØXöî éÍ‹âÕÏà.¿Ô¤ÿ|™�ýJŽK–øp«[¤'›SÌ^úð-ׯKœ¸‘ÿ”ªŸä²¤¬c?Ê·¨)‚T“±ó»°Ï£"Ó‰ñ’=—è3v3…NJ5 ¦šø,›0…,ª ̼Vè q޵²Bc+#£Ä;üc4ïÀœ§s<m$ãš²̈ŒóÌ;Àôê³ÙÈA˜9ú8ãé¤p“.t#¡´Ã ˆ)9q“À'<þ'œ%Â9›žÀ)Â#|>[ ·À(K!º꽤ó­¥û”j)¨ƒ¶7<»Š¤‹ Ë B™…|›¥@"(ƒ>€0$­øê6o“‰W;»þA’º‹‰ µ™/GLÄ$œ‰5"šØC"|— øÃ@Ä<´ bXœI9¸²Dû¯†°Vl:ÄH¤ˆ;0’R0Jc°I²<úÐçŬ¹ª> Äš¸¹u3±N*³aŠé“DNаq5KF]y®+ü¥_ Æ^ü¹sP „;´44:5 >üŒW¬–ö‰4I«Eoqˆ°º¡Ñ4mt7Zû ·»�„ ¼€)<±NÓ þCÄ #W¢‰Íº€}Š9$I3E„¾½ÑƦp’\–IÅÞó­$3ÇšAÇ4Í!:¬8t°ˆÇ^\»k Ø ? ;|| ØsÉMº¬ ÒGJt‰~T9›€É›¢F™8É•{ÈšÀ…nhœJ9Ä»ŽóÇ,GÅcºàZYÄÎYÇ�¬6äÂ4Ž0À<„½ÄNÈFs­N˜ÜÇ™°±r“3ˆ)€áA0H¡H1£G´´µÐ";; ¦¯ Ë t’ñùFckÁÞ>¥kJ§œÁË´¹š8ãrGÔÅ‹ØJ®t#-ˆ¯C³Të33CÌ •TžEä·ê»‰ô?º|½þʼLKèË 4Á?­Â;6D¶5tJÅŒÅtìHSA¾Ê¸´JÂ:Ž{Hœd˜× 9z(Ë@òã Í”,„ ÓA 3ÒLÈê1N ÔÆ×Œ?Á$2·ºH%c¶ÃlCÆD°@7q—˜Ì^1õ›Bܹ¸$Âs»Hä‰Q@FÖ)ƒ#´Î¶#±4AñCBBú Êé†S”pì­¥>ò”Á³™Ì±ŽÜͬ¸ãÂÅ\ —øìÅQ€ÎÐ{3$ÓÛ›T›ÄzüO:B·Ã»e<›t‰NÂ1=<ÑžlP@{P½ˆÐðhYJ¥CÌÛdkÙÈñ «ƒXŒ](þ³´s•’lÐNx5åé¬WÛ• ±•»°ó»‰QH¿qe4#›»‹ÂÖá0-UÎØûQšpýBJL©¿Â4L$MÒŒä?¨‹69D¾ÉƒÌkó^¬S šSê=³/+5}‰>cPà¥g ¶Ñ‰1½ KMMP› °ûîÔÆ\8‡Ûº”ÁÏhÉ?ûS .A­«mYOK«R½JTáN/óJÖDJ ,4ÐÔ¡@HâT½¦R˜cb„Q˜!A™�U!_í`íaíb…„¬S˜@Upd¸#Å&¦sÊõYLZíÈR�¤‘‹óA^ÕFZ¢£™3QÕKQí¸äþÌI¡W¡�FMüÀo bب4$LWmEÁøÓ ®Í1¾I£¶Jk°k› lÐVâL«7±d½Ž“±Å €$ o%Ø—˜ MØ#e:W4WF TÝŒŒ5™ºÀJ²ˆ[HÙ€ H›±z¢NŸ{µ/‹Ö íÙ™ Ê¢›reJ˜MÒj)>ª”؉ýMÀÒ äWG½‰­:­­sNn3=Ý®}»¯}¯¥‰×4¼„]C?ÕÌ‘JEŠXÇ„W‹íA_×áÄW¼Ët«Âó˜ÚÉKAÖ³Üe[˜ †<$ÊI¼r„Õ ½Í™)ìÍvlO+LŒýQ´õ¤é3þJÐÇzzQ-"@4ÀOéÑÍÒ5]ík\˜XY"EŸû‹AÅ«\ÅkR4‰C(MǬˆ¼ÝÙÆÈ@ƒ9èƒ9ˆ-è)|zD7U]ÖÙÑYÞæ}Þè^2eÛ¦M¨5Ì—=Ì$­Zª¼Uöì\ìÛÍê P>C” «b=£ øUžù½Ý™À…2|„™ßǘýSÅ{XuŒ÷©J)IÑ]‚%UÖ!ž˜H\ ›0ü…§Ö| ®Sƒ¥&>]¶à;ß$ŇÎÜ'[_7Á«Š½žýß‹"¾)=f¼^R2Õ�±±ÀÁá® ·•œ"ÝÓEƒÕ>WôìP•þŸCµ‘÷%X9íßPü0ìÜááÜ b�µb!®‰\°!"ßþ݆uŸÇëÍj{ÌÍxOcÄ¢¬2(¨?´LA 0<ÐMK„èÍ;f]Aèá˜> c;ÆãËÜã8ΉÜÕSñ¬Í$cØòL`†ÃÇK«U\¥2¾uäPåÄ…fqAÂ„Ú ½dÄdàAÝä[½J¬Xú€ãQ¶å[î5H6åVX©uÊ3vÊnåFºY‹óÜV‘b\VæeæŸR.ŸAâ$ö]ƇjfÝÍâýPäÝŒZfæogþßLY8�Ë?fÅ»æVß(£ˆ\ÅÅ‹Hæp¦çz.1þÞe¦dtFLk^gÿ£EÏ1Ô[DÔùðf{Fè„.’qn« Eâ_ætÆ{Øœ'… lw=TyVh1…6…Qé‘&é’6é“6iVé•Þ⎶#¤#.W ]e{˜h›†XbÎA“š<vÌÛqiØøèQ…P¥F(;°2 @€§~€¨–ê©–j§~ê§v€)`j2¸‚®&¥k;èƒF ë²æ„³Fë¢.j’Vé ¶£V@J¾Èˆ¾ä›¦hvö&öiúq0ƒvë§i£¶¤^ê)p€ €P€ `ì xǂȖìÉ–lÇ~ìÇnlÆ>àlÎ&��mþx� mÒv€À€Ô>€%˜‚Ö>°.„Ø.„©BkNéþëZÑå¾é™>Lº¶é‰¶fá5¾nGnÖÅ^˜çÜî Q%HHj20 p€(€ˆì€ð€îöîïïðïñîî €ó–€ ì!8É&€o(€ù.�(mp� ¸®¾7pƒØ¶K8ë¢Æmæf˜®&î ßs®é~žh‰³h„6¦X¶ߤ£Žn#@€¸€X€¨¨�ò6ñGñ'切¯€ôñxøÿ€H�X�O-@¥îƒ±nK…–Æðœ€ë‡þÁ¹>à¿ëÉ([_C…çõ…ƒfnS…ÉŠî%�€p‡€×�îVñ3Gó4ï� Ѐ ˜€  8§Ðn €€ÎÆó8oÎþ�ÇV€Ø€èï>˜í"?òÜ`hß“\…uru–h€veƒ p8¡¼9™àŽ6N€n;pƒ+¸�0P�8'ñ HóTWõñÎ�:q;ÇñØè+82ð/�0øƒ^÷õ?�ƒ\÷P0‚+ƒ$xˆ�èx�˜7°ƒC7òD ‡f#ŽÛG·éàn(ò5Öè*QPvëM‡n7 ƒ%Q‡0u þXõz_õŸ�'€&è5èõLx…xc0øƒ7†oPø…ÿ„'øW0x‚Ï„? x�@€˜‚מíBÆv«¦IîeòL∶kF«fœ†¸—C›­CYŽgsiçnO¿‚é€ßùè8 _ï!¨sôž�wq{Gñ6¯�‚€oYg2È„L@ø„ÿx臭çú®÷ú¯û®‡‡†7ø‰÷À€€0‚Ž·ƒF`˜ï –1àFgÊ—­kpwq_Wõ\°ö``@èQ°„Bøô)¸ �€À)ƒ.ðƒÈ÷ƒC8„È—1À|18ƒÍßüþpøùY§ïÀs€€  ÷4oqx@Ÿïˆ‚6ø†WxxÐú°×ýÝçý¯Çý†Ï7H€@Ž'ƒ—ûœHÕ‘7`W¥éU^y•wᚸÉàdoÁY½Ê,¿eN¸y2@|8� 0‚48QH…TY€…ö‡ÿø‡…ùù_ú‡…õ_L üCHÌ> H ã‡„ 2ôÐa‰:0ð`I”6™¾q„¯È"G’,iò$Ê~ð^ýñrC@ŽÈ0rcŠ›BœVñìéó'РB‡-jô(Ò¤J—®šöî)½§RéQ¥ú®*V¬ö¶Ò³þ×u+X°øìÝŠïìY[jméR«ë-ܸowíÒE÷.Þ¼w{ñíë×__‚×bjø0âĆCY*䯦 fLI3 –,Y¼’qîìù3èСy‘æ•YæÌŒàˆaB @ $ èˆa@À�K¼üyåÑcÊà‡ÿý-™$YðÂÇ›v,™Rlý:öì׉Mšõ;x¯UÃ’//vlÚµr׿e›×®Þ]|å÷¢ï÷o/Á}¹Òîÿ?R¦pÂI#…b‡ *˜à&˜ 4�€KÀIi¢i¸!‡rV#D€À�¹Y Ñ+Ä©¸"‹Ã}óG €ÄÄpþ!ÑH(�úø#Kå"UwW÷W\™·äyhá£{r±•zÕ·×|÷í7Ø–ýùebÒS��@�i¦yÀižùæ™ Ârxâ!žyê9IFÀ�] BË&"àÅG-*º(£ ½Ò ܰ'ô€A�Fôa ˜zú.F^ÕÝ‘T%©ÕWL–EÖY¬¦çV”qM_^WÖ§å}€ ¶«—ŸúºŠ)Á ‰cSÐ�"ˆ€[l!´p¤Á#bàp€*0Û¬©èù-¸––Ši@Á‚_äñÉ=íº»M Q¨ðG¢+ês/¾÷‚sK-®Tòo%„LˆþX|0 cQ!�»âÊ-·ä;1¾'Á“IRðÐÃì°‚�+¸Ñ'Áþz2ÊCµB$‘¥fÅUªLšE«f¡µÖ”±¶U^ðYi]¸j¹«/)ì(£„B¬d4 ‚ D@!F|ð &™†Ù$p,!bÀá‡(ášçÖ˜ÇQp±Fƒ¨’»u×­Ž&Qà p#Ý+à?pÛÐâ‰+¾8ãˆ?q°ŸÂLàú˜”ÉOQ-¬PâÓ…2JuF›þéÊ-{gä‘âuõºÌ4—夓PêÜ]sÑz«Ð½ï—ß騙’t(öáÆQC‘´~LRþög¦¥’ #i,!5ó‡@6÷¢ñËôÔ§ÑÅoçñÈ'tÛ½þú´|aA½qÄ‘<ÅÔ°OÞ8ÿýûÿ¿l`†J˜×ǽHb ̵! 9(@ |€��˜ '–èé„¥Á r°tÁû`QH—™j<IŠyh÷ªXål¶ U­æ4\æ/ú  cŠâ5AWøà‡C`b{ŸŸ(Dq1P"#ŒØ½)&ã{©HâÚ¶@¾¸¡ïìûb»æ‘lü¢Œ¿ä�…,¡ zø"è ˆ=ì¡ V°Âò¨Ç<Áû ™¸'Ôá®`†5È¡pþ„%Q°��°`àM¡ëƒ2©ÉMn–øä€FGº~eQU©\3¢-®zÒíÚÒÝÁp†¾«á ‰V4R*Ådð„ LxË{Wô„'ø0Ìà‰~`Ĩ(MY“r CÖ0ˆG\â^£ÝÆhÆ_¨âXƒ¶† "žˆ<=A­!ÂzPÃõ¼0…+á eCšP%(Á =B 2à 0´¡ í€ ý׆V�¡­Â²°‡W`î`ð‚ô6ƒ7`B8)JQú¶5°´¥.m)„Àˆ` S ƒìPOr"äå§FˆJÖ…þv°SÕª^Y;XE‰-jÉÏ~fßõE—8*RÜ@!?xb3¼ˆ¦hº6…‘€Uó„,¤IEXˆÂ˜X[6q‰nþbàl—8U¡WU<bèA-¬‰"­œiF3¢ l0VŽul9ó 1,â–­'ôˆ@ÀA ZÐB¬„¶´¤­ h0Õ²¶µ«MAjc+ÛÔ¦ µP€ð$´ I ƒ¦`„(kYD8îqg ,ð€¥\x.t¹·AP·ºÖ}vûJݹ^âyà‚�0ƒ+äÄ“£Àj§NY•¶N<'\eìZI;YÆrgµ”OЦ*4ýäG—þè5J(LÐ�?l†3˜€hÚ ‹d`¢ âe¬6‰ SkÆ2§§VÐð“(WÜ>ñ ½nœeÔ«ˆ?·/¨a‚ÅÄ0=‘ Ä*v±}¬8Ô¡Žyì˜}¿pÄP6l<–F¦Å^“œâ%3™»Nvò&¢=P¹ÊTÎCx…(¨+qãn”Ã,æM¢Ìe³&Ò¬ G°Ùd@gï(8«ÎäS× ¼¼ä<A RX¯ SKœ÷¿�ZÙ)¡BÔÖ™*,ð5O«TˆúÚ.µ´U·dUÁôÊÐ@)� @ Æ26 �(pgÒ@?pF“¸0Ö4AáIhâVþヶ@†ñÁA–#0œDÞm8øÂˆ¡¾õ‘1ÅÝõòÖ)‡WcB¥(ŨIýXë˜óøö¿-n»‚{¤<!»ÞµÝ÷7¼á½qÒ;ɪ0ã6â­ï}³£ßþî÷66aL¢'Þ«™7am5×Z¹ß¢ ²ž©¡ÓÉO=­˜V¬wTV ÌÈóè&ÉW…±tOTax+[ÒPWýÕe§5Þ2�@ãV�°¢ .AÖðDÍé%1‰ÈD&#ü ­-ˆMl~xúeáùê$S4ŒxD]íö w×»kèBª–ækc›ÛæöŽÅí®q³cëæìþ&úÒîw“›Ýó …   q¸»ï~ÿ;àݽ ?��É`÷ÚÅÝm´™d/…&왆eÎ`B3 à3.ó¥àbugt C¯ª™)u¾·›Õ}û’_ªnšW›÷É(*Y »´ ñc 0°bwOzW,z“þô°‡]ÒnÞÓA-QYÇEöëœ+ã‡OÐß:†·:ü­clp›Ýî÷¸½Iï2"Œ<>„Þùøõ³¿ýáÆ†, u�>Þ:ÞÆ¼Íhä)wa ¡+ôë-wd{µW£¡Í¸JéϤ\êéW®üŽUF�®‚%�@¨Ÿ»�`Aât� �l˜÷þÀ‚ † †#B”É2mA2 b%C*t4‹`#hB™evMuy=‚*ð¾•_6”_ý©ƒ#Á$h ûE¡úÝ<À‚6°ß<ˆC)\Bu¡O~þý˜X€h^w¨Î¢½ÎW¬ÒÈ‘žÍHÚYÔ×}áE¦F~ìaëÝB‚@á=, <ât�X@Õ‘à·¤Mf`hÀÁh‚r©�–ÍY6åÁ\)ÛmÃe(ÎÝÞÕ6¨ 0ý•"+¶¢Ý`Ã!4€&(a»±-È™ ÌÀ 4€ è#Ð‚Ý \œa"Å4¬ ¡Ê"UþXÐ!ZÄÒ]8à^èVÕ–¼Ü®0¤á�À°ƒÝ¢âh€À #®c2˜�ÌÃ/ÌUT"€bºânˆ�"¬">þc²/˜À"8Ù¢ðÀ A„C:d Á|"ˆƒ·}‚4À á1þÄ9$Z*iÅ{-ɪ¸JJšÎ8UêñNjcëÃ. Í¥8Ö �À% À$°# z�<BÝÌ,ÁMº¢*\B¬Aô#øÞ<@øA$Vú6ðA�Ìž»aƒ0Ó„”¥Yš%DÆ�  ™&`À\G~$O,Z’$šþ¤ì¤$êL] Þæ¡ËéŠUÉdÌiœ �@¬Ì�ÿÀ€,Pæ‰(0BÀTÂ)|XÀúÈß÷y[¼µÛ·ñUø@À@ œ&jº@ÜÀ®ÁÁ$hÛ¶_¼9ä˜l~fVæfݰ,@ÐâúˆÃ € œe4A¬¦ØÄ4AY„�#p†'˜@�LA\ãxÇ2`–‡ •^4²Ê=à5ÒÆ$¾Þ™$¦Ý¨ðOpÀ ,bdrˆ °Á =AtݨlHlâ"ÌÀ�€À ÁY6hYZäÀÍ€h††$–baƒ±,ªuFEƒcþ5V·!nêfßi¨ \eQvAY:dPœœI¼@X €l†'lÁL§ÈåO `wº& “Ì¡J®‡SÙ×_fÉy/øa���¨Áú¬�ô À @æ}rÈ!ÄçšÀ&ØMŒ Ù|<@ ¸¨ƒÎé‹ê@DÀ�ÌÀ!ðž†È‚„À$tè· hæ‰Â›nª�€W†Û À<hæŒV*È€Ž¦•Ÿ@©òD7Ô%£)Éw&`^Šg>LZS5àîàa¦æ¦É¤`ÈdÞ@–®O�€Bñ �€DÃ Ž©hÈ‚(âH€þ (!€Õ·À‚„€ È)šÁC’åYZAD&ÁlA*ˆiŸÂ 0Ÿ2"†ÚØ9Ú*)^) &p¶‹*€Xkø€¥æë™è@h*pjÀ§†ê*¤ X¼á‘")4²*\䌥©œ-E锶Ѧ¡ÑœÄÛ%�ÀôÏ�@ðŽ1–° k3Ä`dÁ $Ž ø§Ý4€ÙÈB @XÁœÞhìlôìì,Î6¨$Á ÈÕ¥BZà}«,Èt *±ŠÆ¹’ZºæX÷ùÛ¾ÝM…¨è=| 8dPª¾æ« X�#l†(äÜì„Ã繌£þê3ÎLÞE>0i“òŒÊ¹ä~¥§`Zl0ƒ•nžVÕ:–&�À @Tã|��B¸ißc‘Éà- Ž4€#„„‹,Äâ`+Zòì„ÀŒ†@”@dé–%&‰WYÁ`†¸bHÔn؇&.Ž¡³p_»Þƒ*„@˜A¨®¥6€¼$Á„ÀI ˜@4iBx]�c7¨Ww*,ÝÎN^ªÐª®ª¬´…{Ü!Ëí—`¾LLÚêëõ†,¨®ðÏ@)Xím‚Ó·yŸ:à˜8šb k‡¤A�ACH@”XÝ\„K,þê@ì†A TÒØb A­ìb€ \–e1<ÁÓ!xK*ÀÁ DBðæpg4Ã4@b™¡Šì€TÁ ä«H* ƒ?ðC9 (‚ÀIü@a�ô\¶‚;àË)ÝÖm+‰§“¸ïûÎE¥µäüÚÐýê­îàòÇëA™Øg2l�ì�ÿ¬À è÷©ù}[ö-påšì§,gè±9.Äø!߃à@*\˜ÔQ‹&o2µˆ� ¨°óÁ—p¥šÀPAІA˜�‡F*ˆ ¯©Mç3Ö<6ä¯Vª2ðƒ?³0ûC=°Bþ¼ Á¯¶S2ÀÂH™@#Üb©6Ú‹ÃÞ­ÃÒW¥Qc|dÉßZ,þú‚îëÅ�0³g0�ÜÀN&¨ã†Ðº¯÷%ïú(ž#²8AP0C�,hÍz<‹Àš5A C‹A�`@ %¸@ö’²¥†@ PYZ¤A¹††(@Ïò†ðyK2Ù²gü/ ˜Tô›ˆ�+Ôƒ0×(ÜôM312„×™p@`€ œI!|dHV³"l|Ù­6£Eû2)-]šê±^. ®×*Æ¢—VÉsgÀB4@0Ž æÙÈ`†¨÷y›»Í@$N¹.þ*[‰Â·FO ¦‚©Õëƒþ�ôZôØbÀ4o`€|4h`BÌ€,ϲIO#L<­  ?dO¶T¶eWv ì©gƒö�/³2 +s9LЙX�”6(À o�«%;�hçùéR×-ÉÝ-Tóí¥á×5Ö”Zu­’³®Æq††kãL@á±ã¹ÚXlöÛ»4À $N%$�8+‡¤‚„@ÐZA `©¾òÀà$¬÷DLÃÉ€€Fÿ€ ¶,'06'BNÑd¸ðC8Cß‚'8ø­_ØAÁò„AîR88†þ?I'Q‡ Üè{�(HÂõ‚$ð?ää›4�óƒ óÌ@€&ƒ,œ‰ c2rg‘.ì+))í¬*><uÄʯßRµ87­·g5VÑœJw†PšÀ,N�À“kba(©mBôjCìŸò°©‡,*[ë v¥F$”ƒ›×ŠóC=¸9(¨x¥:ÀÍ®@ȹ0L,ÿÙÔ,@Tˆ¡3øÚea¸d»ð ×5¥Wº¥« fº¦g:Ô&XÌ@ìÀš³ ¬¸!øƒ$À‰$3+@Ò™ÀÀƒ¤•Pb`vÞù¢ŠÌ Çn7lû¢±çŽTyþ˽ñ¬ÎqþîzjœO‡á@�è§âP�ü$IFÀ€â¼@D"Ws�@D›Aš[*€œ 3? C9 ³œK‚«Ï(žWA¢ÿëiÔ»½ßû#š f”¿÷»¿“Fµ{/Lž˜·ª§:œ0�+ð÷�ÂP¯?xÁ›�P»»A:R—댞+™14yÞÆE]x3”¶1~è!±#yq+y0“ó’)˜Ààñ¢Á#7 L{À{Æ H€âH@$˜à #L†ìª9œðÀº›6€ ËªûC9€B—ƒÃ ¤Atÿ<ØoiÌöŒþ²$ˆ-�´Õƒþ2ÜÁ´É°+À‰˜©@#T`¨è¸~<^b³KÉyÞ®Å4zs5R,Ë .’—³ƒ9ož�@·s$‚â¨.µÿ|u.Nt7h詇ˆ�ൌ¾I<½?¼Ì(3PÀs=¨€¥À“yØ{Æ„• üþïOÁ�¿´8Ïó¬ã¬Ïè0ƒ¤´êûƒÁÀìÛþ™Èó¡g'V**$nçvSÿxš<â¯ÞK ÷‘;~9CþàÎ<)…B��€%ÃPÏ�á|LÜÀûo~ÀCA 0Nl;@$(Ì–&3 I˜� F„ˆÇ_Å(%VœþÑKÅz1B“dI“'òRÉ‹Ÿ4D–¬0@€�L`ìH’äC‚vî€ÑÃ…€™3ŒÃhåJ”&C.AÖæNUI±Vô"‘ˆ¿6 ¼ÀÈ*³gѦU»–m[·o‰Ñ“;—n]zöäÚÓ‹wo_¿öðÆ7˜páÁùòF¬K—-Æ»vé‚<yr/Ë»zA¶¼™óf_Ÿ?÷=zt°Ï¦ƒ+–z5°·¯aÇŽ=À^e-”“LÖ!9š4á�0éiqã%ya¨àyóæ0Ü>èI„t“¢`p26$�ü°Þ9’?IÛ€G¦"¤ëÇáT)K¬Ir¶á €Àþ†:^˜` œ+Ð@ç4˜�‚$vØ€�|X‡-Òðƒ¾øÀ V0â"«Š@a!¢%ü1$"â¢3dkÑE[9‡žwìª ¯»pä뮿ö 0Á Ä[ì±Ç(K³Î˜dÒÑH‹µÔ¨¬RµÕjyQË-Õ²d¼Hâã�`Ah‰á¢‰¦™fâk³$?\8Ð9vCˆFPJEŒ=…ëîê)ç)@Ï"¥"I2ÄO7‹ã…>X0ác $( ‚`‚ä UÔ;˜€„J(€€B C”÷P #Á(�ð> jó‡ÃˆnÃ";¸,¶Øijþ´ëƼxìËG½20!S,1ưUR[Í2kÒÛ(IK 4+©\Í4WŒMW6Sh›!Ü„ëâ="�PåvØG_l°IsMHãňF%L„±Í¸4º;�Ö³À‹r1„P À(‡^%2¡øá!$2�F–TR¹o  H ˆ!>Uæ™ì ‚‚(`Fd1îL‰ ð§PˆxãCù)G’7‚®5"L’™¢BÔ­6\Ü‘‹Ædçºq¯y|Zi©rÈ"óqÌÈ$Û¶2o9{Rn(Á=Í—)«4×Ê[¬î›-H0� ‹ž:ä� À€îiÜqÇçaG}þûUóß’�%Ž�"ƒÏ ì`8pAŸ»›d‘!ÂáaV$‘äárÀh@" ©ÈDŒ–À| TD9®!†€`9šeîàs 4�yæ*x!„CÊ|Š6®üy€À„•r>ö§dÄŸýªz$"î©ýŽ?­n¸NvÙfÿŠÚ² CL±È"Ó¶m]nžy”è®»-5w#×0R3ŒbdI~ò³Dø@8È �˜(7ƒmlc%|Ü WBÉQ®_—‹O*ø�-üà5LÁ¬Pš "�áAÒ�Ô…ä þ�FTP¾¬ Ïx0„$@¡(”c<éþÀx<OÀa ;H� †Mz¨@ И¤ m¬€°€( ŽgD£@Õ<ƒYè)pÀHÎ;Vð^?@!ˆð`|ûD‘ †�”ß4h´µúéH/ÌÂ_ØøG-Ä8Æmšá¿%ËÔ­4ãr ¹VA*¡Ë’}…wˆ÷x‚W[ð„'„%‚@ bŸ …*©Š_übì(¡ O¨ÂÉQÎ_‘J&"‘Ílú!ô9Å)Da‚4 D!ø!J~†‘6x‰¸:Z ”ˆöXÑM°�&#ÒÀ„H bœY4 FÐ@@ P@dÀ-,A r€þQ‰FÔA¼Á @ � ´c  BàX%„!Q®©PÜávxxØy"BºIr¢–}ËÅÖ4i¿¼ìè“ÎrV(c-İ”™áÖ’š4·ÖM\¦yeÞª4 ©´¬©º8Kèò rXp°ŒÌ€¬Pˆ‚ô Gl‚­Ÿ@&-h¡¹:šóP¾¦É¯²é)*AH,ð®ƒla$OI§D(2ψPähY 2Xñ0l…žÇ¹f$ü †,€£2 ( j�ÇD�F˜à�‡IL˜ø¥'P–½„d˜‡Hm.%Îv6t'qN’ ÛIÄhXùJDþD°Œ<Ì{!ƒ'¶�‘Q\U]1zG&ë×µžöè§Ñ*ÚÐv¶|d«”HíVW)7¦ÚVZ¹¤Z ùòºê E�`> $ràXw� ‘˜@D ‚ÔàG,˜­¤€«¾ÄqWgâKrre¡ O" n:!ð„a»“»?J¶±È�EÁ „7”Ã,•HXŠ3 Û.á Aò(§Õ í LÛPF¸Ö¢@Yɲˆ²×2K€AHàÑæh�8øðIú x#QyË~(ÖƒPÕ ê›®nà4»8r3O{ Ô„÷0D"ª�ˆ^®r© t*¹"þKJðJLs±n™_8b›pÈr€!Ýžã� ]€ƒŒˆ—¢z…ð4'gaqð«Ñ D Ûdðb A§Ÿü1\ˆD¡±C#r˜ŽÈ8[h�üªR á (À –°…¥ÙȰ©ï’Åà�ãâG�` $‰1\‘ùOõ`ÆX|ÄÔõáÐ\Âä\rʵûm×»>ªw(Á;Ô¢bæ”è= zÁåÔ§º\ñ•ïÁ Ýn-qb K¸ÂÃg`‰Gšâ?@D0@µ—†(#4Q éÕÓüµ^›á �Ôi ˜h�pMr؈ü v’ ˜[þŽî(JÝgqŒÐ€„J5xB“-‡I9Ά6¤èÕ�` p±ÝøPYxâ}9€!Àà <´ ¬!Þ0¾) w°'¦«pÅÞmæK'¿¶îâûlfËwyùʤv£R{ ß+ÜV•»‹BŠNt"œà„% á™Wœó‘¶@D "@A i€ƒä€ià”bM­ç«À,på-Aˆ'Ù<�h-f1¯Ô‰îÄ ûBÂâGBäQO!‚ r\ €NL‡…,žýôøËó~àºPŸ†4ˆ ô Iî æzŠÅ€ {s#N˜âñ/"Æ:®›ÉþxÓ…“p޳`È&¤Ä5ßùp›QÏ+�nÒKJÆÅ½-‚òæà䫪ÚO]LÁF á :ï1ð��ôBF ´/ ø€X« �` Â�jb®;D�+ !Å, � w>„ª."º¢D0âœP‚bà@*`` žOú�FxZëFÐ%Ì 8!ò,—�@x@D`Ò íX¡ÖEp "*é[Î!þæOYÜŒÞ~$ÿ¾«ZúÏÿ�H[O�=c ¯•�Mo‚‚ŠA‚ !ÐB¡¬/ÐÜ€ È@¬,î�4 å�8l ¶þàŠJâÑ""�ÂP(�#(à*²‚|\Œ#*⸠ÂŽc $à@$ �ˆ ú Í>VkNõZMÁ p@´P,€6ph`Ø-L¡1"€XÀXaü`§ „`h$¢Q6ÔPk°«F:i§¶kòOõHÄËÿo3–ļ:àúð�P5d©\ ‘oÁñ¾1]B¡Œ )ŽXÔ",Á ¡ A²âÌé dÁ`.!@1"Œþ+"f€¾€ãˆ€(B#YѼ"`¬8,`�ÀCvÑ%n &–À '-q' '»ÏP- ÁÈ€ þC‘(à'1"(ÿÑ-p~Ú̵ËþübZâPƒ¼üŽHÜñý @£Ïì1ñ�Q÷‘ý±)% �  3Ü€¦¶!ߎ AÖ¸ !à %â$1Â>„à' ËÒOQêÁîàc€Ï¹ŒãL  `n€!b%D8“J/ ¦�Œ` 0Ó7pC 5ÌL` Üà5’!ïÒò,¯ÝÂ(ð>ï�”2à,A-ßâ)ë® ÝïðÇÞÐQÎøo+¹²¼8C÷Ѐêo¬Ðñ, ±…³o0 n`Làó"­,À ‚³o a† þR> /T@öBz"¤ "øá F Qx ƒBì²bw"‚åfKRd!.Ò(­Nâ0€5%tn B-ÔBû 4”6鲂La!Ý` Œ BÅÓB@â$N/%¢0�)úÀ6»S-žòº´¦î²«ó.–óÞDi+ÛÑΠSÏÂR• OànªT#‚Q;Ñ2Fm‰ÁÜàán ÎáÎ  pý*(«ºÌˆ€ ,Ͷ0eÌÔLEa#1b@fiRL#Ô|J´>âe"* È�1!¢E-4À0 5)Ù–` ¨TKí C5TCg“Cá qóò4t(íàR§þ”J¯�Q¯À ú�`ÔIÑbFg¤To”Y<)ÎÄf¾«¹Rß(£[¤s�Cƒ™ª©ÎJ²“I 1-EõI-¯Ýž1â40qŽ ‹¿O $ ý"bµü�:1<ìáÎ� !A!or4Ž ÎàZû C!A #õW­&îÌ•-f”FMÕ8w*UéíYx´öO¨~´+•õP•P,]é:s5¾ ŽW{5] v]†Ò Î@–a§àaK3ÀT@í–H „àbßà žˆMIÒA#¯KÆÕ"]¶dë+ÖpFâÏTO5G“ÓÞ¬¨ü§9__“d_ã†HýÕ/ª�Q–ö,þÑd‰–-F!ò6ò./! á 8/À ²Ü‰¨v|4æ÷œÒ~Óõ5Ý hÁ Q–FWvu ïÀæþäµGûŽköfåqVù¬Vëñ©Nó1h™4.lýÖ-²ªó@ Òçj?ä|XÁT"n )È@K²²5!‘6Tÿör-éýصF£òkà”z„ïêL+kVßæ¨R‰HéöVs5¯$ßKo™´o1·vW!‘óD@ ð ŠPáw£Èb)$Î ÉuHÖv•÷ª0‰ çÏ]Íñ»ÆfZ˜³H„ªtoö2äÖIl••–tuIeW;iwyý6ì þ10ôT� Í:}é÷ªZ¡y7—sYVÞv„*Ǧ*×Vΰ·f÷Átcgù, PJpÕ½ÞKqWËWh}µ~Mv¢ô ²X%b !y-8„mjÍœ·8£²áÿ˜ÓG÷¯tnû-gngÿ,|Øu‘Ð&˜W‡V„‰V-Ïa(Ï` d%‹—K}x‰«†ÖÐyWÖîPØAÿ°Òïîµt÷¡€a¸€ææ{î�Ÿê½ð1Ióv‡g—‰ý6‘·ò ´ú@J©”;·Sí àÎrÕx[„Ü¡„U–.ò×~΀d…]õU¹8VãQÏT×�è4V`¥þjñИ‡+˜K69y=ù“™15y”a™e¡7záÐzçU”üç•]Vª‘pûP|uÕuÉ÷’ r”9˜…yœŠÙÐF Ψt˜t]µ€ó‹g9ðxnoÙðþð,™— ö|‡ù›Á¹vïטåOõ—þºf™™™•¯–cy‘ã1†ç14v¶4(ñ””›Ñ¸‡Ã¹ŸýÙds„ɹTS?÷eƒDëµ^³˜+ žåy¸ní—_w›õYo½ùŸ9º£qœÉ¹œ£X§Þ0m›EYf³7–º2ÞÆI¦“†H’Ë%Ic v+y—3º—3Ù£þ}ú§kjlCÚlYY¼9_6tõ§UG·¡9¸·{­ŒÙË_éà`I‚wZvk¡€ú«ÁZ~@:¤Å‘loô¨]6^SšmZ‘¡yØ‹kÕ–y`syÐ0z«õ֗ú¯ýzKŠy¨¹F¡÷~¦ò¤¯²±¸…]ší •äö€ê¹•î–5l‡õZŸùù¯9»³Íb]‡ºlË:•—E»Ô¶•ûgÎF—¥£9šPªe|X|±¦3[Ÿ»Ú³uÛ¯Ç:´Ë6I[«HöNÿœ³­ßz‹/²Õ‹�Á7\Z×uóú¶'6z·±œÛ·ۜϚþΑW¸­µ¸µ;£þ{¿¸nï9`•tº©»º9»å[»š»5©¨ù7GLZïùŠƒªÎÈ{‹c‹÷A_¿…¢Å8’¡ÊŒ“”5Þ{§7{¾%|‰AÛ¾û¾ñûÍú“¼+ùç•´¡¼µ][H§ó–sõg#ؽ|‚—A¾„¡§'|Æ1·Â-¼] :ûþXÕ¿çÌŸÚ¡£®iÙ{ÃR½¯óå‹Ð`·Åwz^|‚dœÆ©¼dqÁ”-ܘ Ûí’U™ßÙ¡·ØÄÓk²£;‚áK‡|‡¡¼^<Ê弦¼Êí¼;s˳ü”™Ë ù§||¥ÇœHœÀyž×«ukÛgÛãÊ!þýÑ!=Æï¼ÒõÊ÷\°U6ÇQ¸Ë»Ä{=È HòÑWÅÿ0¶Ñƒ6ÊåKÎ%Î#Ò-ýÖ¿ÑÆ3]Ësª°ÓÙÓ«7t‹;+[˜¼[{Ä ]®SɯuÚÕ öÍaÖi=ÒÁ–!Âq}ÛkŠê{×y¤3ülSx¼ÅËØ xÈ£¶œ¦+û¦ñÚe7Î 1Òíۯݺ¹}ß-©¶ܵ¼]÷× Á[¸óG¥Ï=ÀÕ½ÐË\H«›ïQWåÝÅÏÒÞ—ß/>ã—èœß=>]î÷‰ßáþÂ寰Ñz¿z­³ÒZœsÌ‘À n|JîV¾Ê˜ÁþµzâçÝâ±ÝÚ/ßAÛ?¾èÙ" Kž¬Ùl°7É/„[l`¶Y›ÌœÐ>u¯¹g³YºŸç+Îc]Òï]ãƒþÚóýºþãý]äÝ䓊ë"ÇÑÖË¿œ0–Wû©“{Èeþ+'›Î\Ϧ½>ÚNì-^ãÍÞ샞®l=í>ž¡ܾíßž×™¾sú «×zÁœ©{êe¾ôa:n¨Úæñ†Œ©‚±ð ŸÚʯ=ãþöñ­»Î%ÂC~äGþò3Ÿ¬ÞF¦­éþîÿ{êI<¹KæOõU=Í‘”Åa?Ö±¿ÚiŸöoßö?÷u?þ¾{ßÎý½þóŸ Ý~ø{é›^•O:êQ{¡œùþù¡Ÿ_§º:mXñ�¢X°`Âx0¡Â… :|ØpÙ²‡%:«¸Ì™F/vÜR#4gÂ\­:‰2¥Ê•,[º| 3¦Ì™4kÚ¼‰3§Î7s=[÷î;¡B‡=Ô(Ò¥L›¥÷jTzR©Z½jÕžVzZ»zýjŸØ±dËâË—o,ÚµlÙîÛ‡ö­Ü|råöº‹7ï]_|ûúå;ÐWà„†0¡AˆŒ;N(±Ɖ“3v´lY#3fšCn -4³’<K›>:µêÕ¬wâšv®]Ò¡´Ý)uŠ;÷Qþ¨TŸbýýÛU°`ñ…íj\lX³j˦m Ýíܺûôöòµûßí} &<±À‚â›?Ïp"äÊ“=züè9¾HС¡6Ù:¿þýüûû—ùZ7¶)e[RD¨[‚ ^5pW !WÄ·œVÌ™…–XF]p­U—‡vYwwÛÌwàFbå¡ccêQ6£dìU|É÷Y}>ÚGÚBId‘F¢ôZlí%ÛQÖfÔm NÉ›ƒÁ —„ÅY8—’õ[rHW™ÓQWuÚ]W"wÞ¡8‹Ã̉Øb1Þi7rdQŽ!q_}óýXßh¹‰h¢Š.“þOJ¶³$¤²=YTS^ºÛnR5œpYe)!qeyyaZg…yê©dš)"šyaWb›'gœãÅYçAvâÉ«d¾B¬]DìŸ:ÊGh²‚™K+Œ> m´ùµBL7ëHŠ-¤µE·˜^Z•UšZj¨*‡©¥žåܪ¾Õ*šo½Ú›&¦"ІtØ‹½þ›ÂûÞG}îèYhƒ*ë£4Ð8l_-øIKqÅ»”Ë4ÝdËñ’Qø¤”ß*X%¹\·Õ„Ç%gÜÊÌ™šªZ«Æõa¼®êÅ—¬n¾g­õ pÐê¤ç}bÆ <*Ì0¡9,MÔQ:ñÅV_}þ$µÏ<Úq¶–zë¤È#;Õ›¸&Š¥Ê^µ¬.†ìªªêÌïžé*¬~éìWŠzïmPß…ÝÚwÐ�×8pe{ó-ì }ËÒ'õÃK-¡X_ŽykÔjÜε]{Ý-RÎ6ö‚Oùf¥§æª.—Ë}©á˜¦r/ˆðÊ[×^²âÝϾTàB‹Qá¼ÌfŠ7ÞxÓ S½ÔÕXžyõÖÏÔJÆÖ®Ã}çžé;áß6 È¥/X6ê>Ⱥ…®WÈ2ìan]Í4ãž;^÷þXï+.6§ŸéJx¼ÑŒ7,øXPÊCÖš—,‘DMr“‹^5ª! ^ÐPκž«—þ=qo„+¡ »6IY*tÝùÈV²³¬}ksì^&7V‰Èf#bSv|E.J aÊ,dOÄÊLÒ–·0ç9.zT”ž¯8‰}p‹Òr1ž±½ŠQŒ'ß’Â&º4¾P7e3ÙV°4Ö¡ë†cSÜfV¦âÏn|Üß`ô5ÄŸïˆxR¢¯Œ†#>ÁGiÈ‚  UE bðŠ”¬Æ3„Ñ,.jRH!ìÆ9ÆÊî•ьڔ*e ±­q\©û [§:Æn-w¬ßýðG5¹©w´ª•®CÈrF{²È±¦9Íy‘„Þ$+ M ^ÂÀd7‰ÍþÒdï‹çèf(¿YÂï‘r)åCå)W¹”ÞDåtRÝWV÷•–ɇµtK‡ì‡K»älü$®Ì]Ó1<à!Ù³‘Ìt¤Ræ#§8Áf>3šÒ¤ä5.jILV-›mI'Ïvs¤ëøä7ÇHJl¹c|BÐ Ñ™r©.míKN<o8;TÑ.ï⡼ÖÄϼùî—è@Ï¢!’`QC?3(G2SrÍŒE+‰Ñk\ð¢\åjFk‘ÉŽnr›`):B*Ò‘šô¤d¥gcJ)©r›â”ƒÞh.xªŒ,¯sÛS…G¸Ö§Ô飉øæ;~‘ǨGE¢RÙD(þ:p™‚Š"Ô¨ˆA+^õŠ]í¬g½zIkŠkdõ¤ZÕŠV´zs­lõž8»&>°që¥s]eÉÖ)ÃrÍp¯lëë—2T϶àóvùÔgP¿ã? FllžlôØö+$a$HçЦA­‚ΤÜD±ÊYi~¶«Ú¸hy¯¡ôJã’`Ýèh‡TZÓžµÝ ©jÕZR¶¶5¥áß¶˜R[˜¶Ñ®iÕ+»”.¿Æ.¸Ð,q‹ûÃò¯—>S®�så\¤4‰ ¤ît›ÚÐGJpr¡©jf7«Uñnu¼æE¯yÓ ãØ¡ÍE.Üû^žló‹Ýï|\_ ãW¿d|í[EF �¿þ0}¹-×+Ý7O;2¸Á&l]$<+äþ®_Ë0c’:4%BÖ`ÎØLò––ݦ1¯ÄUÌl¿[ jl¶,æêy],ã<ëÆÓ¬ñ¯™c•´bÇÏ�£'Í!äD›õ´÷]-÷X‹RQùsª ™“`Ê”&Ó4e{M°o;?¹ 6DŽ0Xðh€äñòc&féºgºÕ]šTyÙ\;óÄs®(ëLÞïyØÄæFz¯±ÞjbÒÆ®�4i]acb|±Ð=6‡µ¯hEk{¾ö ²£‰|­Iƒ/Éåü¦ÓÉ›øJy-Noã'¿æÈl§¶³òOOÝÁQÕÀ¤«…9æÈJvþ$"iÞš“1î¶9ƒo¾jе ì`£—ا87.ŽñŒg\Ý(t¡«)m‹¼ÙÍ4N=hW@[äÒ&†0<nhlË|æ2ïf¶·­hûª¶ÑàgJÅ×ߦ|íÜd[÷úÞ)G–µÍ92›eƒm7êR—Ÿ<³°œøÕÜ/Q!5‚,ŸWfÅ¥»Mx$ÝLQ9Wâ+ïyËûöŠË]§;Ý5žqoäÝzç»ßÿo„#ðüà¯}øp žæŒo¼ãä›ã¤:Ÿï£Á-JþÆv¶æCÑ«bôõÅñÀŸþ­”ñè!¨Kßøúãÿøu­;¤ë•µ"%{Ý4ß:áþ%fóÙ{Õˆwîs/¶ÝÓ{qã}ïÜø»ó?xÃ>ñØVüã¯ís`ßÚÚ·ùä¿oyH·–¿Ûb!¹•Œ)³©¯•qÔk å œæ4ÔOG“½ DTû2<-’=A¹^LNô'Ö•L·&E&ÆpÔp(æk÷YÇwÅgqÇglw·|Ì÷|ÏWxƒÇ‡gŠg}Û'‚#È}j•m%8ygµh«%~­%n’t¥„JjtièT%¸%CžÒ$KÂ.¨wO·$uûp\4€CÅ<þ·D„CLLt8Á ÇT€>b€?2A gAV|+ÖvÀ&XxˆqèwþÈwÓç!H‚qøxà—sFR-JnõsÝRiŸ·)mÔJZ¢ƒ<eQ&;S6„·sh’þ³o‰1'±ç„[fFÓD8B€ “… Ó8ºö{ 8gYå€n7qcX|Æ–|¨¸|z×|¬¨†mxnøˆg}pH‚Ú'‡Ü'ythV•wZ˜n’ò‚*å1©ô_žwn1ÔdBz¥jBhOD(uA5TC´X“H‰¿¢TÑu0Ë“‰c§,Ô‰žø{¡†Â'l¦8lx†y׊¯˜Ñ׆è¹h3×}¼Èmôey=GB)µRœ7tD—i¡'S44Gñj`B´uExe~¤o¶þ/ä/þÇ [ÇÁN¤@šñT="’Î3bè…_†Çg/¦Ž1ÆŽv׎ç|ïøŽjȆô8‹2W÷¸}ù¨“÷hxˆRü¥B§dnÈøyëd‚6F!ðoˆs‘ø—e®—XÁƒaبe<î4Ä™XpŽ´‰•å{ågÑ„QtökbH|-©g¨hfèŽÍ—†}ÒGX}Öf‹"ˆ‹öø“Œ¶‚á'”Á¨yMÒ$GéBè—~¾±”í¤6±D!óöD7U¹3BäK9H\©‘pMÄHߨ0Ru–Î@ŽÝ¥€æø–[õ–ž—|&—ʧ|ì“4©—Ðþ‹Ò÷¶˜<)‡&è}ßg‡ýXd‘F”cn_©” G'CˆI'?ô“™ÒQ•Dp‚‹±„M(š^i@EÃTvV˜{ŽZÈ…˜…’³9›ÃG^x›2–Š»‰—5Y“}89sÃIœsx‚…Ù‹iu‡Þ”‡‘6Œ0èœpU©Du•ƒ2z‚¸%kƒS 7î’ˆV„Y6‘¿£X9‰„³–øu áT˃…¸]|›õI›,™ŸsÉŸ}'“ð¸†ó( ç—#8˜Å‰ AÖmý˜˜$ô ØBN‡”¶u:¬$S®TSlcˆÚXݹG~´e×È„åyHù•þ‰Äž“…kTÕš ç¦ È–¢ˆ£XŠ;ªŸ¸ÙŽ¬ØŠÿùŠú†‹¨qx¤Fº‹ú¸s@VRMšy丙#z¨Cí§¡fˆ€EKdR3æ¥Þy"ˆ'‘Ø/dª¢°f8ݘcikUplZU'Š]õkõ w÷i§.i—1Éw¼Ù§‚'¤ ø—J˜Iª¤‰Œz˜-1ˆF¦$¥Ò‰ºƒI•?(;Ï1eÃÕ©žªoù♂4H(ŠÃÄaí¡#qšr–S…€k M§’X§vJ—u§«»Ú›ð¸~ ‚;‚Êx6—‹Äú}D†¬°Õ_å%iƒ §i»EzñãþŒÕ ˆH•Ùj„¨Ö­~³"d:š”@ÆÔa×HÅ4õª°Z£m‰£Ç¯·ê’ûy†®x¯@ÚÀ)¬ºxóU¨‰¶¤üÈ =ל²Ñ$ZN¤ã¬˜[œ­Y±oXAHo²ˆÅ…/öÊÅ„¸ràÊ•Ås¦ Ef!bR$ŽZ¸pó9Šsjg.»ŽÈ×£ǧ{ Øç¯7«‹>i¨ êmŸ¤¨‹Úœ û_ K¥LÖ°H—¥ðfzoÃ¥;µ™^:+ HñЕD™H`¨I² s²¯ù…l'ЇŸ-+—eè¶yš†q }„Ç—4W·×°ƒÚ“:Ë‹g•Zá—_.þ´F:5˜Œ¸~W2ˆ^q—ZGKo›­­Ç­Û"á1¦åY‰Úˆžï¹¸·¹Ëš'kUpªAj'›£èvè²0«›o ¤ñØ×÷ºØ&»„yµ›œùÕ·A+´Fk>‚‹i {¥3t°„™´$•õg±¶7Û žàA'‘صë]–û±i:Yé:Ó¹ÞkQ爎Gºòú’(³ªë›|Y¤íÛ¾9›}«· Z¿ë_)WÒÉ Á‹çò”6Ô¡Ke,yƒ„«+ZIž¢YP•˜ž~2pGÁO³½ñéš”¾³ê®bøb¬Žªxw¹Šw»*€'}¿š“þµXœÂJ»ÈÙhvŒO> ¸3è¬S1©)*ZjSK‡! Ù¥>üÃ)¢"+ÄELªÔ Áê‰L#A‰ ÅÒŠó9«jlµy«ôº›>š¾A*‹; ˜eÌ“g ~¶ûckì9lìÆ.D¡Éˆn€ˆúdJ÷2 ÖÁe?S ‘A\+Š5ª›T¿²T_×di–”¥,mú¦ž[£TL§éȶª¸qyzÉêK}9Éxšl·(ˆ‚Çù“*ø‹˜·»Þ%£ó¨àb6 û¿9LG:%•ÃEËEèÇíœ/DÕ"‚ì„a,è™<˜²‡|…$+ O,QV„²á¾ïª£òªŸ•¬§3k“¾ªþ¯'\ÍçÉtx¨ŽÖÂD[ÐÙ»ÑIWì¤nn´´• exÌtz¬©ŠÈÇ È𠽓 f+ŠP—x0ªJ€îÉÏiib½ÆvâUgä+ÉùÉÌÎü|"|“bL·=y‚eœ¤¶;¿Mê=BÊnÜRåcÊTÊÑÊ*«Cˆv܃çœS 6ËzÄÇü;YË,ÍuÂⱉ#– „f$Ë<‘óª¼Æ€^—ÄWÐýÓ]Œ—~÷Å`¼¾ìûÐmœy+dk´0|N2œ)áÂ~¬ Òs¤Ãô„¼T"õvÒƒÈ.â­ŒeÄHŒ#¶—¹cK¶ÊtÁi|tý®øY¾§Û£?ª#Ü—JÆ×þ\˜¾XØúe¿CëRI–”7˜ng3Sý~ ¶¥,µë<¢­·±+-ϺìÒÅ”#:ò·¦&»®ßÛ®kÉ.fgw]º©ÈÅ]œÐ4ËÐ}éЄ*¨;ûɆÊ@[°³yQMNá .¸µ”;è¿•iS]"Í!„sc&' ÈÏû¼“KÈãj8ÔE…0º¹O³Èmö¹üÝx¶ÌÈ7Þ©ëÚæmx†·ÉÞÉï »ìÆ+¨Z‰z¬D¹R¼mŒö}>ª|Öé”–¹2¥3@HÒ¬bÒ'- lrÂÙ,mÏø<kÀÌ<Q´¦Þ½Ž<Ð,&càÅÉ÷²z-“|ʧ¬ë§&|‹!®Â{{‡þ¢<NÚ2>«¿¿Ë)Ô9ˆÿ+O‘­`Û™zªwÙÕ¨À¶‚àŒ@³6…g&²mM’õÁ½'¦YÛí–ƒ®ÁxÆÁl{º0 «¸Ð˜Œ“ém \~Û&¾ÍŠ*ŒšG)Ì*6.Ž>Áã2î”MûŒ9^ÊÍΩöKd@Ð}Ö…ü‘¸‡ädkÁgç½ ^¨íä=×o›—ªë†$\¤´-˜$^»‡É·?«Ûñ ¥/%[e¾°sÌ”•úØ¢Ž© iK<eê¥vûÐÎþ„µ’({C¹ÆS… Å#Õmݜ螬éªîȧڈ¾ÅŽº–¼Ð…×á¨ÁjÔKì8׳¸ëÍY)šŽŒœNþ%â2©Zâ~ZZˆÔŠÜ:”íRwûÏ¡YçÛ˜Öv½«ÊÏìNÌ~ASlQ¡û€o7|ò®Åõºáø |÷ÐÝÇɧõï<;¿†ÝÔfD“òÆ”ÇüëÑ:(íñt™"mG¤>ày4à<þ[öã_Ó°Þªé 9l¶È ¸€$ël›ˆ®ÅþÌ«‹ý ‡Ô,ìˆv ]ÎsBéZáæ·(ƒäãÛ?¯”nT`Ë[ÓšÇ13<jKÏÇÛ~ÿzK¸/’[çK•8ù ÌLcpSò7mëíª’ujèý²bߟpÛèkè†Àšö؇ͥ¿mJ½Â|‹ó*~Fø Ç¿ÍØ9þHܢ¡ýÝ÷ôÃÃ9ñ¥¦7«vñànÄ�x¦»çÅUnõJ.ò×Ýö™ù“¬èü¹w—L‚'Í£ïxƒ-°·KR¹ ßãÖÆFYƒS½Ñ4,Ü .G|ŸÇb2À›ºûß3Ë<âIªç©àÇóÙâñÙÛ{ ЖÕª]»&àA„×´ÔÖPaCˆ%N¤¨7‹5näè›7 EŠ 72ÜÉ’'Í™ ·ÒåÊ–0_Τ¹ò\Mœ/ÏÝÜÙ“§O AÑÝ9t纞ë”.eº´ÝS¨Q¥¶{×Î]ÕwW³¾ãÚµ«V¯aÅŽ K«Y¯ôÔ®eÛÖÞ[¸qãⳇÏî]¼þyõæÃ—Ïï_ÀýîÛ—ðaĉ/f¼ï^0È‘#VyX°aÅ4oæÜÙógСA/+FZó2Ô©U/sÆ:µ3رeÏvÍöíÚÐrßæ­[ÚoàÁƒWûM\àqä˜!Á…+N§ñ¢Å†;†ùq¤·”(Å«ŒÉ2çyôéieß޽Ϧñ™BU:Õ>V°îÀn废ì�Ë2«-Ù’ëÀéÒkA»ó«/ 3¬° ³ðBÅ‚ÑL2 +“L4C±3Ô<[MµÖXƒMEi£­7aÜMh„³QãÓQG‚jÎ çr"éª3"°Ëh;@úÈ»ïJP" $ñf*¯<õ²Ôò=.‹êÉ( ”:G¾¦ÚYÇ>4ŸêO?6³Òï+ÿ”ó¬w,ðNzìÉS-᢫.@懲Á¾ðz0 SCF»çÑ€��;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/jar.png������������������������������������������������������0000644�0001750�0001750�00000001366�14517772113�016340� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��ˆIDATxÚbüÿÿ? lªœ¤2ðƒé~íï³`€�b„°¼¬9¸ö$Šj¶¾}ûÂðýÃcÆ×vîÞ6$²ÿØ€�‚0-•ëxB ˜-,¥ÉðöÙu¸! ðüÍw0}ðð~†¬ÙßAl€�b)zÿåïôS: 9î  €à|1œ ¦ó’#XY˜˜‰á÷Ÿ ?~ýaøüí'÷ßÿÞúưwÏ.“�ˆ Æøó÷_fvb3;73' ;˜þÇÊÃðŸCáëÏ?`ôu Ájaú�@&9�€0ÄÿÿÕ¸5j*­ršÌ'H’h²Ñ'½L,5Tç<Š(¦ hÿ¯èÆ&ø ¸~ÿ*:‘Ÿ•—áß Üf†/?þ0|ü4 è ­ Èja� €àü ¾ýôá+ÓwanV†ÿœÿ¾ øôíï¿ÿ8üýÉ�€�BrÁ†_@‰/Ÿ~0üû÷è\V†w@§úö,ÏÁÊÀ€¬�ˆ]åÓm†[g~3ýg`ægø¾m.ƒ°Ž%Ã/%G&Q �ˆ ÙY,,, ¿/leЗþÁ`å¨ÍðëÖ †øLé· Oö-˃0²�%~Jk30süaøþ—›ÁÆÝšáñƒ› ‡o‹2h¸Û3påY˜Q € éãû ^~ °töeøÃÆÌð•…á'>Ão  `TÕüÂÛOþ‚ÕÂôØ�`~øoê<gÙÜI ë¹ùð¥áï_?mxÿòéœÿÐL@ðÌL\@JˆEäƒ7@ü¨ïˆ`�= ,)%6¿����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/goup.png�����������������������������������������������������0000644�0001750�0001750�00000000716�14517772113�016534� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR������ ��� G×\���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� ÒÝ~ü���tIMEÝ I/–O��[IDAT(Ïm½JQ„¿›'Ðg°–h!¶ÁJEAÐb[«KšÝ7Ä ‘ØV0Ýf#&ˆ` +IVÈ‚¨1AÅfIÌæÂg˜3çΨ߾ϴwç9�¨åÔöTMB&q[ ݼ ·‡iº„ í#Dݼ‰.ô‰ î<‡Ií¿ËÑb¥`¢ó|>¢ó•˜Á˜^õ¿ÂÌUâLôù+—£p3Ø{s¤vAPK«aêûÓç¡ê âMôÙ3t/âíÌnbïÏ“Ú9F†‰ûáW½¢‰ÎÜÀ[~ºÐkcièµÃù-‡ÎÜàÃ÷žCjÉDŸ”¡“…A�ƒ�;%uèb§G,ú¤Lµ`ˆø%‘—­­u± ¤^såãݧ^sÅ2i­4~I,Q–LÆ[9pY\Hªh~j4åêt-Vƒª]»1r!™Œqf3ÆýÀáÞª}ky����IEND®B`‚��������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/exclusive.png������������������������������������������������0000644�0001750�0001750�00000000764�14517772113�017574� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���Kpl_���tEXtSoftware�Adobe ImageReadyqÉe<��–IDATxÚD=HBQÇÏ}Ïò™¶DERØ jASƒS´… -).QC[KMEÐPáT$µEÔâl- ‘KK‘PÉRó=ÓËíŸbî=çþϽçãÇN¢~bŒzˆhƒ©ê¨à< ÿLàX<ÈRly§ˆõ&Ö3ˆÆü*ì£{p„¹=C¾§‡;S7ÊÅDÚ\ ‰K‡Öé0ÌÒ5ž‡!( ¨ª:šóyÇ‚œœÖp Y‚(:àñ9†½AÒ4ç >´Sàœ÷VÊß‚>s‚×ëÏбÄK¥R¤bI§ªY1P!oƒú†ØÖMòhÛÖÖ^@;%^¯Å©±6óz®›t6 sälV¢=˜ózíR†Z‹•=ÆöÂOIE‘­Êê·f„§ÍˆüL¢õÁŠvápµR  ÛmÒpÆhˆ0baètåМv:f +ÍL 1ã Ñ, ñút»¤d·t Øš…@£dyÈT…YÃþ‚¾ }¡¡ÿS’$ ƒtšÀe;Õ˜ŒVòúû+(Yº¤ô'À�磭-$â×����IEND®B`‚������������gprofng-gui-1.0/org/gprofng/mpmt/icons/smallBlank.png�����������������������������������������������0000644�0001750�0001750�00000000177�14517772113�017643� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������—SÆk���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß*ã‡ÛQ��� IDAT×c`¢���¹�Î…NÎ����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/profile.png��������������������������������������������������0000644�0001750�0001750�00000001615�14517772113�017221� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��IDATxÚbüÿÿ?:ÈÈ)ðRñ@ì Ä\@ü ˆ7ñÂS&lGV @ŒÈ¤eæj�©<9%•L9E1 )†Ë×®2èji3¼zñŒáÑý; îÝ™T3iÖôÉ7@z�n@rZ– K‰‘…m²‘¼�¯’!ƒ¤¨ Ö½G|œ­ž¿~Ïðæý†«Î3œ;qxîŸ?zæÎšv €˜`¶ÿüù³H×Ô*ÙLUœáævá·@†{;Yi †Ÿ1˜Y2€ÔÔƒôØÑq‰ž²JªÛ¼ƒ£Tä$þí›Èð÷Þ ¶Ð^Fi”ðùTçÑ †­k—1<¾wÛ €À.øñãGª¬²&/?ï?ÿþX¥1üçàcø¹¹‘áÇ÷o ?~ÿeøñì&ÃÃsÁò u õ }�Ä2àïß?^Ò@6Vf†ï¿þEX˜KØVg30Lófø/¬ÄÀøöØ¿$ Ø$´@êAú�bÀŸ?ìîßbxÿî5ƒ±¾.Ä­¼2 ¬¿¿Aدn2üjúi™ÁðWTƒá칋 Ÿ?¾ë &F �ÈO3cSfVN8þm‘ 2á†ÃÏ™ Ò†`q:z>€�bâÿo_¿}pý"ÃÇo¿˜˜áø¯YÓ ÜjQÄAê@êAú�ˆ>¼_}þø>&fvvfܘäi :z>€�põÊ•ÕgïÞxáØ^†Ï¿~3<tœ—…ƒÄ¿ýýÇ�RRÒ@àD²rr&¦¦›f¬Øúÿö«ïÿï¿ùþÿõ·¿ÿ7¿¦¾û ɃÔÔƒô ,<~ôèп¿&6•þ»pÒÏßÞÝAWW—áãû· /ßc¸|ù2ÃÁ›@xã§g<}úôH@�¡d&`„€rž òðòºó†PŒ¨æ'0íûòùóÎ'Ož¬ªy {€�bÄ–š„”ƒhP8ýâ·@ü¨þ-²Z€��›qu›û����IEND®B`‚�������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/undo.png�����������������������������������������������������0000644�0001750�0001750�00000001404�14517772113�016522� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������ísO/���tEXtSoftware�Adobe ImageReadyqÉe<��¦IDATxÚ|RmHSQ~vïuML§Î‰K«iN # "‰h?2$$…m‹~Ø”èo!d FIEeRY~ P馿L¦æÀÝ͹¹ï{ïÖ9§ QÖ÷¾ïó¼ï9ç=Gu±ñÄ�mø…ÞD"ÙÎqªC©œ™Ð˜Òœ„ïRž/Š’€$+HÐv½çstX.Ð"Q“¾Ûzºþ<J+ª£ËcšÏë1.ÎÛZ‡_ ¶†C[×Hª“æÚɽºÀLô‰ÉÚÔÒ c¢m0ã˜ÊËPz©Oïßµ./9hºS ÛúEfÒæä¡®á<ün'¾;˜Ÿ„×ëešN§CÍÑ0™˜çÞ­n«$_òUņ®êƒåãQ”UUC{°07‡7Cï1³°l›íš^\ëKÊÒWÑå:“™± Y¹˜³Ïª9ºƒX4È(‡½ˆ„ü°Ù¾!—P¨Ïîi¨­n!ž©OÓKŽ•uËÄÄgæÉÕj ËŠYˆK2[A’I467"=CËRW¯tÐÁ¶ÆìÎ]Võó»…"!“œ¾Í-cNv&+¦ð¬-b’¤àì±J„"q¨Óø�ÙÀå8Ó0ò¤ÿáëfžçŒØ‘˜4H¿<ÇÑYŸŸÏòþ@ˆSv £vg7‰j°3Äã•Å´YV’oOžªyhX]ó]ÅFbp§øHáåÔ‹4 ÔŸ«Cq‘^q>Na#îþ±*Ž”ï£C²Üî½±W¯ÏƒD ˆ¬øñ³a¸ÜÞ¾ùî‘.)DjX|4("”ÇãÃŒÍç/†!nlöÙWÖ»ˆVýY\Q¨ÿ=¼©„&rä=‰$\²¢Œo†"ƒ.ßÖÑ\ìæñÒŽjÂ8} t¨tåmÃO�ˆÁGGæÆ4����IEND®B`‚������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/errorNew.png�������������������������������������������������0000644�0001750�0001750�00000005741�14517772113�017370� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa��� pHYs�� �� �šœ�� OiCCPPhotoshop ICC profile��xÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p�³d!sý#�ø~<<+"À¾�xÓ �ÀM›À0‡ÿêB™\€„Àt‘8K€�@zŽB¦�@F€˜&S� �`Ëcbã�P-�`'æÓ�€ø™{�[”! ‘� eˆD�h;�¬ÏVŠE�X0�fKÄ9�Ø-�0IWfH�°·�ÀÎ ²� �0Qˆ…)�{�`È##x�„™�FòW<ñ+®ç*��x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ�� ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@��át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ� éÚWópø~<<E¡¹ÙÙåääØJÄB[aÊW}þgÂ_ÀWýlù~<ü÷õà¾â$2]GøàÂÌôL¥Ï’ „bÜæGü· ÿüÓ"ÄIb¹X*ãQqŽDšŒó2¥"‰B’)Å%Òÿdâß,û>ß5�°j>{‘-¨]cöK'XtÀâ÷��ò»oÁÔ(€hƒáÏwÿï?ýG %�€fI’q��^D$.Tʳ?Ç��D *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È�2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿÑ�§€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²<qyÛ ã+†V¬<¸Š¶*mÕO«íW—®~½&zMk^ÁÊ‚Áµkë U å…}ëÜ×í]OX/Yßµaú†>‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ4<YyJóTÉiÚé‚Ó“gòÏŒ•}~.ùÜ`Û¢¶{çcÎßjoïºtáÒEÿ‹ç;¼;Î\ò¸tò²ÛåW¸Wš¯:_mêtê<þ“ÓOÇ»œ»š®¹\k¹îz½µ{f÷éž7ÎÝô½yñÿÖÕž9=ݽózo÷Å÷õßÝ~r'ýÎË»Ùw'î­¼O¼_ô@íAÙC݇Õ?[þÜØïÜjÀw óÑÜG÷…ƒÏþ‘õC™Ë† †ëž8>99â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-Û��� cHRM��z%��€ƒ��ùÿ��€é��u0��ê`��:˜��o’_ÅF�� IDATxÚ¤’±JAEÏìÄÂJ#Xhe«XØ©ýK±Ó*H:Á°³AölµK#¦X!…MÚ`)(ˆ"¢ÆÌM6$Îfè…éÞ=óÞ»ÏHàtÇè X;g Ê£ ¿I’8ÞFÒnf‘š’šRZFie5yÏf ç�÷Màr®ÚTêýî®çŒÆud½–†Kj3°¸Z²„è¬ +#  1‰îoaZOE#(Ù\`W#˜œà’£Ïè YÞ?‡Œé3ÐÈ5z�»;¤ý É~kì?5²Du`ã:{afàÀ}�oá‹ÍQÿð€Á–`ªq¤ðð[Õþ,͇z�˜0|±$|!È����IEND®B`‚�������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/callee.png���������������������������������������������������0000644�0001750�0001750�00000001075�14517772113�017006� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��ÏIDATxÚbüÿÿ?%� €X`ŒØÜšL 5 ˆ³On™Ÿ[5óÿDZjæççg�  ¢³«2øÿï?ÿƒh$ÂmÉMÿ^ûŠƒä�ˆ)*«2óß¿ÓæOhføþóˆñAâ [¾~ýÊpïÞ=¬$@, Å‹&·1TwLf¨*HÓ &¶0ÄåV¼3‘‘‘aæÌ™X½ÀÃÃÃ�@,_>}X“]øûï?ÃGO€|†o_>­‰µ,ïÐRì vJJÊ™9sæ˜ ™ñ €„‹%ž™ÖÓÌUR˰n^?HÑk`<Šo˜yÈV ÷�ˆ¤ÈxÏðçï?†¿ÿ‚ï,LÅ÷/Ÿ•šJ³°ê®ëž¦@ðhi„€ >}xËpæñ¬€ä�É€? ÀhÓÈàãÛ×O§wÔJc3àßß¿Oˆ  Nl˜ë DOOÏ3Û·oG D€�"h@\ýŒÈgæ9n�0=€£D#B@hüÃ0€P Ü€ï_?¯)(. ùùýëR €aÙ˜dÁ –€`Š€â:°@Ä~�Ä„,$t›é����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/green100.png�������������������������������������������������0000644�0001750�0001750�00000000264�14517772113�017101� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���d��� ���Í~l)��� pHYs�� �� �šœ���tIMEÞ� xîÃo���tEXtComment�Created with The GIMPïd%n���*IDATHÇíÐ1���0d”_|ž-²§ƒ›R K–,Y²d)%ëÛhäšTt8§����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/redo.png�����������������������������������������������������0000644�0001750�0001750�00000001365�14517772113�016514� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������ísO/���tEXtSoftware�Adobe ImageReadyqÉe<��—IDATxÚ„S[HTQ]w¼Meãhz'I)_™¦ö¦aÔÁkLJ°ˆ ú †”¢¨>L+£ÂÀ>$’0-+!ÔJÍ)GsÏÑÔ9÷չ׿´6¬s9k¯³8gï}Y–ŠÜcåÙôSEa¦Ø¤G)º(šzß¶ôSÍ£ F‰&&d°×RV«×él§OX½+ .Zå}“Óèÿ:ˆÖ×ð/,ÔQÊÖö¬^ÍY/\†j“_Z›žœd»TQ „‡ IªˆÕh°Q»²2ž¶àÛwîÖ]SsWm7ÁfåY³#t[le§ŠáôLapx>ucrrJq\ Ž:€´MÃãfüžžSs¢ ‚åI ¦ Ï‚ ß,FFè|÷3Þñj÷ð@¯"2¦ìÉõz½ òa2%áLI1ææƒ<XI̺ȭ*ÙÝ݃i·³Ú5Ô÷‚æçSZ*#„Àn·Ãk„–Õ€+Ϭ(ŠÛy™áy¸Ý.(‡i]üŠÀ´Ï\uÿÞ-Uìÿ³Ǹ~µi+7P «Dèphß7økÅìÌ ²<ÊŠ„¸æýþø½ñ±±HÌ:l³Tú²¸Ðö¤±Þº¦ƒ,ò¥V&.9畹è¸55#Ä?…ææç$)ÿ×—ž.†a©Ô€µcY&ʸ³3&tœ«¬AÜ6¾ 'ÚÛß`Ìé Ma“kèóuLè|�á1 ©õ¦´ŒŠÒ³çgàÀEE`“–…ÏçCUåÅq¯c q=–m‘^õºD‡¢ñöŠ¢“%H߉hÎ@Gw’À‡á±ú/P“øðHÃQíf½UÆîWö4çòrÖóãÊ ‚&áÁ¢é)´J#”BQg=ƒ¿ �7ú+ªCv����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/small_up_focused.png�����������������������������������������0000644�0001750�0001750�00000000247�14517772113�021105� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������—SÆk���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß!1I6���4IDAT×mŠA �@ÃýøæÏz™‚D” I±“™ò± ©Ý\¸6.ÁÅà†ªú Ù -Z•S‹����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/inclusive.png������������������������������������������������0000644�0001750�0001750�00000000533�14517772113�017560� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���©¬w&���tEXtSoftware�Adobe ImageReadyqÉe<���ýIDATxÚt‘oJÃ@ÅßdÓøBðƒö�%¡7(x¿y{£‚ß# ˆ^Áø‡6í ÒñMwÓ…ˆ ÃN~;™}óVTO%�†´€2ì¾(j{ÆÚ”…“úü,s»ýÏÀüŽñΟ ð”–—¹Ë³9\2s›þãmìLŽ<»!OÉ?ïY¬ÏÛþkÐÃÁõûovŠì•qKÞD޵xÍ+êÒ† òúÄ7÷z߀šmãj…Š¿HÂGéÙ:JäÇ %ŒnØ~ͼ‘CŽÜ¤Wtã:LÝMܘÜÜ�Ýèpê­ŸšÃÝÀnØ Ê‚§¼Ä¡Nš—öW€�¦€N„5Û–����IEND®B`‚���������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/bubble_icon_16.png�������������������������������������������0000644�0001750�0001750�00000001147�14517772113�020332� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���tEXtSoftware�Adobe ImageReadyqÉe<�� IDATxÚ”S½kša¿÷Í+(~¼qQ2VDA°1 é íæ¡Î:YÌ¿l‡B'‡R};uˆÄ¨±"‚SED‰QÄÏPÁ¯Þ½Ä`!´zðƒ‡»ûÝÝsÏïaB¡l[*•:‘J¥oÔjõk‰D"'ß|>¿‡?f³Ù—ËÛÎç6‡d2ù\¡P|¶Z­Ç‡, ¨T*16åÅbñ4›Ížæóù›étúÎívÿ¢C$ »V«½òù|<v�Žãà)[,4!‚0êt:/=ÏO1“çù ¿ßÏÛív`–Ëå“(F d2‡/Ðux°Z­Þc%Ÿ×ëÖëõ?A¦Óé ßï?‹F£÷,Þó­ÓéƒÔyP.qˆËáÆõz=à$°‡¸÷%“mx,>Q£Ùl>:vE½^‡ÉdÒ`Ûí¶Ëåö"ÓP7Ðjµ¾³¥RécµZ]þoûÛ@AA:¾EîÖf³ÉQª»IH±X "‘È›ž¡ï8ti4¨T*¢ÊhD³Ù F£”J¥¸0¼+ Èd2P.— µZí÷&þ z…£Á`�@à+êý“Á`°ÅãñW¨Î(iÙƒ„F£t·Û½Äå]£«Ýg¢:M&Ó·^¯' ¶óè¼ ƒôƒ45‚ݼbˆècÎø/y“&w›ŠûÚ�Mž¬ÑihÙƒ����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/time.png�����������������������������������������������������0000644�0001750�0001750�00000000716�14517772113�016520� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ��� ���rëä|���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEßÃc��[IDAT(Ï’±KBqÇ?Ö#BÂÍ!pJñ7 ¹4D“ äîàZÐàä"½?A°AjqušBy¿Éå)â $‘ƒ‚òkñ‰øúNÇÝ}¸ã{âˆLÓÔÛpÓív þ«=0 ÐaBD²@Ö0Œ§õzý(à])µ @"r¼¦Óé{!‹1›Íp‡v»=�î”Rîá„7˲ô15 -"Žˆœœn›L&S­T*ýW«ZkÂáðe¿ßg2™tN¶µ|.— �žçQ*•0 ƒB¡�ð�àÛF£”Ëe¦ÓéÇT«U’ɤŸºÚ‡¾—Ë%µZù|Îp8Äu]R©‰D€Åbðà¯×±m€H$‚iš‹Å�Ðjµ�>ö;»Ùlu¯×ëiù‘ø¡å×"âY–¥ƒÖZëÑh¤ëõºä~ÄöÀÀ-\àxVJ}ù}`"±«´TZ����IEND®B`‚��������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/warnexperiment.png�������������������������������������������0000644�0001750�0001750�00000001435�14517772113�020631� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��¯IDATxÚbüÿÿ?:H/kž¤20Áô™]µYÈ�Ä�2�§7üðþßÿu{OüŸ±xíÿõû΂ù qtµ�Ä„n#|úð~Íìù‹45uìÜüÔ´ô@|8HY=@�auÈÅçUÿ¿þìëÿÝ7¾ƒqbA HB]-@�±0`ÿüù füþû— h§,÷{°8ºB€�Âj@xZI®’’2˜ýç÷0mbbÉZ$\ dö « FäXM)’R5ºzz™a¡a ßÿc¸÷ú'XŽÿÿ{Æ×'f¬=;ÈmY=§ïH €à&äñÙÑÑ1麺º ?ÿücøüý/Ów?Àòßdx´É̾ûÇuó‡qkæMú�@ðXøýûw޵]º¼83˜ÿhûÇo¿~½�Â/.,aJ²cmÁǾ?~þΩ x�-ËE/ƒÏ+†ž3è \fàà{ÉpöÜY†K Çôí>1ˆ 324çð2?» €�‚»àïß¿’ Z”ù)˜ÏÎô6‡Žbpõ6`tçd°1á`pñ2`àýsS�$@,°Äãà÷ Èäñ9þ¾døñ÷;LJc ÇÏßb•eeàfϰ¼Olàûßï,,¸òƒÓ�ˆ š˜þùôqõ…3§nܸÅðïÍy–¯Þþ3`Ø{胭«8ƒ Ѐ ¬W` bƒÄ~üdÈ� x¼~ö`ÊÔ5ÿyâ~ó‡üù„ˆç{Ï¿3È+ýfxýˆ‰aÝz)ˆÚGÿÀbÀ°5 x4}Á&£¢c ,!›ÎÁÅãÃÈÈ$çù|à¾çKEl îãW†Ù�„’@†€ÂˆAže… ƒ¼‰žçaüç��ä¼F¢ÆnT ����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/stop.png�����������������������������������������������������0000644�0001750�0001750�00000001256�14517772113�016547� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������ísO/���tEXtSoftware�Adobe ImageReadyqÉe<��PIDATxÚ|RAkQžD£1›-‹ í!“‹b (Ê‚mô  ô¦¡(x°9¯ÓÜ 6€àAzÈÉ›šB ʦ…Pk5¨ôRD«öPÛ¸û6Ñ$»¾ïÕ,‹&™|ó}_æÍ{Û¶)?11þ›1x’¤äííÆÃf³K®¸•HøŽŽŒ¨nÞýjµîŶ®kW³YB¢·X ‡U7¯cÂè >z–EoÊAžÊåèI¡ )ÃÃI.l� …Ô_¦©¡7àõú}ñ-&hîì¤×—ë�aê^ŽX«¥IŠ2Žìð± ÄoW–é×8'$©øqwW˜Ø6Ÿ¦R¦ëù<™¦YcŒÕ®ÍÌ =ˆÁ…Z–88ç{]¿q\QŸ#ÇC§R)Ñ[¯ìÿój½N{{éQY.–ì L>èúÍc²üè\2é¾ZÑ4ú¤ë™“²¼à¾!¯›ô•1ЇB]¾ ŒëN`èãÇàJ<î“EÕ £v{v–ȲÉêvE¢fð8àtâ�ü’¤vÚm-;?OkKKd[}*¿|%v‘ºpž<Þtzr’ð…‚$ké§››]1Áá@@ˆï ôºTâÒ‹m™fæ c™E^ƒñ¹92 S;2$«Î ~ϯ•‰3éYõ9}f,ñû[¼†80ùÙÒ5Ç�/Qˆy€ø­ÝNǃÁ"FDÆxýc„¸=kÿ%v‡§/E£öÅHÄ …¦/Çb>àî&x‘¨ .jàÎ;àË:û×p•þÿòþ0�ŽWs>pÔ8����IEND®B`‚��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/circleRed.gif������������������������������������������������0000644�0001750�0001750�00000000131�14517772113�017426� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������GIF89a � �€�ç„„ÿÿÿ!þCreated with The GIMP�!ù ��,���� � ��Œ©kྞL²¢:~wƒ¾QX”1æ�;���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/up.png�������������������������������������������������������0000644�0001750�0001750�00000001011�14517772113�016173� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��›IDATxÚbüÿÿ?.°&O$H-â¸IoVbS@L¸4¯Î ÿÿaEPïC6 âcS@  ãYÂá@üÿ÷ççÿ¾¾¦A|8ºZ€�bD÷ÂÒLaM+B1üùô.ÎÂ'ðºÞÄŒˆžþî€�B1`QºXsXí6†_ooa¸–MXaU³ظ™ïÀ†�< 槆ÿýûEHù*†1üûöŒ×N·³Aâ y:z>€�»`V¢�ØæèŠÅ ?ž…Û¸vцôMf&🠎+€‹sH3,툻 €À.øûïÿŠèò… ?žžb`øÿŒW-èkZpDƒø09:z>€�bðû-±(þÍ_ú¬SgM~ÿx=\�ì ¤1–è=‹¡‹:€�Ð΋;9��ö òZ–’¬yRM4@�±@úgH6�¤ €`±@–óAú�u~\d‡@�áŒb@€�ìë:)¥ä™����IEND®B`‚�����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/expandcollaps.png��������������������������������������������0000644�0001750�0001750�00000001676�14517772113�020425� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��PIDATxÚbüÿÿ? ,‹ òRñ@ì Ä\@ü ˆ7ñ¨åë¶3`�Ä3`IDàDAI©<“Ða6..†_ß¾1|xóšáÌš• ïŸ?›³b}>º�6`a˜ÿD=ý<ëàP†WOž0||ûE¯�?ÃÝ3§\º8)~ÕFC�ˆan°çú¬äÿ¿Nûÿïüéÿ׿Íú@b?OýRR²†ˆåÇïß)jšZ ¬?¾3üÿôòׯ ~3\Ÿ1l¿´4¿€�ÛÏ už<I Ãà €˜€!à¥,+ Ôø‚1üþÅ ™œ ÆïÞaä`ËÔÔ#û� €XþþýÇÁþ÷0¼ ?~€ ¸>iÕ·Ž>Åpy×a†¿ÿ0p°²0ˆýÿDZÌÑÍãèþ];@�Óï?~þøô‰èD0jþ÷ó;Ãú;Nqð2ÜçÞÁÀ#{œADé4˜þ&wšÁÚÂb»ƒ«wÈ�€�búðãÇÁë·o! øõ‹aóž \& ÷?Lgàäâ`áf`ùdǰ~önn†{¦2øû–»zfÓ‹Ï_Wœ½y 猿ƒpíú- žžž Ê º &Ö2 «¦½dX·f/?ƒ‘¥$X$ÏÊÆV�@LsÎ]Zwåɳ›NœZ <eE†ÏL¬ RÒR ̬Œ lì Ùµú ܼ¬`ĉƒäÙÙ9Tˆ—?=S3NIp°I>zõZä¯[ÿ˜4ôõØ9ÝÊ ¡'ÎVfÉðñÃ…3÷,SX™¤>ü� €X@€†<fdd, ÒP9vëåKŸ_‚âN‡Žgqs c`eåb¸z{;ÃÖ+'d% Üã´T|ví:ÀðýÛ·%�Ĉœ™€†ð)a Vð /´±wô122dPWWg`cc{ñæÍ› çÎg8súÔµKæ• r¢�öHð= a7þütýú5N.[ Ÿ(ÿýÇ÷o‡Ÿ=~´eÏÖ ë€ü×�„⌜ÆÈȤD@)å@üjÁ ¾O 5��¼\v":ͽs����IEND®B`‚������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/apply_filter.png���������������������������������������������0000644�0001750�0001750�00000001433�14517772113�020251� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR���������óÿa���gAMA��¯È7Šé���tEXtSoftware�Adobe ImageReadyqÉe<��­IDATxÚbüÿÿ?%� €“ j÷Í0²yIÔ{rÞ„& €�bùû÷ŸÃŒî:¸(;œýãç/8ûýû· OŸ<c8}úƒ™™ÃÂåëÌAâ�ÄÄÆ±Ù•gÚjŠqZõãÇ7†Ï>0\¾tžACSƒaÊ `q>¶$€�b†ÁÙ+玄–7t~ÁªùÛ†_¿1ܼq•A[[›aÒ¼µ ïÜ,éùðõû<€�b):üð–ë—Nƕֵ1022¢àß0\¹|žAEE…¡gæ2†7/—>¾{u%HÏß¿�ˆ @ꦖ>ê:¦«'u6À]póêE0=uÑz0ýïïÏú›ºËµ0 ~«ó €˜` ý¸|úø–gïd×00ma˜±xÛ—Oêv®Y`ùXòH÷ŸÂ.ä½bxÍw… €˜ý 2„áÏÏíþüa`bbbè:\ÂØ‘áÿn†?_?­,ùÿ’û*ãÅ¢ ÷¿døû“ €˜ÐíØ½÷ÿüÀȰòô\†KÏ^q\c¸o¹§ðï† ÿöç£ ¿ÿübøû €0 �ºâ÷ß?ÁüùÆÀpãÃ>†+ Oþ|gHÑ þï??¼ƒ~>eØ@,Ø¢îÏŸß ,ÌÌ`~ýùÈpùí&†kÀ4Ög1üýȰñÃ*†2€�bÂfÀß¿˜™™l%=|˲€6~f¸ðj%˜ñ½„hºö@�œŒm=Bþ?õîÿÆ­Ûÿ;åXÿç fø¿ã^-˜ærg�%C5˜Z€�bÄ–MlÝqpqÇ‚Øß¿~þ}Ÿõô‹<eÿeØøc?Ôf(� ¬�• ‡rÿAs*È»Ï5ƒ�@€�ÏïWÆ[œ_����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/icons/small_up.png�������������������������������������������������0000644�0001750�0001750�00000000251�14517772113�017370� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������‰PNG  ��� IHDR��� ������—SÆk���bKGD�ÿ�ÿ�ÿ ½§“��� pHYs�� �� �šœ���tIMEß5¹^ÒG���6IDAT×}ŒQ � BmWr÷¿š})+"a8ô!$aIÝYa¨»5ÝZ$ý…{�YzÉëÜsÀ"SU÷����IEND®B`‚�������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/���������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�017210� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/CoordCalcDataMaster.java���������������������������0000644�0001750�0001750�00000002611�14517772113�023555� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; import java.util.ArrayList; public abstract class CoordCalcDataMaster implements CoordCalcDataReader { public abstract void setCanvasPixels(int visiblePixels); public abstract void edt_revalidate(); // must be called from event dispatch thread public abstract boolean isValid(); // must be called from event dispatch thread public abstract boolean isInitialized(); public abstract void setAbsRowMinHeights(ArrayList<Integer> mins); public abstract void setAbsRowMinHeights(int rowCount, int minPixels); public abstract void setExpandToFill(boolean expands); public abstract void setRowRange(int startrow, int endrow); public abstract void setVisibleRange(double start, double end); } �����������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/CoordCalcTimeImpl.java�����������������������������0000644�0001750�0001750�00000014516�14517772113�023257� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; /** Coordinate Calculator for Timeline Time axis */ public class CoordCalcTimeImpl extends CoordCalcTimeMaster { // adjustable settings private int canvasPixels = 0; private long start_time = 0; private long end_time = 0; // computed private long start_time_align = 0; // used to align start @ data fetch private long time_per_bin = 1; private boolean is_initialized = false; // edt_revalidate() has been called at least once private boolean needs_compute = true; // preferences private final int min_pixels_per_bin = 1; private final int x_margins; // space between TL and ruler public CoordCalcTimeImpl(int canvas_margin) { x_margins = canvas_margin; } // --- canvas geometry /** Sets current canvas width */ public void setCanvasPixels(int visiblePixels) { if (canvasPixels == visiblePixels) { return; } canvasPixels = visiblePixels; needs_compute = true; } /** Gets current canvas width */ public int getCanvasPixels() { return canvasPixels; } // --- time geometry settings public void edt_revalidate() { setTimeBinAlignment(); is_initialized = true; } private void setTimeBinAlignment() { // for a given zoom, determine time alignment of bins so that it is // consistent regardless of panning. long trange = getTimeDuration(); // nanoseconds int maxBinCount = getAvailPixels() / min_pixels_per_bin; long estBinSize; if (maxBinCount <= 0) { estBinSize = 0; } else { estBinSize = (trange + (maxBinCount - 1)) / maxBinCount; } time_per_bin = estBinSize; if (time_per_bin < 1) { time_per_bin = 1; } // compute alignment long absStartTime = 0; // Should it be: getAbsoluteTimeStart() ? long startdelta = start_time - absStartTime; long mod = startdelta % time_per_bin; start_time_align = mod; needs_compute = false; } /** Get the minimum number of pixels allowed for a bin */ private int getMinPixelsPerBin() { return min_pixels_per_bin; } /** margins allow states along edges to be visible and accessible */ public int getMargin() { return x_margins; } public boolean isInitialized() { return is_initialized; } public boolean isValid() { return !needs_compute; } // --- time range public void setTimeRange(long start, long end) { if (start_time == start && end_time == end) { return; } start_time = start; end_time = end; needs_compute = true; } public long getTimeStart() { return start_time; } public long getTimeEnd() { return end_time; } public long getTimeDuration() { long duration = end_time - start_time + 1; return duration; } // ---------- computed values ---------- public int getAvailPixels() { // in pixels int availWidth = getCanvasPixels() - getMargin() * 2; return availWidth; } /** get avail # of bins */ public int getNumBins() { long tmp = getTimeDuration() + time_per_bin - 1; tmp /= time_per_bin; return (int) tmp; } /** get avail # of bins */ public long getTimePerBin() { return time_per_bin; } public long getTimeStartAligned() { long tstart = getTimeStart() - start_time_align; return tstart; } public long getTimeStartAligned(long time) { long absStartTime = 0; // Should it be: getAbsoluteTimeStart() ? // compute alignment if (time < absStartTime) { // punt on handling negative time return absStartTime; } long startdelta = time - absStartTime; long mod = startdelta % time_per_bin; long returnTime = time - mod; return returnTime; } public long getTimeEndAligned() { long tstart = getTimeStartAligned(); int nbins = getNumBins(); long tduration = nbins * time_per_bin; // fills the last bin long tend = tstart + tduration - 1; // != options.getFilterTimeEnd() return tend; } // return may be MPVIEW_CHART_DATA_NAN if click was not on a state public long getTimeAtCoord(int xx) { int x = xx - getMargin(); long totalTime = getTimeDuration(); int availWidth = getAvailPixels(); if (availWidth <= 0) { availWidth = 1; } long time = x * totalTime / availWidth; if (time < 0) { return 0; } if (time >= getTimeDuration()) { return getTimeDuration(); } time += start_time; return time; } // always returns a valid value public long getTimeNearCoord(int xx) { int x = xx - getMargin(); long totalTime = getTimeDuration(); int availWidth = getAvailPixels(); if (availWidth <= 0) { return getTimeStart(); } long time = x * totalTime / availWidth; time += start_time; if (time < getTimeStart()) { time = getTimeStart(); } if (time > getTimeEnd()) { time = getTimeEnd(); } return time; } public int getLowCoordForBin(int bin) { int totalBins = getNumBins(); if (totalBins <= 0) { return 0; } if (bin < 0) { int ii = 0; // breakpoint } int availWidth = getAvailPixels(); int x = bin * availWidth / totalBins; int xx = x + getMargin(); return xx; } public int getCoordAtTime(long time) { long offsetTime = time - start_time; long duration = getTimeDuration(); if (duration <= 0) { return 0; } int availWidth = getAvailPixels(); int x = (int) (offsetTime * availWidth / duration); int xx = x + getMargin(); return xx; } public int getBinAtTime(long time) { long offsetTime = time - start_time; long duration = getTimeDuration(); if (duration <= 0) { return 0; } int totalBins = getNumBins(); int bin = (int) (offsetTime * totalBins / duration); return bin; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/VerticalRowRuler.java������������������������������0000644�0001750�0001750�00000001674�14517772113�023241� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; import java.awt.Graphics; import javax.swing.JComponent; public abstract class VerticalRowRuler extends JComponent { public abstract void setRange(long start_p, long end_p); public abstract void lockRulerThickness(Graphics g, boolean lock); } ��������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/CoordCalcDataReader.java���������������������������0000644�0001750�0001750�00000003544�14517772113�023532� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; public interface CoordCalcDataReader { // pixels public int getMargin(); public int getCanvasPixels(); public int getAvailPixels(); // pixels available for data public int getTotalPixels(); // virtual # of pixels if everything drawn public int getMinPixelsForAllRows(); public int getMinPixelsRequired(int row_lo, int row_hi); // YXXX unused // rows public int getRowStart(); public int getRowEnd(); public int getRowCount(); public int getAbsRowEnd(); // last valid row; zero if getRowCount()=0 public int getAbsRowCount(); // percent visible (used with smooth scrolling) public double getVisibleStart(); public double getVisibleEnd(); public double getVisiblePercent(); // conversions public int getLowCoordForRow(int yrow); public int getCenterCoordForRow(int yrow); public int getHighCoordForRow(int yrow); public double getCenterPercentForRow(int yrow); public double getPercentNearCoord(int canvasY); public double getRowPercentOfTotal(int yrow); public int getRowAtCoord(int canvasY); public int getRowNearCoord(int canvasY); public int getRowNearPercent(double percent); // always returns a valid row } ������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/TimelinePanel.java���������������������������������0000644�0001750�0001750�00000273533�14517772113�022521� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.timeline2.TimelineDraw; import org.gprofng.mpmt.timeline2.TimelineSelectionEvent; import org.gprofng.mpmt.util.gui.AnLongScrollBar; import org.gprofng.mpmt.util.ruler.RangeRuler; import org.gprofng.mpmt.util.ruler.valuetypes.ValuesNanoseconds; import org.gprofng.mpmt.util.zoomruler.OverlayMouseHandler; import org.gprofng.mpmt.util.zoomruler.ZoomRulerEvent; import org.gprofng.mpmt.util.zoomruler.ZoomRulerListener; import org.gprofng.mpmt.util.zoomruler.ZoomRulerOverlay; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.util.ArrayList; import java.util.List; import java.util.Vector; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollBar; import javax.swing.Timer; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; /** * This class provides a JComponent to display a timeline. The timeline shows several processes or * threads of execution simultaneously. Each will be represented by a horizontal bar with the color * of the bar indicating the state at each moment in time. The raw data is provided by a * TimelineProvider object with display options specified by a TimlineOptions objects. * * <p>The timeline provides panning and zooming capabilities. In addition to the state information, * optional message lines can be displayed to show communication between processes. * * <p>To minimize refetches of data from DBE, this class may draw a subset of the data that has been * fetched from DBE and stored in the TimelineProcessStates array. * * <p>With the current implementation, the time interval displayed is exactly what has been fetched * from dbe. In the process direction, however, zoom is allowed to show a subset of the data. */ public class TimelinePanel extends JPanel { // image data private TimelineDrawer tldrawer; private CoordCalcTimeMaster timeAxisCalculator; private CoordCalcDataMaster dataAxisCalculator; // listeners private Vector<ChangeListener> change_listeners; private boolean forceDataReload; // options private final boolean enable_vertical_zoom; private final boolean enable_zoom_overlays; private final boolean enable_vertical_row_snap; private final boolean enable_time_caliper; // zoom and pan history private class ZoomHistoryEvent { public final long timeStart; public final long timeEnd; public final double ypctStart; // used by MPI timeline public final double ypctEnd; // used by MPI timeline public final long timeFocus; public final double timeFocusScreenPercent; public final double ypctFocus; public final double ypctFocusScreenPercent; public final int vZoomLevel; // used by regular timeline public ZoomHistoryEvent( long timeStart, long timeEnd, double ypctStart, double ypctEnd, long timeFocus, double timeFocusScreenPercent, double ypctFocus, double ypctFocusScreenPercent, int vZoomLevel) { this.timeStart = timeStart; this.timeEnd = timeEnd; this.ypctStart = ypctStart; this.ypctEnd = ypctEnd; this.timeFocus = timeFocus; this.timeFocusScreenPercent = timeFocusScreenPercent; this.ypctFocus = ypctFocus; this.ypctFocusScreenPercent = ypctFocusScreenPercent; this.vZoomLevel = vZoomLevel; } public boolean equals(ZoomHistoryEvent e) { if (e.timeStart != this.timeStart || e.timeEnd != this.timeEnd || e.vZoomLevel != this.vZoomLevel) { return false; } double epsilon = 0.0001; if (Math.abs(e.ypctStart - this.ypctStart) > epsilon) { return false; } if (Math.abs(e.ypctEnd - this.ypctEnd) > epsilon) { return false; } return true; } public String toString() { ZoomHistoryEvent e = this; String s = String.format( "[t=(%.1f, %.1f), v=(%.0f, %.0f) z=%d]", e.timeStart / 10000000f, e.timeEnd / 10000000f, e.ypctStart * 100, e.ypctEnd * 100, e.vZoomLevel); return s; } } private List<ZoomHistoryEvent> zoomHistory = new ArrayList(); private int zoomHistoryIdx = 0; // position of next add, can't undo from here private long visible_time_start = 0; // first time visible on screen private long visible_time_end = 0; // last time visible on screen private double visible_ypct_start = 0; // y axis visible start (% of total) private double visible_ypct_end = 0; // y axis visible end (% of total) private boolean zoom_ypct_at_max; // true when at max vertical zoom out private ZoomHistoryEvent referenceEvent; // zoom center private long zoom_time_center; // should be renamed to time_focus private double zoom_time_center_screen_percent; // should be renamed to time_focus_screen_percent private double ypct_focus; // y axis zoom center (% of total) private double ypct_focus_screen_percent; // screen center of time zoom // calipers private TimelineCaliper timeCaliper; /* scrolling state */ private boolean set_vscroll = false; private boolean set_hscroll = false; private boolean hscroll_adjusting = false; private boolean yscroll_adjusting = false; ZoomHistoryEvent scroll_adjusting_snapshot; /* variables for rubberband zoom rectangle */ private static int RUBBERBAND_WIDTH = 2; private boolean rubberbandIs2D = false; /* mouse settings */ private final int MOUSE_PRESS_DRAG_DELAY = 400; // ms before enabled private final int AUTO_PAN_REPEAT_TIME = 100; // ms between updates private final int AUTO_PAN_REGION_PIXELS = 4; // margin where activated private final double AUTO_PAN_RELOCATION_PERCENT = 0.25; // new location percent of screen private final int MOUSE_DRAG_MIN_PIXELS = 2; // pixels before enabled private final int CALIPER_CLICK_PIXEL_TOLERANCE = TimelineDraw.CLICK_PIXEL_TOLERANCE + 0; // yuck, crosses interface public static enum MouseDragMode { MOUSE_RUBBERBANDING_MODE, // zoom MOUSE_GRABBING_MODE, // pan MOUSE_SELECTION_MODE // set/expand selection }; private static enum MouseSubmode { MM_UNKNOWN, MM_HOVER_CALIPER, MM_HOVER_SELECTION, MM_HOVER_GRAB, MM_HOVER_RUBBERBAND, MM_DRAG_CALIPER, // drag-to-adjust caliper MM_DRAG_SELECTION, // drag-to-adjust selection region MM_DRAG_GRAB, // drag-to-pan MM_DRAG_RUBBERBAND, // drag to zoom MM_OVERLAY // nop, pass to overlay }; private MouseDragMode mouse_drag_mode = MouseDragMode.MOUSE_GRABBING_MODE; private boolean global_mouse_drag_mode_changed = true; private final int SMALL_PAN_STEP_FRACTION = 40; // 1/40th of screen step private final int LARGE_PAN_STEP_FRACTION = 5; // 1/5th of screen step private static final boolean MOUSE_WHEEL_ZOOMS = false; // true=>hzoom, false=>vscroll // components private JPanel southPanel; private AnLongScrollBar horScroll; private JScrollBar verScroll; private static final int VERSCROLL_TO_PERCENT = 100000; private static final double PERCENT_TOLERANCE = 0.000001; // YXXX need to restructure private static final double HUNDRED_PERCENT_ROUNDUP = 1.0 - PERCENT_TOLERANCE; private static final double ROW_SNAP_TOLERANCE = 0.01; private JPanel southEastSpacer; private JPanel southWestSpacer; private TimelineCanvas timelineCanvas; private TimelineCursor handcursors; private RangeRuler globalRuler; private RangeRuler localRuler; private VerticalRowRuler verticalRuler; private final MouseDragMode mainPanelDefaultMouseMode; private final MouseDragMode hRulerDefaultMouseMode; private final MouseDragMode vRulerDefaultMouseMode; // zoom overlays private ZoomRulerOverlay timeOverlay = null; private ZoomRulerOverlay processOverlay = null; private OverlayMouseHandler defaultOverlayMouseHandler = new OverlayMouseHandler() { @Override public boolean inOverlay(int x, int y) { return false; } @Override public void deactivate() {} @Override public void activate() {} @Override public Cursor getCursor() { return null; } }; private OverlayMouseHandler overlayMouseHandler = defaultOverlayMouseHandler; /** Creates a new instance of TimelinePanel. Call this from AWT thread only */ public TimelinePanel( final TimelineDrawer tldrawer, final MouseDragMode mainPanelMode, final MouseDragMode hRulerMode, final MouseDragMode vRulerMode) { super(); this.tldrawer = tldrawer; mainPanelDefaultMouseMode = mainPanelMode; hRulerDefaultMouseMode = hRulerMode; vRulerDefaultMouseMode = vRulerMode; this.enable_vertical_zoom = tldrawer.getEnableZoomVertical(); this.enable_zoom_overlays = tldrawer.getEnableZoomOverlays(); this.enable_vertical_row_snap = !tldrawer.getEnableUnalignedRows(); this.enable_time_caliper = tldrawer.getEnableTimeCaliper(); // sync with calculators initAxisCalculators(); change_listeners = new Vector(); handcursors = new TimelineCursor(); timeCaliper = new TimelineCaliper(0, 0); initializeComponents(); // zoomHistoryAdd(); } private void initAxisCalculators() { this.timeAxisCalculator = tldrawer.getTimeAxisMaster(); long zoom_time_start_prev = tldrawer.getAbsoluteTimeStart(); long zoom_time_end_prev = tldrawer.getAbsoluteTimeEnd(); zoom_time_center = (zoom_time_start_prev + zoom_time_end_prev + 1) / 2; zoom_time_center_screen_percent = 0.5; // zoom focus at middle timeAxisCalculator.setTimeRange(zoom_time_start_prev, zoom_time_end_prev); timeAxisCalculator.edt_revalidate(); this.dataAxisCalculator = tldrawer.getDataAxisMaster(); double zoom_ypct_start_prev = 0.0; /* display from 0% */ double zoom_ypct_end_prev = 1.0; /* display to 100% */ ypct_focus = 0.0; /* center at 0% */ ypct_focus_screen_percent = 0.0; // focus at top zoom_ypct_at_max = true; dataAxisCalculator.setVisibleRange( // order matters, do this last zoom_ypct_start_prev, zoom_ypct_end_prev); dataAxisCalculator.edt_revalidate(); } public void edt_resetAll() { // edt only initAxisCalculators(); // Depends on TL2DataSnapshot being reset first zoomHistoryReset(); } public void edt_resetExperiments() { // edt only int ii = 0; } public void edt_resetTLRanges() { zoomYToPercent(1.0); zoomTimeToDuration(tldrawer.getAbsoluteTimeDuration()); ZoomHistoryEvent latest = zoomHistoryCreateEvent(); if (referenceEvent != null && !referenceEvent.equals(latest)) { zoomHistoryReset(); } referenceEvent = latest; } // ----- stuff used by right-hand-tab filter selector public long getFilterTimeStart() { return timeAxisCalculator.getTimeStart(); } public long getFilterTimeEnd() { return timeAxisCalculator.getTimeEnd(); } /** Returns the center time at the current pan offset */ public int getFilterProcStart() { int p; if (zoom_ypct_at_max) { p = 0; } else { p = dataAxisCalculator.getRowStart(); } return p; } public int getFilterProcEnd() { int p; if (zoom_ypct_at_max) { p = tldrawer.getAbsoluteRowEnd(); } else { p = dataAxisCalculator.getRowEnd(); } return p; } /** Force a data refresh and a display update (used by unfilter) */ public void edt_refetchAndRepaint() { // AWT thread only forceDataReload = true; // AWT thread only repaint(); } public void edt_revalidateAll(boolean _forceDataReload) { // AWT thread only if (_forceDataReload) { forceDataReload = true; } // zoomHistoryAdd(); updateY(true); updateX(true); } // ---- listeners for context menu /** Adds a MouseListener to the timeline display */ public void addMouseListener(MouseListener l) { timelineCanvas.addMouseListener(l); verticalRuler.addMouseListener(l); globalRuler.addMouseListener(l); localRuler.addMouseListener(l); } /** Adds a MouseMotionListener to the timeline display */ public void addMouseMotionListener(MouseMotionListener l) { timelineCanvas.addMouseMotionListener(l); } // ----- Zoom to endpoints /** sets zoom endpoints and center.. e.g. rubberband */ private void zoomTimeToRange(long t1, long t2, boolean isPan) { long newstart = t1; long newend = t2; // swap if needed if (newstart > newend) { long tmp = newstart; newstart = newend; newend = tmp; } long delta = newend - newstart; long absEnd = tldrawer.getAbsoluteTimeEnd(); long absStart = tldrawer.getAbsoluteTimeStart(); if (newend > absEnd) { newend = absEnd; if (isPan) { newstart = newend - delta; } } if (newstart < absStart) { newstart = absStart; if (isPan) { newend = newstart + delta; } if (newend > absEnd) { newend = absEnd; } } zoom_time_center = (newstart + newend + 1) / 2; zoom_time_center_screen_percent = 0.5; timeAxisCalculator.setTimeRange(newstart, newend); updateX(false); } /** sets zoom endpoints and center. e.g. rubberband */ private void zoomProcessToRange(int start_p, int end_p, boolean isPan) { int newstart = start_p; int newend = end_p; // swap if needed if (newstart > newend) { // swap if needed int tmp = newstart; newstart = newend; newend = tmp; } int delta = newend - newstart; if (!isPan) { // for zooms, update zoom_proc_at_max int range = delta + 1; zoom_ypct_at_max = (range >= tldrawer.getAbsoluteRowCount()); } if (newend > tldrawer.getAbsoluteRowEnd()) { newend = tldrawer.getAbsoluteRowEnd(); if (isPan) { newstart = newend - delta; } } if (newstart < 0) { newstart = 0; if (isPan) { newend = newstart + delta; } if (newend > tldrawer.getAbsoluteRowEnd()) { newend = tldrawer.getAbsoluteRowEnd(); } } ypct_focus = (newstart + newend + 1) / 2; ypct_focus_screen_percent = 0.5; dataAxisCalculator.setRowRange(newstart, newend); updateY(false); } /** sets zoom endpoints and center. e.g. rubberband */ private void zoomYToRange(double start_pct, double end_pct, boolean isPan) { double newstart = start_pct; double newend = end_pct; // swap if needed if (newstart > newend) { double tmp = newstart; newstart = newend; newend = tmp; } double delta = newend - newstart; if (!isPan) { // for zooms, update zoom_proc_at_max zoom_ypct_at_max = (delta >= HUNDRED_PERCENT_ROUNDUP); } if (enable_vertical_row_snap) { int start_p, end_p; if (isPan) { int num_p = dataAxisCalculator.getRowCount(); double slop = 1.0 / (dataAxisCalculator.getAbsRowEnd() + 1) * ROW_SNAP_TOLERANCE; double start_pct_rounded = newstart + slop; start_p = dataAxisCalculator.getRowNearPercent(start_pct_rounded); end_p = start_p + num_p - 1; } else { start_p = dataAxisCalculator.getRowNearPercent(newstart); end_p = dataAxisCalculator.getRowNearPercent(newend); } zoomProcessToRange(start_p, end_p, isPan); return; } // contrain the zoom level if (!isPan) { double min_percent = 1.0 / (dataAxisCalculator.getAbsRowEnd() + 1); if (delta < min_percent) { delta = min_percent; double center = (newstart + newend) / 2; newstart = center - delta / 2; newend = center + delta / 2; } } if (newend > HUNDRED_PERCENT_ROUNDUP) { newend = 1.0; if (isPan) { newstart = newend - delta; } } if (newstart < 0.0) { newstart = 0.0; if (isPan) { newend = newstart + delta; } if (newend > HUNDRED_PERCENT_ROUNDUP) { newend = 1.0; } } ypct_focus = (newstart + newend) / 2; ypct_focus_screen_percent = 0.5; dataAxisCalculator.setVisibleRange(newstart, newend); updateY(false); } // --- zoom to a fixed scale using existing zoom center /** zoom to a fixed scale using existing zoom center, e.g. zoom slider */ private void zoomTimeToDuration(long duration) { if (duration < 1) { duration = 1; } else if (duration > tldrawer.getAbsoluteTimeDuration()) { duration = tldrawer.getAbsoluteTimeDuration(); } long newstart = zoom_time_center - (long) (zoom_time_center_screen_percent * duration); if (newstart < tldrawer.getAbsoluteTimeStart()) newstart = tldrawer.getAbsoluteTimeStart(); long newend = newstart + (duration - 1); if (newend > tldrawer.getAbsoluteTimeEnd()) { newend = tldrawer.getAbsoluteTimeEnd(); newstart = newend - (duration - 1); } timeAxisCalculator.setTimeRange(newstart, newend); updateX(false); } /** zoom to a fixed scale using existing zoom center, e.g. zoom slider */ private void zoomProcessToCount(int procCount) { zoom_ypct_at_max = (procCount >= tldrawer.getAbsoluteRowCount()); if (procCount < 1) { procCount = 1; } else if (procCount > tldrawer.getAbsoluteRowCount()) { procCount = tldrawer.getAbsoluteRowCount(); } int zoom_proc_center = dataAxisCalculator.getRowNearPercent(ypct_focus); int newstart = zoom_proc_center - procCount / 2; // YXXX probably should be something like below, but needs testing // - (long)(ypct_focus_screen_percent * procCount); if (newstart < 0) newstart = 0; int newend = newstart + (procCount - 1); if (newend > tldrawer.getAbsoluteRowEnd()) { newend = tldrawer.getAbsoluteRowEnd(); newstart = newend - (procCount - 1); } dataAxisCalculator.setRowRange(newstart, newend); updateY(false); } /** zoom to a fixed scale using existing zoom center, e.g. zoom slider */ private void zoomYToPercent(double percent) { zoom_ypct_at_max = (percent >= HUNDRED_PERCENT_ROUNDUP); if (enable_vertical_row_snap) { int procCount = (int) (dataAxisCalculator.getAbsRowCount() * (percent + PERCENT_TOLERANCE)); if (procCount < 1) { procCount = 1; } zoomProcessToCount(procCount); return; } // contrain the zoom level double min_percent = 1.0 / (dataAxisCalculator.getAbsRowEnd() + 1); if (percent < min_percent) { percent = min_percent; } else if (percent >= HUNDRED_PERCENT_ROUNDUP) { percent = 1.0; } double newstart = ypct_focus - ypct_focus_screen_percent * percent; if (newstart < 0.0) { newstart = 0.0; } double newend = newstart + percent; if (newend >= HUNDRED_PERCENT_ROUNDUP) { newend = 1.0; newstart = newend - percent; } dataAxisCalculator.setVisibleRange(newstart, newend); updateY(false); } // --- zoom by step /** Zoom in by a factor of 2 */ public void zoomTimeIn() { zoomHistoryAdd(); long duration = timeAxisCalculator.getTimeDuration() / 2; zoomTimeToDuration(duration); } /** Zoom out by a factor of 2 */ public void zoomTimeOut() { zoomHistoryAdd(); long duration = timeAxisCalculator.getTimeDuration() * 2; zoomTimeToDuration(duration); } /** Zoom in by a factor of 2 */ public void zoomProcessIn() { zoomHistoryAdd(); double range = dataAxisCalculator.getVisiblePercent() / 2; zoomYToPercent(range); } /** Zoom out by a factor of 2 */ public void zoomProcessOut() { zoomHistoryAdd(); double range = dataAxisCalculator.getVisiblePercent() * 2; zoomYToPercent(range); } // -----Compute Zoom levels used by Zoom slider widgets public int getZoomTimeLevelMax() { return getZoomLevel(tldrawer.getAbsoluteTimeDuration(), 0); } public int getZoomProcessLevelMax() { return getZoomLevel(tldrawer.getAbsoluteRowCount(), 0); } public int getZoomTimeLevel() { long absolute = tldrawer.getAbsoluteTimeDuration(); long current = timeAxisCalculator.getTimeDuration(); int level = getZoomLevel(absolute, current); return level; } public int getZoomProcessLevel() { long totalnp = tldrawer.getAbsoluteRowCount(); long current; if (zoom_ypct_at_max) { current = totalnp; } else { current = (long) (totalnp * dataAxisCalculator.getVisiblePercent()); } int level = getZoomLevel(totalnp, current); return level; } /** Compute the nearest level for a segment within max */ private int getZoomLevel(long max, long segment) { int i = 0; long lt = max; while (lt > segment) { lt >>= 1; i++; } return i; } private long getZoomMultiplier(int lev) { long mult = 1L << lev; return mult; } // --- zoom to level public void zoomTimeToLevel(int lev) { zoomHistoryAdd(); long multiplier = getZoomMultiplier(lev); long abs_count = tldrawer.getAbsoluteTimeDuration(); long desired_count = abs_count / multiplier; zoomTimeToDuration(desired_count); } public void zoomProcessToLevel(int lev) { zoomHistoryAdd(); long multiplier = getZoomMultiplier(lev); double percent = 1.0 / multiplier; zoomYToPercent(percent); } // --- reset and revert zoom /** Reset zoom to show entire time and process range */ public void resetZoom() { zoomHistoryAdd(); zoomTimeToDuration(tldrawer.getAbsoluteTimeDuration()); zoomYToPercent(1.0); // YXXX does double paint } public void zoomCenterSelection() { if (tldrawer.selectionActive()) { zoomHistoryAdd(); tldrawer.zoomCenterSelection(); ypct_focus = tldrawer.getSelectionYCenter(); ypct_focus_screen_percent = 0.5; zoom_time_center = tldrawer.getSelectionTimeCenter(); zoom_time_center_screen_percent = 0.5; zoomTimeToDuration(timeAxisCalculator.getTimeDuration()); zoomYToPercent(dataAxisCalculator.getVisiblePercent()); } } private double calcTimeScreenPercent(long tstamp) { final double deltat = tstamp - timeAxisCalculator.getTimeStart(); final long duration = timeAxisCalculator.getTimeDuration(); if (duration < 1) { return 0; // weird } double screenPercent = deltat / duration; if (screenPercent > 1.0) { screenPercent = 1.0; // weird } else if (screenPercent < 0.0) { screenPercent = 0.0; // weird } return screenPercent; } private double calcYpctScreenPercent(double ypct) { final double deltat = ypct - dataAxisCalculator.getVisibleStart(); final double visible = dataAxisCalculator.getVisiblePercent(); if (visible == 0) { return 0; // weird } double screenPercent = deltat / visible; if (screenPercent > 1.0) { screenPercent = 1.0; // weird } else if (screenPercent < 0.0) { screenPercent = 0.0; // weird } return screenPercent; } // --- zoomHistory internal and external functions private static boolean dumpHistory = false; private void zoomHistoryReset() { zoomHistory.clear(); zoomHistoryIdx = 0; zoomHistoryNotifyListeners(); } public boolean zoomHistoryAtMax() { validate_zoomHistoryIdx(); if (zoomHistoryIdx >= zoomHistory.size() - 1) { return true; } return false; } public boolean zoomHistoryAtMin() { validate_zoomHistoryIdx(); if (zoomHistoryIdx == 0) { return true; } return false; } public void zoomHistoryAdd() { ZoomHistoryEvent e = zoomHistoryCreateEvent(); zoomHistoryAdd(e); } private void zoomHistoryAdd(ZoomHistoryEvent e) { validate_zoomHistoryIdx(); for (int ii = zoomHistory.size() - 1; ii >= zoomHistoryIdx; ii--) { zoomHistory.remove(ii); } int prev_frame = zoomHistoryIdx - 1; if (prev_frame >= 0 && prev_frame < zoomHistory.size()) { ZoomHistoryEvent old_e = zoomHistory.get(prev_frame); if (e.equals(old_e)) { if (dumpHistory) System.out.printf( "HistoryAdd@%d: skipping - exact match: %s\n", zoomHistoryIdx, e.toString()); // debug zoomHistoryNotifyListeners(); return; } } zoomHistory.add(e); zoomHistoryIdx = zoomHistory.size(); if (dumpHistory) System.out.printf("HistoryAdd@%d: %s\n", zoomHistoryIdx, e.toString()); // debug // // if(debugHistory)System.out.printf("HistoryAdd@%d:\n%s",zoomHistoryIdx,zoomHistoryDump().toString()); // debug zoomHistoryNotifyListeners(); } public void undoZoom() { if (zoomHistoryAtMin()) { return; } // remember where we came from: ZoomHistoryEvent e = zoomHistoryCreateEvent(); if (zoomHistoryIdx > zoomHistory.size() - 1) { zoomHistory.add(e); } else { zoomHistory.set(zoomHistoryIdx, e); } if (dumpHistory) System.out.printf( "HistoryUndo@%d: updated %d: %s\n", zoomHistoryIdx - 1, zoomHistoryIdx, e.toString()); // debug // restore zoom e = zoomHistory.get(--zoomHistoryIdx); // // if(debugHistory)System.out.printf("HistoryUndo@%d:\n%s",zoomHistoryIdx,zoomHistoryDump().toString()); // debug zoomHistoryDoZoom(e); zoomHistoryNotifyListeners(); } public void redoZoom() { if (zoomHistoryAtMax()) { return; } // remember where we came from: ZoomHistoryEvent e = zoomHistoryCreateEvent(); zoomHistory.set(zoomHistoryIdx, e); if (dumpHistory) System.out.printf( "HistoryRedo@%d: updated %d: %s\n", zoomHistoryIdx, zoomHistoryIdx, e.toString()); // debug // restore zoom e = zoomHistory.get(++zoomHistoryIdx); // // if(debugHistory)System.out.printf("HistoryRedo@%d:\n%s",zoomHistoryIdx,zoomHistoryDump().toString()); // debug zoomHistoryDoZoom(e); zoomHistoryNotifyListeners(); } private void validate_zoomHistoryIdx() { if (zoomHistoryIdx > zoomHistory.size()) { if (dumpHistory) System.out.printf( "HistoryValidate fail: idx=%d size=@%d\n", zoomHistoryIdx, zoomHistory.size()); // debug zoomHistoryIdx = zoomHistory.size(); // weird } else if (zoomHistoryIdx < 0) { if (dumpHistory) System.out.printf( "HistoryValidate fail: idx=%d size=@%d\n", zoomHistoryIdx, zoomHistory.size()); // debug zoomHistoryIdx = 0; // weird } } private ZoomHistoryEvent zoomHistoryCreateEvent() { ZoomHistoryEvent e = new ZoomHistoryEvent( timeAxisCalculator.getTimeStart(), timeAxisCalculator.getTimeEnd(), dataAxisCalculator.getVisibleStart(), dataAxisCalculator.getVisibleEnd(), zoom_time_center, zoom_time_center_screen_percent, ypct_focus, ypct_focus_screen_percent, AnWindow.getInstance().getSettings().getTimelineSetting().getTLStackDepth()); return e; } private StringBuffer zoomHistoryDump() { StringBuffer sb = new StringBuffer(); for (int ii = 0; ii < zoomHistory.size(); ii++) { if (ii == zoomHistoryIdx) { sb.append(" *"); } else { sb.append(" "); } sb.append(String.format("%2d: %s\n", ii, zoomHistory.get(ii).toString())); } return sb; } private void zoomHistoryNotifyListeners() { TimelineSelectionHistoryEvent e = new TimelineSelectionHistoryEvent(zoomHistoryAtMin(), zoomHistoryAtMax()); tldrawer.notifyZoomHistoryChange(e); } private void zoomHistoryDoZoom(ZoomHistoryEvent e) { zoom_time_center = e.timeFocus; zoom_time_center_screen_percent = e.timeFocusScreenPercent; ypct_focus = e.ypctFocus; ypct_focus_screen_percent = e.ypctFocusScreenPercent; AnWindow.getInstance() .getSettings() .getTimelineSetting() .setTLStackDepth(TimelinePanel.this, e.vZoomLevel); // delayed :( zoomTimeToRange(e.timeStart, e.timeEnd, false); zoomYToRange(e.ypctStart, e.ypctEnd, false); zoom_time_center = e.timeFocus; zoom_time_center_screen_percent = e.timeFocusScreenPercent; ypct_focus = e.ypctFocus; ypct_focus_screen_percent = e.ypctFocusScreenPercent; // YXXX does double paint } // --- mouse and rubberbanding modes /** * Set Mouse Mode to MOUSE_GRABBING_MODE or MOUSE_RUBBERBANDING_MODE The modes differ in how to * process mouse drags. MOUSE_GRABBING_MODE - a drag pans MOUSE_RUBBERBANDING_MODE - a drag draws * a rectangle for zooming Both modes select objects with a single click and zoom and center on a * double click. */ public void setMouseMode(MouseDragMode mode) { if (mouse_drag_mode != mode) { mouse_drag_mode = mode; global_mouse_drag_mode_changed = true; } } /** Return mouse mode */ public MouseDragMode getMouseMode() { return mouse_drag_mode; } /** Set type of rubberbanding to use */ public void setRubberbandIs2D(boolean is2d) { rubberbandIs2D = is2d; } /** Add a listener for changes to the range of the display */ public void addChangeListener(ChangeListener listener) { change_listeners.add(listener); } /** Notify change listeners of a zoom or pan */ private void notifyListeners() { ChangeEvent event = new ChangeEvent(this); for (ChangeListener listener : change_listeners) { listener.stateChanged(event); } } private int limitCoord(int initialCoord, int max) { int coord = initialCoord; if (coord < 0) { coord = 0; } else if (coord >= max) { coord = max - 1; } return coord; } /** * Main routine to layout the timeline with the following components. timelineCanvas - central * drawing area to display the timeline globalRuler - ruler showing the global range on the bottom * of the timeline. localRuler - ruler that shows the width of the current display. verticalRuler * - ruler with the process labels. horScroll - time Scrollbar on the bottom of the timeline. * verScroll - process scrollbar on the right side of the display. */ private void initializeComponents() { this.setLayout(new BorderLayout()); southPanel = new JPanel(); southPanel.setLayout(new BorderLayout()); this.add(southPanel, BorderLayout.SOUTH); /* south: graph's horizontal scrollbar */ horScroll = new AnLongScrollBar(JScrollBar.HORIZONTAL); horScroll.addLongAdjustmentListener( new AnLongScrollBar.LongAdjustmentListener() { public void adjustmentValueChanged(AnLongScrollBar.LongAdjustmentEvent adjustmentEvent) { if (set_hscroll) { /* ignore events while adjusting geometry */ return; } { if (scroll_adjusting_snapshot == null) { scroll_adjusting_snapshot = zoomHistoryCreateEvent(); } hscroll_adjusting = true; long newstart = adjustmentEvent.getValue(); panTimeTo(newstart); hscroll_adjusting = false; if (!adjustmentEvent.getValueIsAdjusting()) { zoomHistoryAdd(scroll_adjusting_snapshot); scroll_adjusting_snapshot = null; } } } }); southPanel.add(BorderLayout.CENTER, horScroll); /* east: scroll bar for processes */ verScroll = new JScrollBar(JScrollBar.VERTICAL); verScroll.addAdjustmentListener( new AdjustmentListener() { public void adjustmentValueChanged(AdjustmentEvent adjustmentEvent) { if (set_vscroll) { /* ignore events while adjusting geometry */ return; } { if (scroll_adjusting_snapshot == null) { scroll_adjusting_snapshot = zoomHistoryCreateEvent(); } yscroll_adjusting = true; double newstart; if (enable_vertical_row_snap) { int proc = verScroll.getValue(); int yy = dataAxisCalculator.getLowCoordForRow(proc); newstart = dataAxisCalculator.getPercentNearCoord(yy); } else { newstart = verScroll.getValue(); newstart /= VERSCROLL_TO_PERCENT; } panProcTo(newstart); yscroll_adjusting = false; if (!adjustmentEvent.getValueIsAdjusting()) { zoomHistoryAdd(scroll_adjusting_snapshot); scroll_adjusting_snapshot = null; } } } }); this.add(verScroll, BorderLayout.EAST); /* north: time ruler */ ValuesNanoseconds vtype = new ValuesNanoseconds(timeAxisCalculator.getTimeStart(), timeAxisCalculator.getTimeEnd()); globalRuler = new RangeRuler(vtype, RangeRuler.HORIZONTAL_ORIENTATION); globalRuler.setTitlePlacement(localRuler.PLACEMENT_WITH_LABELS); globalRuler.setTitle(AnLocale.getString("Time")); globalRuler.setTickPlacement(RangeRuler.TICKS_ON_THE_BOTTOM); globalRuler.setUseTickCenterForUnitSteps(true); TimelineMouseAdapter globalRulerMouseAdapter = new TimelineMouseAdapter( globalRuler, MousePanelType.MP_X_RULER, hRulerDefaultMouseMode, MouseDragMode.MOUSE_RUBBERBANDING_MODE); globalRuler.addMouseWheelListener(globalRulerMouseAdapter); globalRuler.addMouseMotionListener(globalRulerMouseAdapter); globalRuler.addMouseListener(globalRulerMouseAdapter); this.add(globalRuler, BorderLayout.NORTH); /* south panel's relative scale ruler */ vtype = new ValuesNanoseconds(0, timeAxisCalculator.getTimeDuration()); localRuler = new RangeRuler(vtype, RangeRuler.HORIZONTAL_ORIENTATION); localRuler.setTitlePlacement(localRuler.PLACEMENT_WITH_LABELS); localRuler.setTitle(AnLocale.getString("Relative")); localRuler.setTickPlacement(RangeRuler.TICKS_ON_THE_TOP); localRuler.setUseTickCenterForUnitSteps(false); TimelineMouseAdapter localRulerMouseAdapter = new TimelineMouseAdapter( localRuler, MousePanelType.MP_X_RULER, hRulerDefaultMouseMode, MouseDragMode.MOUSE_RUBBERBANDING_MODE); localRuler.addMouseWheelListener(localRulerMouseAdapter); localRuler.addMouseMotionListener(localRulerMouseAdapter); localRuler.addMouseListener(localRulerMouseAdapter); southPanel.add(BorderLayout.NORTH, localRuler); /* south: spacer to east of scrollbar */ southEastSpacer = new JPanel(); southPanel.add(BorderLayout.EAST, southEastSpacer); /* south: spacer to west of scrollbar */ southWestSpacer = new JPanel(); southPanel.add(BorderLayout.WEST, southWestSpacer); /* The canvas is where the timeline is drawn */ timelineCanvas = new TimelineCanvas(); { // YXXX is this the right place vs. AnWindow or TL2Disp/MPITLDisp? AccessibleContext ac = timelineCanvas.getAccessibleContext(); if (ac != null) { String accessibleName = AnLocale.getString("Timeline"); // YXXX what should text be? String accessibleDescription = AnLocale.getString("Timeline shows experiment activity vs. time"); ac.setAccessibleName(accessibleName); ac.setAccessibleDescription(accessibleName); } } TimelineMouseAdapter timelineMouseAdapter = new TimelineMouseAdapter(timelineCanvas, MousePanelType.MP_MAIN_PANEL, mainPanelDefaultMouseMode, MouseDragMode.MOUSE_RUBBERBANDING_MODE); timelineCanvas.addMouseWheelListener(timelineMouseAdapter); timelineCanvas.addMouseMotionListener(timelineMouseAdapter); timelineCanvas.addMouseListener(timelineMouseAdapter); // zoom sliders. Dimensions are used for timelineCanvas if (enable_zoom_overlays) { initZoomOverlays(timelineCanvas); int overlaySz = timeOverlay.getWidth(); timelineCanvas.setPreferredSize(new Dimension(overlaySz, overlaySz)); timelineCanvas.setMinimumSize(new Dimension(overlaySz, overlaySz)); } this.add(timelineCanvas, BorderLayout.CENTER); /* west: vertical ruler for processes */ verticalRuler = tldrawer.getVerticalRuler(); TimelineMouseAdapter vRulerMouseAdapter = new TimelineMouseAdapter( verticalRuler, MousePanelType.MP_Y_RULER, vRulerDefaultMouseMode, null); verticalRuler.addMouseWheelListener(vRulerMouseAdapter); verticalRuler.addMouseMotionListener(vRulerMouseAdapter); verticalRuler.addMouseListener(vRulerMouseAdapter); this.add(verticalRuler, BorderLayout.WEST); tldrawer.addSelectionListener( new TimelineSelectionListener() { public void valueChanged(TimelineSelectionGenericEvent ge) { if (ge instanceof TimelineSelectionEvent) { // update caliper TimelineSelectionEvent rowTimeEvent = (ge instanceof TimelineSelectionEvent) ? (TimelineSelectionEvent) ge : null; boolean shift = false; boolean updateCaliper = true; if (rowTimeEvent != null) { if (rowTimeEvent.shiftKey) { shift = true; } if (!rowTimeEvent.requestCaliperUpdate) { updateCaliper = false; } if (rowTimeEvent.moveAxis == rowTimeEvent.moveAxis.LEFT_RIGHT) { long eventTimeStart = tldrawer.getSelectionTimeStart(); long eventTimeEnd = tldrawer.getSelectionTimeEnd(); panLeftRightToMakeVisible(eventTimeStart, eventTimeEnd); } else if (rowTimeEvent.moveAxis == rowTimeEvent.moveAxis.UP_DOWN) { double yCenter = tldrawer.getSelectionYCenter(); panUpDownToMakeVisible(yCenter); } else { // direct or restored selection (not cursor move) if (tldrawer.selectionActive()) { double yCenter = tldrawer.getSelectionYCenter(); panUpDownToMakeVisible(yCenter); } else { int ii = 1; // weird } } } if (updateCaliper) { long timeLow = tldrawer.getSelectionTimeStart(); long timeHigh = tldrawer.getSelectionTimeEnd(); caliperUtilSetAndNotify(timeLow, timeHigh, shift); } } else { int ii = 1; // for breakpoint } } }); this.revalidate(); // needed after adding components } private void panUpDownToMakeVisible(double yCenter) { ZoomHistoryEvent e = zoomHistoryCreateEvent(); final double recenterPercentOfScreen = AUTO_PAN_RELOCATION_PERCENT; // Y axis ypct_focus = yCenter; final double visibleStart = dataAxisCalculator.getVisibleStart(); final double visibleEnd = dataAxisCalculator.getVisibleEnd(); final double vizPercent = dataAxisCalculator.getVisiblePercent(); if (ypct_focus <= visibleStart) { zoomHistoryAdd(e); ypct_focus_screen_percent = recenterPercentOfScreen; double newStart = ypct_focus - vizPercent * recenterPercentOfScreen; panProcTo(newStart); } else if (ypct_focus >= visibleEnd) { zoomHistoryAdd(e); ypct_focus_screen_percent = 1 - recenterPercentOfScreen; double newStart = ypct_focus - vizPercent * (1 - recenterPercentOfScreen); panProcTo(newStart); } else { ypct_focus_screen_percent = calcYpctScreenPercent(ypct_focus); } } private void panLeftRightToMakeVisible(long eventTimeStart, long eventTimeEnd) { ZoomHistoryEvent e = zoomHistoryCreateEvent(); double recenterPercentOfScreen = AUTO_PAN_RELOCATION_PERCENT; // Time axis zoom_time_center = (eventTimeStart + eventTimeEnd) / 2; final long visibleTimeStart = timeAxisCalculator.getTimeStart(); final long visibleTimeEnd = timeAxisCalculator.getTimeEnd(); final long visibleDuration = timeAxisCalculator.getTimeDuration(); if (visibleDuration < 5) { // with very few ns of time, percentage doesn't work, pick middle. recenterPercentOfScreen = 0.51; } if (eventTimeEnd < visibleTimeStart) { zoomHistoryAdd(e); zoom_time_center_screen_percent = recenterPercentOfScreen; zoomTimeToDuration(visibleDuration); } else if (eventTimeStart > visibleTimeEnd) { zoomHistoryAdd(e); zoom_time_center_screen_percent = 1 - recenterPercentOfScreen; zoomTimeToDuration(visibleDuration); } else { zoom_time_center_screen_percent = calcTimeScreenPercent(zoom_time_center); } } // === Mouse handlers private static enum MousePanelType { MP_MAIN_PANEL, MP_X_RULER, MP_Y_RULER }; private class TimelineMouseAdapter extends MouseAdapter { /* mouse dragging */ private ZoomHistoryEvent history_start_drag; private int x_start_drag = 0; private int y_start_drag = 0; private int caliperStepX = 0; private int caliperX = 0; private int recent_mouse_button = -1; private long x_start_drag_timeOffset; private double y_start_drag_percentOffset; private Timer mousePressedTimer = null; private Timer autoScrollTimer; private final MousePanelType parentPanelType; private final JComponent parentPanel; private MouseSubmode mouseSubmode = MouseSubmode.MM_UNKNOWN; private final MouseDragMode altDragAction; private final MouseDragMode dragAction; // if null, use global mouse_mode private final boolean x_is_live, y_is_live; public TimelineMouseAdapter( JComponent _parentPanel, MousePanelType _mmode, MouseDragMode _dragAction, MouseDragMode _altDragAction) { parentPanel = _parentPanel; parentPanelType = _mmode; dragAction = _dragAction; altDragAction = _altDragAction; x_is_live = (parentPanelType == MousePanelType.MP_MAIN_PANEL || parentPanelType == MousePanelType.MP_X_RULER); y_is_live = (parentPanelType == MousePanelType.MP_MAIN_PANEL || parentPanelType == MousePanelType.MP_Y_RULER); autoScrollTimer = new Timer( AUTO_PAN_REPEAT_TIME, new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { // user timer to scroll if (x_is_live) { long curStart = timeAxisCalculator.getTimeStart(); long binTime = timeAxisCalculator.getTimePerBin(); long newTime = curStart + binTime * caliperStepX / 3; panTimeTo(newTime); switch (getMouseSubmode()) { case MM_DRAG_CALIPER: case MM_DRAG_SELECTION: { long time = timeAxisCalculator.getTimeNearCoord(caliperX); timeCaliper.setActiveCaliperTime(time); caliperUtilNotify(timeCaliper); break; } default: int ii = 1; // weird break; } } } }); autoScrollTimer.setRepeats(true); } private boolean killMousePressedTimer() { if (mousePressedTimer != null) { mousePressedTimer.stop(); mousePressedTimer = null; return true; } return false; } private void checkAutoScrollTimer(MouseEvent e) { int scrollzonePixels = AUTO_PAN_REGION_PIXELS; int rightScrollzonePixels = timeAxisCalculator.getAvailPixels() - scrollzonePixels; caliperStepX = 0; final int ix = translateX(e); if (ix > rightScrollzonePixels) { caliperStepX = ix - rightScrollzonePixels; } else if (scrollzonePixels > ix) { caliperStepX = -(scrollzonePixels - ix); } if (caliperStepX != 0) { // auto-pan needed caliperX = ix; if (!autoScrollTimer.isRunning()) { autoScrollTimer.start(); } } else { // turn off auto-pan autoScrollTimer.stop(); } } // === track ctrl-key events to change mouse state // couldn't figure out which JComponent's getInputMap() is needed: // private boolean ctrlKeyDown = false; // private void initCtrlKeyListener(){ // String ks_string; // KeyStroke ks_def; // ks_string = "_CONTROLPRESSED"; // ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, // InputEvent.CTRL_DOWN_MASK, false); // parentPanel.getInputMap(JComponent.WHEN_FOCUSED).put(ks_def, ks_string); // parentPanel.getActionMap().put(ks_string, new AbstractAction() { // @Override // public void actionPerformed(ActionEvent ev) { // ctrlKeyDown = true; // // parentPanel.setCursor(handcursors.getCursor(TimelineCursor.OPEN_HAND_CURSOR)); // } // }); // // ks_string = "_CONTROLRELEASED"; // ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, // InputEvent.CTRL_DOWN_MASK, true); // parentPanel.getInputMap(JComponent.WHEN_FOCUSED).put(ks_def, ks_string); // parentPanel.getActionMap().put(ks_string, new AbstractAction() { // @Override // public void actionPerformed(ActionEvent ev) { // ctrlKeyDown = false; // // parentPanel.setCursor(handcursors.getCursor(TimelineCursor.CLOSED_HAND_CURSOR)); // } // }); // } // === translate coordinates from rulers to pmain panel private int translateX(MouseEvent e) { // translate to main panel coordinates if (!x_is_live) { return Integer.MIN_VALUE; } // YXXX ugly switch on global object final int x_offset; if (e.getComponent() == globalRuler) { x_offset = globalRuler.getPaddingLow() - timeAxisCalculator.getMargin(); } else if (e.getComponent() == localRuler) { x_offset = localRuler.getPaddingLow() - timeAxisCalculator.getMargin(); } else if (e.getComponent() == verticalRuler) { x_offset = 0; } else { x_offset = 0; } final int ix = e.getX() - x_offset; return ix; } private int translateY(MouseEvent e) { // translate to main panel coordinates if (!y_is_live) { return Integer.MIN_VALUE; } return e.getY(); } private boolean coord_is_live(int ix) { if (ix == Integer.MIN_VALUE) { return false; } return true; } // === timeline mouse modes, Submodes private MouseSubmode getMouseSubmode() { return mouseSubmode; } private void setMouseSubmode(final MouseSubmode newMode) { // sets mouseSubmode and panel's cursor if (mouseSubmode == newMode && !global_mouse_drag_mode_changed) { return; } global_mouse_drag_mode_changed = false; mouseSubmode = newMode; parentPanel.setCursor(getSubmodeCursor(newMode)); } private Cursor getSubmodeCursor(MouseSubmode submode) { switch (submode) { case MM_OVERLAY: return overlayMouseHandler.getCursor(); case MM_DRAG_RUBBERBAND: case MM_HOVER_RUBBERBAND: return handcursors.getCursor(Cursor.TEXT_CURSOR); case MM_DRAG_GRAB: return handcursors.getCursor(TimelineCursor.CLOSED_HAND_CURSOR); case MM_HOVER_GRAB: return handcursors.getCursor(Cursor.DEFAULT_CURSOR); case MM_DRAG_SELECTION: case MM_HOVER_SELECTION: return handcursors.getCursor(Cursor.CROSSHAIR_CURSOR); case MM_DRAG_CALIPER: case MM_HOVER_CALIPER: return handcursors.getCursor(Cursor.E_RESIZE_CURSOR); } return handcursors.getCursor(Cursor.DEFAULT_CURSOR); // weird, should not happen } private MouseSubmode convertHoverToDrag(MouseSubmode hoverMode) { switch (hoverMode) { case MM_HOVER_RUBBERBAND: return MouseSubmode.MM_DRAG_RUBBERBAND; case MM_HOVER_GRAB: return MouseSubmode.MM_DRAG_GRAB; case MM_HOVER_SELECTION: return MouseSubmode.MM_DRAG_SELECTION; case MM_HOVER_CALIPER: return MouseSubmode.MM_DRAG_CALIPER; } return hoverMode; // weird, should not happen } private void setMouseDragMode() { MouseSubmode newMode = convertHoverToDrag(getMouseSubmode()); setMouseSubmode(newMode); } // === other listener actions public void mouseWheelMoved(MouseWheelEvent e) { int notches = e.getWheelRotation(); if (e.getScrollType() == MouseWheelEvent.WHEEL_UNIT_SCROLL) { // e.getScrollAmount() // unit increments per notch // e.getUnitsToScroll() // unit increments // scrollPane.getVerticalScrollBar().getUnitIncrement(1) // Vertical unit increment pixels } else { // scroll type == MouseWheelEvent.WHEEL_BLOCK_SCROLL // scrollPane.getVerticalScrollBar().getBlockIncrement(1) // Vertical block increment pixels } if (MOUSE_WHEEL_ZOOMS) { // zoom X Double zoomFactor = notches * 1.5; final int ix = translateX(e); long mouseTime = coord_is_live(ix) ? timeAxisCalculator.getTimeAtCoord(ix) : zoom_time_center; long duration; if (zoomFactor < 0) { // zoom in Double dd = timeAxisCalculator.getTimeDuration() / (-zoomFactor); duration = dd.longValue(); } else { // zoom out Double dd = timeAxisCalculator.getTimeDuration() * (zoomFactor); duration = dd.longValue(); if (duration < 2) { duration = 2; // deal with rounding at maximum zoom } } zoomTimeToDuration(duration); // sets the duration recalc_time_focus(mouseTime); zoomTimeToDuration(duration); // pans to updated center } else { // vertical scrolling final int visiblePixels = dataAxisCalculator.getAvailPixels(); if (visiblePixels <= 0) { return; } final int pixelsPerNotch = 50; final double percentPerPixel = dataAxisCalculator.getVisiblePercent() / visiblePixels; Double panPercent = (notches * pixelsPerNotch) * percentPerPixel; panProcBy(panPercent); } } public void mouseDragged(MouseEvent e) { if (recent_mouse_button != e.BUTTON1) { return; } final MouseSubmode submode = getMouseSubmode(); switch (submode) { case MM_OVERLAY: break; case MM_DRAG_RUBBERBAND: processRubberband(e, false); break; case MM_DRAG_GRAB: if (x_is_live) { final int ix = translateX(e); int deltaX = ix - x_start_drag; long deltatime = timeAxisCalculator.getTimeDuration() * deltaX / timeAxisCalculator.getAvailPixels(); long start = x_start_drag_timeOffset - deltatime; panTimeTo(start); } if (y_is_live) { final int iy = translateY(e); int deltaY = iy - y_start_drag; double deltaPercent = dataAxisCalculator.getVisiblePercent() * deltaY / dataAxisCalculator.getAvailPixels(); double startYPercent = y_start_drag_percentOffset - deltaPercent; panProcTo(startYPercent); } break; case MM_DRAG_SELECTION: case MM_DRAG_CALIPER: if (x_is_live) { checkAutoScrollTimer(e); final int ix = translateX(e); long time = timeAxisCalculator.getTimeNearCoord(ix); timeCaliper.setActiveCaliperTime(time); caliperUtilNotify(timeCaliper); } else { int ii = 1; // weird, not supported yet } break; case MM_HOVER_RUBBERBAND: case MM_HOVER_GRAB: case MM_HOVER_SELECTION: case MM_HOVER_CALIPER: final int xDist = x_is_live ? Math.abs(x_start_drag - translateX(e)) : 0; final int yDist = y_is_live ? Math.abs(y_start_drag - translateY(e)) : 0; if (mousePressedTimer != null && (xDist < MOUSE_DRAG_MIN_PIXELS && yDist < MOUSE_DRAG_MIN_PIXELS)) { // for the initial period, don't pan/rubberband for small movements int foo = 1; // for breakpoint } else { // either timer expired or cursor moved significantly killMousePressedTimer(); setMouseDragMode(); } break; default: int xx = 1; // weird break; } } private void mouseDraggedEnd(MouseEvent e) { // called by mouseReleased(). Cleans up any state used by mouseDragged() switch (getMouseSubmode()) { case MM_DRAG_RUBBERBAND: processRubberband(e, true); break; default: // Java appears to provide same X/Y to mouseDragged() // and mouseReleased(), no need to do anything else here break; } } public void mouseMoved(MouseEvent e) { selectHoverState(e, false); } private void selectHoverState(final MouseEvent e, final boolean checkAltMode) { /* Set the cursor and mouse MM_HOVER_* state */ if (parentPanelType == MousePanelType.MP_MAIN_PANEL && overlayMouseHandler.inOverlay(e.getX(), e.getY())) { // for now, only support zoom overlay in main panel setMouseSubmode(MouseSubmode.MM_OVERLAY); overlayMouseHandler.activate(); return; } overlayMouseHandler.deactivate(); if (enable_time_caliper) { // check if over a caliper int idx = caliperUtilSelectNearX(translateX(e)); if (idx != -1) { // we're hovering over a caliper if (idx == 0) { // selected caliper arm is the anchor timeCaliper.swapAnchor(); // make the other the anchor } timeCaliper.setActiveIdx(1); setMouseSubmode(MouseSubmode.MM_HOVER_CALIPER); return; } } final MouseDragMode defaultDragAction; if (checkAltMode && e.isControlDown() && altDragAction != null) { // toggle to alternate mode defaultDragAction = altDragAction; } else { defaultDragAction = dragAction != null ? dragAction : mouse_drag_mode; } final MouseSubmode newMode; switch (defaultDragAction) { default: case MOUSE_GRABBING_MODE: newMode = MouseSubmode.MM_HOVER_GRAB; break; case MOUSE_SELECTION_MODE: newMode = MouseSubmode.MM_HOVER_SELECTION; break; case MOUSE_RUBBERBANDING_MODE: newMode = MouseSubmode.MM_HOVER_RUBBERBAND; break; } setMouseSubmode(newMode); } public void mouseClicked(MouseEvent e) { if (getMouseSubmode() == MouseSubmode.MM_OVERLAY) { return; } if (e.getButton() == e.BUTTON1) { if (e.getClickCount() == 2) { doubleClickZoomIn(e); } } } private void doubleClickZoomIn(final MouseEvent e) { zoomHistoryAdd(); if (x_is_live) { // reset zoom X center final int x = translateX(e); zoom_time_center = timeAxisCalculator.getTimeNearCoord(x); zoom_time_center_screen_percent = calcTimeScreenPercent(zoom_time_center); // zoom X long duration = timeAxisCalculator.getTimeDuration() / 4; zoomTimeToDuration(duration); } if (y_is_live) { final int y = translateY(e); // reset zoom Y center //YXXX mouse up already sets the center?? ypct_focus = dataAxisCalculator.getPercentNearCoord(y); ypct_focus_screen_percent = calcYpctScreenPercent(ypct_focus); // zoom Y if (parentPanelType == MousePanelType.MP_MAIN_PANEL || enable_vertical_zoom) { double vis_percent = dataAxisCalculator.getVisiblePercent(); int yproc = dataAxisCalculator.getRowNearPercent(ypct_focus); double three_rows_pct = dataAxisCalculator.getRowPercentOfTotal(yproc) * 3; if (vis_percent > three_rows_pct) { vis_percent /= 2; if (vis_percent < three_rows_pct) { vis_percent = three_rows_pct; } zoomYToPercent(vis_percent); } } else if (parentPanelType == MousePanelType.MP_Y_RULER) { int xx = 1; // no action implemented yet } } } public void mousePressed(final MouseEvent e) { selectHoverState(e, e.isControlDown()); if (getMouseSubmode() == MouseSubmode.MM_OVERLAY) { return; } int button = e.getButton(); recent_mouse_button = button; if (button != e.BUTTON1) { return; } /* This is where a mouse drag starts (though it's also called for * a click), there is not a call for MouseDragged with the initial * coordinates */ { mousePressedTimer = new Timer( MOUSE_PRESS_DRAG_DELAY, new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { setMouseDragMode(/*e*/ ); mousePressedTimer = null; } }); mousePressedTimer.setRepeats(false); mousePressedTimer.start(); } x_start_drag = translateX(e); y_start_drag = translateY(e); x_start_drag_timeOffset = timeAxisCalculator.getTimeStart(); y_start_drag_percentOffset = dataAxisCalculator.getVisibleStart(); history_start_drag = zoomHistoryCreateEvent(); if (getMouseSubmode() == MouseSubmode.MM_HOVER_SELECTION && !e.isShiftDown()) { // always resets the selection, give feedback right away long time = timeAxisCalculator.getTimeNearCoord(x_start_drag); timeCaliper.setActiveIdx(1); timeCaliper.setTime(0, time); timeCaliper.setTime(1, time); caliperUtilNotify(timeCaliper); } } private void processRubberband(final MouseEvent e, final boolean isDragEnd) { final int xx = translateX(e); final int yy = translateY(e); boolean yzoom = true, xzoom = true; if (!coord_is_live(xx)) { xzoom = false; } else if (!coord_is_live(yy) || !enable_vertical_zoom) { yzoom = false; } else if (!rubberbandIs2D) { // determine the primary direction of drag int dx = Math.abs(xx - x_start_drag); int dy = Math.abs(yy - y_start_drag); if (dx < dy) { xzoom = false; } else { yzoom = false; } } final int x1, y1, x2, y2; if (xzoom) { // x1 = timeAxisCalculator.getCoordAtTime(x_start_drag_time); x1 = x_start_drag; x2 = limitCoord(xx, timelineCanvas.getWidth()); } else { x1 = 0; x2 = timelineCanvas.getWidth() - 1; } if (yzoom) { y1 = y_start_drag; y2 = limitCoord(yy, timelineCanvas.getHeight()); } else { y1 = 0; y2 = timelineCanvas.getHeight() - 1; } if (!isDragEnd) { setRubberband(x1, y1, x2, y2); repaint(); } else { clearRubberband(); repaint(); { if (yzoom) { double p1 = dataAxisCalculator.getPercentNearCoord(y1); double p2 = dataAxisCalculator.getPercentNearCoord(y2); zoomYToRange(p1, p2, false); } if (xzoom) { long t1 = timeAxisCalculator.getTimeNearCoord(x1); long t2 = timeAxisCalculator.getTimeNearCoord(x2); zoomTimeToRange(t1, t2, false); } } } } /* The drag is complete */ public void mouseReleased(MouseEvent e) { if (getMouseSubmode() == MouseSubmode.MM_OVERLAY) { selectHoverState(e, false); autoScrollTimer.stop(); killMousePressedTimer(); return; } recent_mouse_button = -1; int button = e.getButton(); if (button != e.BUTTON1) { return; } autoScrollTimer.stop(); boolean preTimeout = killMousePressedTimer(); final int xx = x_start_drag; // may be MIN_VALUE final int yy = y_start_drag; // may be MIN_VALUE final boolean isClick = preTimeout; if (isClick) { // we consider this to be a click final TimelineCaliper selected; if (coord_is_live(yy) || getMouseSubmode() == MouseSubmode.MM_HOVER_GRAB) { // vRuler or main panel // check for event hit: selected = tldrawer.selectNearXY(xx, yy, e.isControlDown(), e.isShiftDown()); } else { // hRuler // don't modify event selection: selected = null; } // update calipers if (selected != null) { // x-axis click hit an event, update caliper to match: caliperUtilSetAndNotify(selected.getLowTime(), selected.getHighTime(), e.isShiftDown()); } else { // x-axis click did not update event selection if (coord_is_live(xx)) { // hRuler or main panel, put caliper at click location: long time = timeAxisCalculator.getTimeNearCoord(xx); caliperUtilSetAndNotify(time, time, e.isShiftDown()); } } } else { // end of drag action mouseDraggedEnd(e); } if (coord_is_live(yy)) { // y-axis click, update zoom center double clickYPercent = dataAxisCalculator.getPercentNearCoord(yy); recalc_ypct_focus(clickYPercent, !isClick); } ZoomHistoryEvent updated = zoomHistoryCreateEvent(); if (!updated.equals(history_start_drag)) { zoomHistoryAdd(history_start_drag); } history_start_drag = null; selectHoverState(e, false); } } private boolean isTimeVisible(long time) { final long start = timeAxisCalculator.getTimeStart(); final long end = timeAxisCalculator.getTimeEnd(); // if( end-start<=1 && time==start ){ // // special rule when only two ticks visible on screen // return true; // } // return start<time && time<end; return start <= time && time <= end; } private boolean isYpctVisible(double ypct) { final double start = dataAxisCalculator.getVisibleStart(); final double end = dataAxisCalculator.getVisibleEnd(); return start < ypct && ypct < end; } private void recalc_time_focus(long mouseTime) { // This method updates zoom_time_center and zoom_time_center_screen_percent // There are many options for what zoom should use as the focal point... long new_zoom_center = -1; // final int maxSnapToCaliperPixels = 20; // // if a caliper line is near mouse, use it // if (new_zoom_center == -1) { // if (timeCaliper != null){ // long candidateTime = -1; // int bestDist = Integer.MAX_VALUE; // for (int ii = 0; ii < 2; ii++) { // long ctime = timeCaliper.getTime(ii); // if ( isVisible(ctime) ) { // // caliper is on screen // int caliperX = timeAxisCalculator.getCoordAtTime(ctime); // int dist = Math.abs(caliperX - mouseX); // if( maxSnapToCaliperPixels > dist && // bestDist> dist){ // bestDist = dist; // candidateTime = ctime; // } // } // } // if(candidateTime != -1){ // new_zoom_center = candidateTime; // } // } // } // // // // try active caliper // if (new_zoom_center == -1) { // if (timeCaliper != null) { // final long caliperTime = timeCaliper.getActiveCaliperTime(); // if ( caliperTime!=-1 && // isVisible(caliperTime) ) { // new_zoom_center = caliperTime; // } // } // } // // // if a single caliper line is visible, use it // if (new_zoom_center == -1) { // if (timeCaliper != null){ // int num_visible = 0; // long candidateTime = -1; // for (int ii = 0; ii < 2; ii++) { // long ctime = timeCaliper.getTime(ii); // if ( isVisible(ctime) ) { // candidateTime = ctime; // num_visible++; // } // } // if (num_visible == 1) { // new_zoom_center = candidateTime; // } // } // } // if any caliper line is visible, pick the closest one if (new_zoom_center == -1) { if (timeCaliper != null) { long candidateTime = Long.MAX_VALUE; int num_visible = 0; long minDist = Long.MAX_VALUE; for (int ii = 0; ii < 2; ii++) { long ctime = timeCaliper.getTime(ii); if (isTimeVisible(ctime)) { num_visible++; long dist = Math.abs(mouseTime - ctime); if (minDist > dist) { minDist = dist; candidateTime = ctime; } } } // if( num_visible == 2){ { // consider midpoint as well long ctime = (timeCaliper.getTime(0) + timeCaliper.getTime(1)) / 2; long dist = Math.abs(mouseTime - ctime); if (isTimeVisible(ctime)) { if (minDist > dist) { minDist = dist; candidateTime = ctime; } } } if (candidateTime != Long.MAX_VALUE) { new_zoom_center = candidateTime; } } } // // try selection center // if (new_zoom_center == -1) { // long selectionTime = tldrawer.getSelectionTimeCenter(); // if (tldrawer.selectionActive() && isVisible(selectionTime)) { // // if selection is visible, use it as the selection center // new_zoom_center = selectionTime; // } // } // use the mouse location if (new_zoom_center == -1) { new_zoom_center = mouseTime; } boolean needPercentCalc = false; if (zoom_time_center != new_zoom_center) { zoom_time_center = new_zoom_center; needPercentCalc = true; } if (timeAxisCalculator.getTimeStart() == tldrawer.getAbsoluteTimeStart() || timeAxisCalculator.getTimeEnd() == tldrawer.getAbsoluteTimeEnd()) { // maxxed out at one edge needPercentCalc = true; } if (timeAxisCalculator.getTimeDuration() < 10) { // using percentage when there are only a few ns doesn't work. Pick middle zoom_time_center_screen_percent = 0.49; } else if (needPercentCalc) { double newPercent = calcTimeScreenPercent(zoom_time_center); zoom_time_center_screen_percent = newPercent; } } private boolean double_equals(double a, double b) { final double sigma = 0.0001; return Math.abs(a - b) < sigma; } private void recalc_ypct_focus(double clickYPercent, boolean isDrag) { // try selection center double new_zoom_center = -1; final double visEnd = dataAxisCalculator.getVisibleEnd(); final double visStart = dataAxisCalculator.getVisibleStart(); final double midScreen = (visEnd + visStart) / 2; if (isDrag) { double sel = tldrawer.getSelectionYCenter(); if (tldrawer.selectionActive() && isYpctVisible(sel)) { // if selection is visible, use it as the selection center new_zoom_center = sel; } else { new_zoom_center = midScreen; } } // use the mouse location if (new_zoom_center < 0) { if (isYpctVisible(clickYPercent)) { new_zoom_center = clickYPercent; } else { new_zoom_center = midScreen; } } boolean needPercentCalc = false; if (!double_equals(ypct_focus, new_zoom_center)) { ypct_focus = new_zoom_center; needPercentCalc = true; } else if (double_equals(visStart, 0) || double_equals(visEnd, 1)) { // maxxed out at one edge needPercentCalc = true; } if (needPercentCalc) { double newPercent = calcYpctScreenPercent(ypct_focus); ypct_focus_screen_percent = newPercent; } } public TimelineCaliper getCaliperClone() { if (timeCaliper == null) { return null; } return timeCaliper.clone(); } public void zoomToCaliper() { if (timeCaliper == null || timeCaliper.isSingleEvent()) { return; } zoomHistoryAdd(); zoomTimeToRange(timeCaliper.getLowTime(), timeCaliper.getHighTime(), true); } private void caliperUtilNotify(TimelineCaliper caliper) { timeCaliper = caliper; recalc_time_focus(zoom_time_center); tldrawer.notifyCaliperChange(getCaliperClone()); updateLocalRuler(); if (hRulerDefaultMouseMode == TimelinePanel.MouseDragMode.MOUSE_SELECTION_MODE) { updateHRulerCalipers(); } } private void caliperUtilSetTimeAndNotify(long anchor, long caliper) { TimelineCaliper newCaliper = new TimelineCaliper(anchor, caliper); caliperUtilNotify(newCaliper); } private int caliperUtilSelectNearX(int ix) { // returns index of caliper or -1 if (timeCaliper == null) { return -1; } if (ix == Integer.MIN_VALUE) { return -1; } int closestDist = CALIPER_CLICK_PIXEL_TOLERANCE; TimelineCaliper closestCaliper = null; int closestTimeIdx = -1; { // originally designed to loop through multiple calipers TimelineCaliper caliper = timeCaliper; for (int timeIdx = 0; timeIdx < caliper.getSize(); timeIdx++) { long time = caliper.getTime(timeIdx); if (caliper.getHighTime() == time // is right side && !(caliper.isSingleEvent() && timeIdx == 0)) { // is not left side time += 1; // +1 because all events are shown fattened by 1 ns } int x = timeAxisCalculator.getCoordAtTime(time); final int xDist = Math.abs(x - ix); if (closestDist > xDist) { closestDist = xDist; closestCaliper = caliper; closestTimeIdx = timeIdx; } } } if (closestCaliper == null) { return -1; // nothing found within caliper_max_grab_distance } return closestTimeIdx; } private void caliperUtilSetAndNotify(long timeLow, long timeHigh, boolean shift) { final long anchorTime, caliper; if (timeCaliper != null && shift) { anchorTime = timeCaliper.getTime(0); if (timeLow >= anchorTime) { caliper = timeHigh; } else if (timeHigh <= anchorTime) { caliper = timeLow; } else { // new event straddles anchor, ambigous if (Math.abs(anchorTime - timeHigh) > Math.abs(anchorTime - timeLow)) { caliper = timeHigh; } else { caliper = timeLow; } } } else { anchorTime = timeLow; caliper = timeHigh; } caliperUtilSetTimeAndNotify(anchorTime, caliper); } // requires timelineCanvas private void initZoomOverlays(JComponent parentCanvas) { timeOverlay = new ZoomRulerOverlay( parentCanvas, 2, 2, ZoomRulerOverlay.HORIZONTAL_ORIENTATION, ZoomRulerOverlay.RULER_LD_DEFAULT, false, true, false, false); timeOverlay.setNumberOfLevels(getZoomTimeLevelMax()); timeOverlay.addZoomRulerListener( new ZoomRulerListener() { public void zoomChanged(ZoomRulerEvent event) { if (event.isUndo()) { undoZoom(); } else if (event.isRedo()) { redoZoom(); } else if (event.isLevelChange()) { int lev = event.getZoomLevel(); zoomTimeToLevel(lev); } else if (event.isLevelPlus()) { zoomTimeIn(); } else if (event.isLevelMinus()) { zoomTimeOut(); } else if (event.isReset()) { resetZoom(); } else if (event.isPan()) { if (event.getDirection() == ZoomRulerEvent.PAN_UP) panUp(); else if (event.getDirection() == ZoomRulerEvent.PAN_RIGHT) panRight(); else if (event.getDirection() == ZoomRulerEvent.PAN_DOWN) panDown(); else // PAN_LEFT panLeft(); } } }); if (enable_vertical_zoom) { processOverlay = new ZoomRulerOverlay( parentCanvas, 2, timeOverlay.getHeight() + 1, ZoomRulerOverlay.VERTICAL_ORIENTATION, ZoomRulerOverlay.RULER_LD_DEFAULT, false, false, false, false); processOverlay.setNumberOfLevels(getZoomProcessLevelMax()); processOverlay.addZoomRulerListener( new ZoomRulerListener() { public void zoomChanged(ZoomRulerEvent event) { if (event.isLevelChange()) { int lev = event.getZoomLevel(); zoomProcessToLevel(lev); } else if (event.isLevelPlus()) { zoomProcessIn(); } else if (event.isLevelMinus()) { zoomProcessOut(); } } }); } this.overlayMouseHandler = new OverlayMouseHandler() { private boolean active = false; public boolean inOverlay(int x, int y) { return timeOverlay.withinBounds(x, y) || (enable_vertical_zoom && processOverlay.withinBounds(x, y)); } public void activate() { if (active) { return; } active = true; timeOverlay.activateMouseHandling(); if (enable_vertical_zoom) { processOverlay.activateMouseHandling(); } } public void deactivate() { if (!active) { return; } active = false; timeOverlay.deactivateMouseHandling(); if (enable_vertical_zoom) { processOverlay.deactivateMouseHandling(); } } public Cursor getCursor() { return overlaycursor; } }; } // --- X & Y update private void updateX(boolean force) { updateXCalc(); if (force || timeAxisCalculator.getTimeStart() != visible_time_start || timeAxisCalculator.getTimeEnd() != visible_time_end) { updateXWidgetsRanges(); repaint(); return; } return; } private void updateY(boolean force) { updateYCalc(); if (force || dataAxisCalculator.getVisibleStart() != visible_ypct_start || dataAxisCalculator.getVisibleEnd() != visible_ypct_end) { updateYWidgetsRanges(); repaint(); return; } return; } // Update X widgets. X-axis TimelineOptions must already be set. // Should not modify TimelineOptions private void updateXWidgetsRanges() { long start_ts = timeAxisCalculator.getTimeStart(); long duration = timeAxisCalculator.getTimeDuration(); updateXRulers(); // horizontal scroll bar if (!hscroll_adjusting) { set_hscroll = true; horScroll.setValues( start_ts, duration, tldrawer.getAbsoluteTimeStart(), tldrawer.getAbsoluteTimeEnd() + 1); set_hscroll = false; } int zlvl = getZoomTimeLevel(); if (timeOverlay != null) { timeOverlay.setZoomLevel(zlvl); } } private void updateXRulers() { long start_ts = timeAxisCalculator.getTimeStart(); long end_ts = timeAxisCalculator.getTimeEnd(); globalRuler.setRange(start_ts, end_ts); updateLocalRuler(); } private void updateLocalRuler() { long start_ts = timeAxisCalculator.getTimeStart(); long duration = timeAxisCalculator.getTimeDuration(); final long centerTime; TimelineCaliper caliper = timeCaliper; if (caliper != null) { centerTime = caliper.getLowTime(); } else if (tldrawer.selectionActive()) { centerTime = tldrawer.getSelectionTimeStart(); } else { centerTime = zoom_time_center; } long relStart = start_ts - centerTime; long relEnd = relStart + duration - 1; localRuler.setRange(relStart, relEnd); } private void updateHRulerCalipers() { List<Long> valueList = new ArrayList(); List<RangeRuler.TabStopTypes> typeList = new ArrayList(); TimelineCaliper caliper = timeCaliper; if (caliper != null) { valueList.add(caliper.getLowTime()); valueList.add(caliper.getHighTime()); typeList.add(RangeRuler.TabStopTypes.TABSTOP_LEFT); typeList.add(RangeRuler.TabStopTypes.TABSTOP_RIGHT); } globalRuler.setTabStops(valueList, typeList, timeAxisCalculator); localRuler.setTabStops(valueList, typeList, timeAxisCalculator); } // Update Y widgets. Y-axis TimelineOptions must already be set. // Should not modify TimelineOptions private void updateYWidgetsRanges() { // process ruler int start_p = dataAxisCalculator.getRowStart(); int end_p = dataAxisCalculator.getRowEnd(); verticalRuler.setRange(start_p, end_p); // process scrollbar. Scrollbar range is based ranks. if (!yscroll_adjusting) { set_vscroll = true; int scroll_lo; int scroll_hi; int scroll_abs_start; int scroll_abs_end; if (enable_vertical_row_snap) { scroll_lo = start_p; scroll_hi = end_p; scroll_abs_start = 0; scroll_abs_end = tldrawer.getAbsoluteRowEnd(); } else { double start_pct = dataAxisCalculator.getVisibleStart(); double end_pct = dataAxisCalculator.getVisibleEnd(); scroll_lo = (int) (start_pct * VERSCROLL_TO_PERCENT); scroll_hi = (int) (end_pct * VERSCROLL_TO_PERCENT); scroll_abs_start = 0; scroll_abs_end = VERSCROLL_TO_PERCENT; } int scroll_visible = scroll_hi - scroll_lo + 1; verScroll.setValues(scroll_lo, scroll_visible, scroll_abs_start, scroll_abs_end + 1); int scrollBlockStep = scroll_visible / 2; if (scrollBlockStep <= 0) scrollBlockStep = 1; verScroll.setBlockIncrement(scrollBlockStep); int scrollUnitStep = scrollBlockStep / SMALL_PAN_STEP_FRACTION; if (scrollUnitStep <= 0) scrollUnitStep = 1; verScroll.setUnitIncrement(scrollUnitStep); set_vscroll = false; } if (enable_vertical_zoom && processOverlay != null) { int plvl = getZoomProcessLevel(); processOverlay.setZoomLevel(plvl); } } // --- "state" selection via cursor // --- pan commands // internal private void panTimeTo(long start) { long duration = timeAxisCalculator.getTimeDuration(); zoomTimeToRange(start, start + duration - 1, true); } public void panProcTo(double start) { // YXXX public, hack for TL2 remap center double proc_cnt = dataAxisCalculator.getVisiblePercent(); zoomYToRange(start, start + proc_cnt, true); } private void panTimeBy(long step) { panTimeTo(timeAxisCalculator.getTimeStart() + step); } private void panProcBy(double step) { zoomHistoryAdd(); panProcTo(dataAxisCalculator.getVisibleStart() + step); } // external public void pageUp() { zoomHistoryAdd(); panProcBy(-dataAxisCalculator.getVisiblePercent()); } public void pageDown() { zoomHistoryAdd(); panProcBy(dataAxisCalculator.getVisiblePercent()); } public void panUp() { zoomHistoryAdd(); panProcBy(-dataAxisCalculator.getVisiblePercent() / LARGE_PAN_STEP_FRACTION); } public void panDown() { zoomHistoryAdd(); panProcBy(dataAxisCalculator.getVisiblePercent() / LARGE_PAN_STEP_FRACTION); } public void stepUp() { zoomHistoryAdd(); panProcBy(-dataAxisCalculator.getVisiblePercent() / SMALL_PAN_STEP_FRACTION); } public void stepDown() { zoomHistoryAdd(); panProcBy(dataAxisCalculator.getVisiblePercent() / SMALL_PAN_STEP_FRACTION); } public void pageLeft() { zoomHistoryAdd(); panTimeBy(-timeAxisCalculator.getTimeDuration()); } public void pageRight() { zoomHistoryAdd(); panTimeBy(timeAxisCalculator.getTimeDuration()); } public void panLeft() { zoomHistoryAdd(); panTimeBy(-(timeAxisCalculator.getTimeDuration() / LARGE_PAN_STEP_FRACTION + 1)); } public void panRight() { zoomHistoryAdd(); panTimeBy((timeAxisCalculator.getTimeDuration() / LARGE_PAN_STEP_FRACTION + 1)); } public void stepLeft() { zoomHistoryAdd(); panTimeBy(-(timeAxisCalculator.getTimeDuration() / SMALL_PAN_STEP_FRACTION + 1)); } public void stepRight() { zoomHistoryAdd(); panTimeBy((timeAxisCalculator.getTimeDuration() / SMALL_PAN_STEP_FRACTION + 1)); } private int findTimeMarkerIndex = 0; public void findTimeMarker() { if (timeCaliper == null) { return; } zoomHistoryAdd(); long newTime = timeCaliper.getTime(findTimeMarkerIndex); findTimeMarkerIndex = (findTimeMarkerIndex + 1) & 1; // zoom_time_center = newTime; // zoom_time_center_screen_percent = 0.5; // zoomTimeToDuration(timeAxisCalculator.getTimeDuration()); panLeftRightToMakeVisible(newTime, newTime); } public void setTimeMarker() { long anchor = (timeAxisCalculator.getTimeStart() + timeAxisCalculator.getTimeEnd()) / 2; caliperUtilSetTimeAndNotify(anchor, anchor); } private long limitTime(long inTime) { if (inTime < tldrawer.getAbsoluteTimeStart()) { inTime = tldrawer.getAbsoluteTimeStart(); } else if (inTime > tldrawer.getAbsoluteTimeEnd()) { inTime = tldrawer.getAbsoluteTimeEnd(); } return inTime; } private void moveTimeMarker(long delta) { if (timeCaliper == null) { return; } long newTime = limitTime(timeCaliper.getTime(1) + delta); caliperUtilSetTimeAndNotify(newTime, newTime); panLeftRightToMakeVisible(newTime, newTime); } private void moveTimeSelectionMarker(long delta) { if (timeCaliper == null) { return; } long tmp; do { tmp = timeCaliper.getTime(1); if (isTimeVisible(tmp) || // is maxxed out (tmp == tldrawer.getAbsoluteTimeStart() && tmp == timeAxisCalculator.getTimeStart()) || (tmp == tldrawer.getAbsoluteTimeEnd() && tmp == timeAxisCalculator.getTimeEnd())) { break; } tmp = timeCaliper.getTime(0); if (isTimeVisible(tmp)) { timeCaliper.swapAnchor(); // make the other the anchor break; } tmp = timeCaliper.getTime(1); } while (false); long anchor = timeCaliper.getTime(0); long newTime = limitTime(tmp + delta); caliperUtilSetTimeAndNotify(anchor, newTime); panLeftRightToMakeVisible(newTime, newTime); } public void moveTimeMarkerLeft() { long step = timeAxisCalculator.getTimeDuration() / SMALL_PAN_STEP_FRACTION + 1; moveTimeMarker(-step); } public void moveTimeMarkerRight() { long step = timeAxisCalculator.getTimeDuration() / SMALL_PAN_STEP_FRACTION + 1; moveTimeMarker(+step); } public void moveTimeRangeToLeft() { long step = timeAxisCalculator.getTimeDuration() / SMALL_PAN_STEP_FRACTION + 1; moveTimeSelectionMarker(-step); } public void moveTimeRangeToRight() { long step = timeAxisCalculator.getTimeDuration() / SMALL_PAN_STEP_FRACTION + 1; moveTimeSelectionMarker(+step); } // --- image update utilites /* Bar heights are calculated on image initialization, process zoom, and * component resizes */ private void updateYCalc() { int canvasHeight = timelineCanvas.getHeight(); if (dataAxisCalculator.getCanvasPixels() != canvasHeight) { // must update setCanvasPixels() before calling doCompute() dataAxisCalculator.setCanvasPixels(canvasHeight); if (zoom_ypct_at_max) { // attempt to resize to full height dataAxisCalculator.setVisibleRange(0.0, 1.0); } } int avail = dataAxisCalculator.getAvailPixels(); int min_pixels = dataAxisCalculator.getMinPixelsForAllRows(); double desired_pct = dataAxisCalculator.getVisiblePercent(); int desired_min = (int) (min_pixels * desired_pct); boolean percentAdjustNeeded = false; if (!enable_vertical_zoom) { // vertical size is set externally percentAdjustNeeded = true; } else { // has local control of vertical zoom if (avail < desired_min) { // not enough canvas real estate for all procs double percentAvail = (double) avail / min_pixels; if (enable_vertical_row_snap) { int visibleProcs = (int) (tldrawer.getAbsoluteRowCount() * (percentAvail + PERCENT_TOLERANCE)); if (visibleProcs < 1) { visibleProcs = 1; } int absStartProc = 0; int absEndProc = tldrawer.getAbsoluteRowEnd(); int zoom_proc_center = dataAxisCalculator.getRowNearPercent(ypct_focus); int newStartProc = zoom_proc_center - visibleProcs / 2; if (newStartProc < absStartProc) { newStartProc = absStartProc; } int newEndProc = newStartProc + (visibleProcs - 1); if (newEndProc > absEndProc) { newEndProc = absEndProc; newStartProc = newEndProc - (visibleProcs - 1); } dataAxisCalculator.setRowRange(newStartProc, newEndProc); dataAxisCalculator.edt_revalidate(); return; } else { percentAdjustNeeded = true; } } } if (percentAdjustNeeded && min_pixels > 0) { double percentAvail = (double) avail / min_pixels; double newStartPct = ypct_focus - ypct_focus_screen_percent * percentAvail; if (newStartPct < 0.0) { newStartPct = 0.0; } double newEndPct = newStartPct + percentAvail; if (newEndPct > 1.0) { newEndPct = 1.0; newStartPct = newEndPct - percentAvail; } dataAxisCalculator.setVisibleRange(newStartPct, newEndPct); } dataAxisCalculator.edt_revalidate(); } private void updateXCalc() { int canvasWidth = timelineCanvas.getWidth(); timeAxisCalculator.setCanvasPixels(canvasWidth + 1); // +1: scrollbar acts like border timeAxisCalculator.edt_revalidate(); // set alignment } // rubberband private int rb_x1, rb_x2, rb_y1, rb_y2; private boolean rb_enable = false; private void setRubberband(int x1, int y1, int x2, int y2) { int tmp; if (x2 < x1) { tmp = x1; x1 = x2; x2 = tmp; } if (y2 < y1) { tmp = y1; y1 = y2; y2 = tmp; } rb_x1 = x1; rb_x2 = x2; rb_y1 = y1; rb_y2 = y2; rb_enable = true; } private void clearRubberband() { rb_enable = false; } private void drawRubberband(final Graphics g) { if (!rb_enable) { return; } g.setXORMode(Color.YELLOW); int w = rb_x2 - rb_x1; int h = rb_y2 - rb_y1; for (int ii = 0; ii < RUBBERBAND_WIDTH; ii++) { g.drawRect(rb_x1 + ii, rb_y1 + ii, w - 2 * ii, h - 2 * ii); } } /* This is the component where the timeline process bars and message lines * are rendered */ private class TimelineCanvas extends javax.swing.JComponent implements Accessible { private boolean firstPaint = true; public TimelineCanvas() { super(); initialize(); } private void initialize() { this.addComponentListener( new ComponentListener() { public void componentResized(ComponentEvent componentEvent) { if (dataAxisCalculator.getCanvasPixels() != timelineCanvas.getHeight()) { updateY(true); // visible proc range may change verticalRuler.repaint(); } if (timeAxisCalculator.getCanvasPixels() != timelineCanvas.getWidth() + 1) { // +1: see setCanvasPixels() updateX(false); globalRuler.repaint(); localRuler.repaint(); } repaint(); // may be redundant, tbd } public void componentMoved(ComponentEvent componentEvent) {} public void componentShown(ComponentEvent componentEvent) {} public void componentHidden(ComponentEvent componentEvent) {} }); } @Override public void setCursor(Cursor cursor) { if (super.getCursor() != cursor) { super.setCursor(cursor); // YXXX see if this is fast enough... } } // Notify timeline PaintListeners @Override public void paintComponent(Graphics g) { myPaint(g); if (timeOverlay != null) { timeOverlay.paintRuler(g); } if (enable_vertical_zoom && processOverlay != null) { processOverlay.paintRuler(g); } drawRubberband(g); } /* Get new data from the image provide and request that the state and * message drawers redraw the timeline image */ private void myPaint(Graphics g) { // javax.swing.JOptionPane.showMessageDialog(null, "Updating"); boolean notify = false; if (dataAxisCalculator.getCanvasPixels() != this.getHeight()) { return; // let componentResized handle it } if (timeAxisCalculator.getCanvasPixels() != this.getWidth() + 1) { // +1: see setCanvasPixels() return; // let componentResized handle it } if (dataAxisCalculator.isInitialized() && timeAxisCalculator.isInitialized()) { if (tldrawer.edt_fetchData(forceDataReload)) { // fetch started // notify = true; forceDataReload = false; } else { int ii = 0; // for breakpoint } } else { int ii = 0; // for breakpoint } if (visible_ypct_start != dataAxisCalculator.getVisibleStart() || visible_ypct_end != dataAxisCalculator.getVisibleEnd() || visible_time_start != timeAxisCalculator.getTimeStart() || visible_time_end != timeAxisCalculator.getTimeEnd()) { // data range change visible_ypct_start = dataAxisCalculator.getVisibleStart(); visible_ypct_end = dataAxisCalculator.getVisibleEnd(); visible_time_start = timeAxisCalculator.getTimeStart(); visible_time_end = timeAxisCalculator.getTimeEnd(); if (dataAxisCalculator.getAbsRowCount() != 0) { // YXXX should probably look at Time data too? // legit new data notify = true; } } if (firstPaint) { // YXXX some of the following may not be kosher from paintComponent()? // adjust rulers for margins int vRulerWidth = verticalRuler.getWidth(); // not known until 1st update int xMargin = timeAxisCalculator.getMargin(); // currently, static int xPaddingLo = xMargin + vRulerWidth; int vScrollWidth = verScroll.getWidth(); int xPaddingHi = xMargin + vScrollWidth; globalRuler.setPadding(xPaddingLo, xPaddingHi); localRuler.setPadding(xPaddingLo, xPaddingHi); globalRuler.lockRulerThickness(g, true); localRuler.lockRulerThickness(g, true); verticalRuler.lockRulerThickness(g, true); // repaint rulers. Why? Initially, rulers may know their range, // but not geometry, so they wouldn't have painted at the // resize event. globalRuler.repaint(); verticalRuler.repaint(); southWestSpacer.setPreferredSize(new Dimension(vRulerWidth, 0)); southEastSpacer.setPreferredSize(new Dimension(vScrollWidth, 0)); southPanel.revalidate(); firstPaint = false; } if (tldrawer.drawData(g)) { // notify = true; } if (notify) { // YXXX some of the listeners may not be kosher from paintComponent()? notifyListeners(); } } /////////////////////////// // Accessibility support // /////////////////////////// /** * Gets the AccessibleContext associated with this JPanel. For MPITimelineCanvas, the * AccessibleContext takes the form of an AccessibleMPITimelineCanvas. A new AccessibleJPanel * instance is created if necessary. * * @return an AccessibleJPanel that serves as the AccessibleContext of this JPanel */ public AccessibleContext getAccessibleContext() { if (accessibleContext == null) { accessibleContext = new AccessibleMPITimelineCanvas(); } return accessibleContext; } /** * This class implements accessibility support for the <code>MPITimelineCanvas</code> class. It * provides an implementation of the Java Accessibility API appropriate to panel user-interface * elements. */ protected class AccessibleMPITimelineCanvas extends AccessibleJComponent { /** * Get the role of this object. * * @return an instance of AccessibleRole describing the role of the object */ public AccessibleRole getAccessibleRole() { return AccessibleRole.PANEL; } } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/CoordCalcDataImpl.java�����������������������������0000644�0001750�0001750�00000033756�14517772113�023241� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; import java.util.ArrayList; /** * Coordinate calculator for timeline rows * * <p>Coordinate systems used: * * <p>"ucoord": coordinate system to represent unscaled user rows. Zero corresponds to upper edge of * first row. "vcoord": coordinate system to represent user rows scaled to fit screen. Zero * corresponds to upper edge of first row. "canvas": coordinate system of canvas. Scrollbar and * margins are added to vcoord; */ public class CoordCalcDataImpl extends CoordCalcDataMaster { // ------- user settings ------ // --- total range of rows to be displayed private int abs_row_end = 0; // absolute end row (at full zoom out) private int abs_row_count = 0; // number of rows (at full zoom out) // --- canvas size private int canvasPixels = 0; // --- unscaled row layout (ucoord) private ArrayList<Integer> ucoord_row_tops; // row upper edge (unscaled) private ArrayList<Integer> ucoord_row_bottoms; // row lower edge (unscaled) // --- zoom range (value [0.0-1.0] corresponds to [0-ucoord_total_pixels]) private double visible_start_pct = 0.0; // visible start (% of total) private double visible_end_pct = 0.0; // visible end (% of total) private int visible_start_row; // visible start (row) private int visible_end_row; // visible start (row) // ------- computed values ------ // --- state private boolean is_initialized = false; // edt_revalidate() has been called at least once private boolean needs_compute = false; private boolean needs_vcoord_table; private int vcoord_visible_top; // vcoord offset to start of visible data private double vcoord2ucoordRatio = 1.0; // YXXX look for div/zero private boolean use_rows_for_range; // rows or percent to set range? // --- unscaled row layout (ucoord) private int ucoord_total_pixels = 1; // total size of all rows (unscaled) // --- scaled row layout (vcoord) private ArrayList<Integer> vcoord_row_tops; // row upper edge (scaled) private ArrayList<Integer> vcoord_row_bottoms; // row lower edge (scaled) private int vcoord_total_pixels = 1; // total size of all rows (scaled) // preferences private boolean expandRowsToFill = true; // expand (only at full zoom out) private final int canvasY_header = 0; // optional vertical offset private final int canvasY_margin; // space between TL and ruler public static final double HUNDRED_PERCENT_ROUNDUP = 0.999; public CoordCalcDataImpl(int canvas_margin) { canvasY_margin = canvas_margin; } // --- canvas geometry /** Sets current canvas height */ @Override public void setCanvasPixels(int visiblePixels) { if (canvasPixels != visiblePixels) { canvasPixels = visiblePixels; needs_compute = true; } } /** Gets current canvas height */ public int getCanvasPixels() { return canvasPixels; } // --- row geometry settings @Override public void edt_revalidate() { // setAbsRowMinHeight*() must be called first if (needs_compute) { calculateRowSizes(); needs_compute = false; } is_initialized = true; } /** sets variables used to calculate row height */ private void calculateRowSizes() { if (ucoord_row_tops == null) { setVcoordHeights(1.0); vcoord_visible_top = 0; needs_compute = false; return; } // calculate new scale double vdelta = getAvailPixels(); double udelta; if (use_rows_for_range) { int uy_top = ucoord_row_tops.get(visible_start_row); int uy_bottom = ucoord_row_bottoms.get(visible_end_row); udelta = uy_bottom - uy_top; } else { udelta = ucoord_total_pixels * getVisiblePercent(); } double ideal_scale = vdelta / udelta; // adjust scale if required double actual_scale; if (!expandRowsToFill && ideal_scale > 1.0) { actual_scale = 1.0; } else { if (ideal_scale < HUNDRED_PERCENT_ROUNDUP) { boolean toBigToFit = true; } actual_scale = ideal_scale; } // update the vcoord tables setVcoordHeights(actual_scale); // update vcoord_visible_top { int vy_top; if (use_rows_for_range) { vy_top = vcoord_row_tops.get(visible_start_row); } else { vy_top = (int) (vcoord_total_pixels * visible_start_pct); } vcoord_visible_top = vy_top; } needs_compute = false; } /** margins allow states along edges to be visible and accessible */ public int getMargin() { return canvasY_margin; } public boolean isInitialized() { return is_initialized; } public boolean isValid() { return !needs_compute; } // --- row range private void setAbsRowCount(int rowCount) { int end = rowCount > 0 ? rowCount - 1 : 0; if (abs_row_count != rowCount || abs_row_end != end) { abs_row_count = rowCount; abs_row_end = end; needs_vcoord_table = true; needs_compute = true; } } public int getAbsRowEnd() { return abs_row_end; } public int getAbsRowCount() { return abs_row_count; } public void setAbsRowMinHeights(ArrayList<Integer> mins) { // YXXX just set mins setAbsRowCount(mins.size()); int absRowCount = getAbsRowCount(); int total_used = 0; if (absRowCount == 0) { ucoord_row_tops = ucoord_row_bottoms = null; } else { ucoord_row_tops = new ArrayList(absRowCount); ucoord_row_bottoms = new ArrayList(absRowCount); for (int ii = 0; ii < absRowCount; ii++) { ucoord_row_tops.add(total_used); int rowHeight = mins.get(ii); total_used += rowHeight; ucoord_row_bottoms.add(total_used); } } setUcoordHeights(total_used); } public void setAbsRowMinHeights(int rowCount, int minPixels) { setAbsRowCount(rowCount); int absRowCount = getAbsRowCount(); int total_used = 0; if (absRowCount == 0) { ucoord_row_tops = ucoord_row_bottoms = null; } else { ucoord_row_tops = new ArrayList(absRowCount); ucoord_row_bottoms = new ArrayList(absRowCount); for (int ii = 0; ii < absRowCount; ii++) { ucoord_row_tops.add(total_used); total_used += minPixels; ucoord_row_bottoms.add(total_used); } } setUcoordHeights(total_used); } public void setExpandToFill(boolean expands) { expandRowsToFill = expands; } public void setRowRange(int startrow, int endrow) { if (use_rows_for_range != true || visible_start_row != startrow || visible_end_row != endrow) { use_rows_for_range = true; visible_start_row = startrow; visible_end_row = endrow; if (ucoord_row_tops == null) { visible_start_pct = 0; visible_end_pct = 0; } else { visible_start_pct = (double) ucoord_row_tops.get(startrow) / ucoord_total_pixels; visible_end_pct = (double) ucoord_row_bottoms.get(endrow) / ucoord_total_pixels; } needs_compute = true; } } public int getRowStart() { return visible_start_row; } public int getRowEnd() { return visible_end_row; } public int getRowCount() { return visible_end_row - visible_start_row + 1; } public void setVisibleRange(double start, double end) { if (use_rows_for_range != false || visible_start_pct != start || visible_end_pct != end) { use_rows_for_range = false; visible_start_pct = start; visible_end_pct = end; visible_start_row = getRowNearPercent(visible_start_pct); visible_end_row = getRowNearPercent(visible_end_pct); needs_compute = true; } } public double getVisibleStart() { return visible_start_pct; } public double getVisibleEnd() { return visible_end_pct; } public double getVisiblePercent() { return visible_end_pct - visible_start_pct; } /* --- initialize coordinate tables --- */ private void setUcoordHeights(int total_used) { // set unscaled row layout ucoord_total_pixels = total_used; if (ucoord_total_pixels < 1) { ucoord_total_pixels = 1; } needs_vcoord_table = true; visible_start_row = getRowNearPercent(visible_start_pct); visible_end_row = getRowNearPercent(visible_end_pct); needs_compute = true; } private void setVcoordHeights(double new_vcoord2ucoordRatio) { if (!needs_vcoord_table && vcoord2ucoordRatio == new_vcoord2ucoordRatio) { return; } vcoord2ucoordRatio = new_vcoord2ucoordRatio; if (ucoord_row_tops == null) { vcoord_row_tops = vcoord_row_bottoms = null; needs_vcoord_table = false; vcoord_total_pixels = 1; return; } // populate vcoord_row_* ArrayLists int absRowCount = getAbsRowCount(); vcoord_row_tops = new ArrayList(absRowCount); vcoord_row_bottoms = new ArrayList(absRowCount); int ii; int vcoord; // loop (below) ensures that top of each row is the same value // as bottom of previous row. This prevents gaps caused by rounding. int ucoord = 0; vcoord_row_tops.add(0); for (ii = 1; ii < absRowCount; ii++) { ucoord = ucoord_row_tops.get(ii); vcoord = ucoord2vcoord(ucoord, new_vcoord2ucoordRatio); vcoord_row_bottoms.add(vcoord); vcoord_row_tops.add(vcoord); } ucoord = ucoord_row_bottoms.get(absRowCount - 1); vcoord = ucoord2vcoord(ucoord, new_vcoord2ucoordRatio); vcoord_row_bottoms.add(vcoord); vcoord_total_pixels = vcoord; if (vcoord_total_pixels < 1) { vcoord_total_pixels = 1; } needs_vcoord_table = false; } private int ucoord2vcoord(int ucoord, double ratio) { double vcoord = ucoord * ratio; if (vcoord > Integer.MAX_VALUE) { vcoord = Integer.MAX_VALUE; /* overflow! */ } return (int) vcoord; } // ---------- computed values ---------- private int vcoord2canvas(int vy) { int canvasY = vy - vcoord_visible_top + (canvasY_margin + canvasY_header); return canvasY; } private int canvas2vcoord(int canvasY) { int vy = canvasY + vcoord_visible_top - (canvasY_margin + canvasY_header); return vy; } public int getAvailPixels() { int availHeight = canvasPixels - canvasY_margin * 2; if (availHeight < 1) { availHeight = 1; } return availHeight; } public int getTotalPixels() { // YXXX unused return vcoord_total_pixels; } public int getMinPixelsForAllRows() { return ucoord_total_pixels; } public int getMinPixelsRequired(int row_lo, int row_hi) { // YXXX unused if (vcoord_row_tops == null) { return 0; } int top = ucoord_row_tops.get(row_lo); int bottom = ucoord_row_tops.get(row_hi); return bottom - top; } /** Get top coordinate for the ith row */ public int getLowCoordForRow(int yrow) { if (vcoord_row_tops == null) { return 0; } int vy = vcoord_row_tops.get(yrow); int y = vcoord2canvas(vy); return y; } /** Get center coordinate for the ith row */ public int getCenterCoordForRow(int yrow) { if (vcoord_row_tops == null) { return 0; } int vyt = vcoord_row_tops.get(yrow); int vyb = vcoord_row_bottoms.get(yrow); int vy = (vyt + vyb) / 2; int y = vcoord2canvas(vy); return y; } /** Get bottom coordinate for the ith row */ public int getHighCoordForRow(int yrow) { if (vcoord_row_tops == null) { return 0; } int vy = vcoord_row_bottoms.get(yrow); int y = vcoord2canvas(vy); return y; } // will return -1 if yy is between states public int getRowAtCoord(int canvasY) { // YXXX this might no longer be needed int idx = internalCoord2Row(canvasY); if (idx >= getAbsRowCount()) { return -1; } return idx; } // always returns a valid row num public int getRowNearCoord(int canvasY) { int idx = internalCoord2Row(canvasY); int nrows = getAbsRowCount(); if (idx < 0) { return 0; } else if (idx >= nrows) { return nrows - 1; } return idx; } // always returns a valid row num private int internalCoord2Row(int canvasY) { if (vcoord_row_tops == null) { return -1; } int vy = canvas2vcoord(canvasY); if (vy < 0) { return -1; } int nrows = getAbsRowCount(); for (int ii = 0; ii < nrows; ii++) { if (vy >= vcoord_row_tops.get(ii) && vy < vcoord_row_bottoms.get(ii)) { return ii; } } return nrows; } public double getPercentNearCoord(int canvasY) { if (vcoord_row_tops == null) { return 0; } int vy = canvas2vcoord(canvasY); double percent = (double) vy / vcoord_total_pixels; return percent; } /* --- important: the following use only ucoord values --- */ public double getCenterPercentForRow(int yrow) { if (ucoord_row_tops == null) { return 0; } int uy = (ucoord_row_tops.get(yrow) + ucoord_row_bottoms.get(yrow)) / 2; double percent = (double) uy / ucoord_total_pixels; return percent; } public double getRowPercentOfTotal(int yrow) { if (ucoord_row_tops == null) { return 0; } int uy = ucoord_row_bottoms.get(yrow) - ucoord_row_tops.get(yrow); double percent = (double) uy / ucoord_total_pixels; return percent; } public int getRowNearPercent(double percent) { if (ucoord_row_tops == null) { return 0; } int uy = (int) (ucoord_total_pixels * percent); if (uy <= 0) { return 0; } int nrows = getAbsRowCount(); for (int ii = 0; ii < nrows - 1; ii++) { if (uy >= ucoord_row_tops.get(ii) && uy < ucoord_row_bottoms.get(ii)) { return ii; } } return nrows - 1; } } ������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/TimelineCursor.java��������������������������������0000644�0001750�0001750�00000014161�14517772113�022725� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Image; import java.awt.Point; import java.awt.Toolkit; import java.awt.image.MemoryImageSource; import java.util.HashMap; import java.util.Map; /** * This class provides the cursors displayed in the timeline. * * @author Owner */ public class TimelineCursor extends Component { private final Map<Integer, Cursor> savedCursors; private final Image openHandImage; public static final int CLOSED_HAND_CURSOR = -1; public static final int OPEN_HAND_CURSOR = -2; /** Creates a new instance of HandCursor */ public TimelineCursor() { Image img; Cursor cursor; savedCursors = new HashMap(); img = createOpenHandImage(24, 24); openHandImage = img; img = createOpenHandImage(32, 32); cursor = Toolkit.getDefaultToolkit().createCustomCursor(img, new Point(5, 5), "openhand"); savedCursors.put(OPEN_HAND_CURSOR, cursor); img = createClosedHandImage(32, 32); cursor = Toolkit.getDefaultToolkit().createCustomCursor(img, new Point(5, 5), "closedhand"); savedCursors.put(CLOSED_HAND_CURSOR, cursor); } /** Get the open hand "Grabber" cursor */ public Image getOpenHandImage() { return openHandImage; } private Image createOpenHandImage(final int curWidth, final int curHeight) { int curCol; Image img; int x, y; int pix[] = new int[curWidth * curHeight]; for (y = 0; y <= curHeight; y++) { for (x = 0; x <= curWidth; x++) { pix[y + x] = 0; // all points transparent } } // black pixels curCol = Color.black.getRGB(); int n = 0; while (open_black[n] != 0) { pix[open_black[n++] + open_black[n++] * curWidth] = curCol; } // white pixels curCol = Color.white.getRGB(); n = 0; while (open_white[n] != 0) { pix[open_white[n++] + open_white[n++] * curWidth] = curCol; } // white pixel runs n = 0; y = 9; while (open_whiteruns[n] != 0) { for (x = open_whiteruns[n++]; x < open_whiteruns[n]; x++) { pix[x + y * curWidth] = curCol; } n++; y++; } img = createImage(new MemoryImageSource(curWidth, curHeight, pix, 0, curWidth)); return img; } // hand cursor data private final int closed_black[] = { 6, 5, 7, 5, 9, 5, 10, 5, 12, 5, 13, 5, 5, 6, 8, 6, 11, 6, 14, 6, 15, 6, 5, 7, 14, 7, 16, 7, 6, 8, 16, 8, 5, 9, 6, 9, 16, 9, 4, 10, 16, 10, 4, 11, 16, 11, 4, 12, 15, 12, 5, 13, 15, 13, 6, 14, 14, 14, 7, 15, 14, 15, 7, 16, 14, 16, 0 }; private final int closed_white[] = { 6, 4, 7, 4, 9, 4, 10, 4, 12, 4, 13, 4, 5, 5, 8, 5, 11, 5, 14, 5, 15, 5, 4, 6, 6, 6, 7, 6, 9, 6, 10, 6, 12, 6, 13, 6, 16, 6, 4, 7, 15, 7, 17, 7, 5, 8, 17, 8, 4, 9, 17, 9, 3, 10, 5, 10, 15, 10, 17, 10, 3, 11, 17, 11, 3, 12, 16, 12, 4, 13, 16, 13, 5, 14, 15, 14, 6, 15, 15, 15, 6, 16, 15, 16, 7, 17, 14, 17, 0 }; private final int closed_whiteruns[] = { 6, 13, 7, 15, 7, 15, 5, 15, 5, 15, 5, 14, 6, 14, 7, 13, 8, 13, 8, 13, 0 }; private final int open_black[] = { 10, 3, 11, 3, 6, 4, 7, 4, 9, 4, 12, 4, 13, 4, 14, 4, 5, 5, 8, 5, 9, 5, 12, 5, 15, 5, 5, 6, 8, 6, 9, 6, 12, 6, 15, 6, 17, 6, 6, 7, 9, 7, 12, 7, 15, 7, 16, 7, 18, 7, 6, 8, 9, 8, 12, 8, 15, 8, 18, 8, 4, 9, 5, 9, 7, 9, 15, 9, 18, 9, 3, 10, 6, 10, 7, 10, 18, 10, 3, 11, 7, 11, 17, 11, 4, 12, 17, 12, 5, 13, 17, 13, 5, 14, 16, 14, 6, 15, 16, 15, 7, 16, 15, 16, 8, 17, 15, 17, 8, 18, 15, 18, 0 }; private final int open_white[] = { 10, 2, 11, 2, 6, 3, 7, 3, 9, 3, 12, 3, 13, 3, 5, 4, 8, 4, 10, 4, 11, 4, 15, 4, 4, 5, 6, 5, 7, 5, 10, 5, 11, 5, 13, 5, 14, 5, 16, 5, 17, 5, 4, 6, 6, 6, 7, 6, 10, 6, 11, 6, 13, 6, 14, 6, 16, 6, 18, 6, 5, 7, 7, 7, 8, 7, 10, 7, 11, 7, 13, 7, 14, 7, 17, 7, 19, 7, 4, 8, 5, 8, 7, 8, 8, 8, 10, 8, 11, 8, 13, 8, 14, 8, 16, 8, 17, 7, 19, 8, 3, 9, 6, 9, 16, 9, 17, 9, 19, 9, 2, 10, 4, 10, 5, 10, 19, 10, 2, 11, 18, 11, 3, 12, 18, 12, 4, 13, 18, 13, 4, 14, 17, 14, 5, 15, 17, 15, 6, 16, 16, 16, 7, 17, 18, 17, 7, 18, 16, 18, 8, 19, 15, 19, 0 }; private final int open_whiteruns[] = { 9, 14, 8, 17, 4, 16, 5, 16, 6, 16, 6, 15, 7, 15, 8, 14, 9, 14, 9, 14, 0 }; private Image createClosedHandImage(final int curWidth, final int curHeight) { int curCol; Image img; int x, y; int pix[] = new int[curWidth * curHeight]; for (y = 0; y <= curHeight; y++) { for (x = 0; x <= curWidth; x++) { pix[y + x] = 0; // all points transparent } } // black pixels curCol = Color.black.getRGB(); int n = 0; while (closed_black[n] != 0) { pix[closed_black[n++] + closed_black[n++] * curWidth] = curCol; } // white pixels curCol = Color.white.getRGB(); n = 0; while (closed_white[n] != 0) { pix[closed_white[n++] + closed_white[n++] * curWidth] = curCol; } // white pixel runs n = 0; y = 7; while (closed_whiteruns[n] != 0) { for (x = closed_whiteruns[n++]; x < closed_whiteruns[n]; x++) { pix[x + y * curWidth] = curCol; } n++; y++; } img = createImage(new MemoryImageSource(curWidth, curHeight, pix, 0, curWidth)); return img; } public Cursor getCursor(int id) { Cursor cursor = savedCursors.get(id); if (cursor == null) { try { cursor = new Cursor(id); } catch (IllegalArgumentException e) { cursor = new Cursor(Cursor.DEFAULT_CURSOR); } savedCursors.put(id, cursor); } return cursor; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/TimelineCaliper.java�������������������������������0000644�0001750�0001750�00000004406�14517772113�023030� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; public class TimelineCaliper { private final long time[]; // length[2], one for each caliper. [0] is anchor. private int activeIdx; // which of two calipers is dynamically changing, or -1 for none public TimelineCaliper(long time0, long time1) { this.time = new long[2]; this.time[0] = time0; this.time[1] = time1; this.activeIdx = -1; } public TimelineCaliper clone() { TimelineCaliper clone = new TimelineCaliper(time[0], time[1]); clone.activeIdx = this.activeIdx; return clone; } public int getSize() { return time.length; } public long getTime(int idx) { return time[idx]; // throws if out of bounds } public void setTime(int idx, long newTime) { time[idx] = newTime; // throws if out of bounds } public boolean isSingleEvent() { return time[0] == time[1]; } public long getLowTime() { return (time[0] < time[1]) ? time[0] : time[1]; } public long getHighTime() { return (time[0] < time[1]) ? time[1] : time[0]; } public int getActiveIdx() { return activeIdx; } public long getActiveCaliperTime() { if (activeIdx == -1) { return -1; } return time[activeIdx]; } public void setActiveIdx(int idx) { if (idx >= 0 && idx < time.length) { activeIdx = idx; } else { activeIdx = -1; } } public boolean setActiveCaliperTime(long newTime) { if (activeIdx == -1) { return false; } time[activeIdx] = newTime; return true; } public void swapAnchor() { long tmp = time[0]; time[0] = time[1]; time[1] = tmp; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/TimelineSelectionCaliperEvent.java�����������������0000644�0001750�0001750�00000001741�14517772113�025677� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; /** Holds information about timeline caliper state */ public class TimelineSelectionCaliperEvent extends TimelineSelectionGenericEvent { public final TimelineCaliper caliper; public TimelineSelectionCaliperEvent(TimelineCaliper caliper) { this.caliper = caliper.clone(); } } �������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/TimelineSelectionListener.java���������������������0000644�0001750�0001750�00000002131�14517772113�025075� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; /** * TimelineSelectionListeners are notified when the selected objects in the timeline change. This * allows for the display around the timeline component to update. */ public interface TimelineSelectionListener { /** * Called by the Timeline for each TimelineSelection Listener when there is a change in selected * objects. */ public void valueChanged(TimelineSelectionGenericEvent e); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/CoordCalcTimeReader.java���������������������������0000644�0001750�0001750�00000002715�14517772113�023556� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; public interface CoordCalcTimeReader { // pixels public int getMargin(); public int getCanvasPixels(); public int getAvailPixels(); // pixels available for data // time public long getTimeStart(); public long getTimeEnd(); public long getTimeDuration(); // bin-related public int getNumBins(); public long getTimePerBin(); public long getTimeStartAligned(); public long getTimeStartAligned(long time); // return is >= 0 public long getTimeEndAligned(); // conversions public int getCoordAtTime(long time); public int getLowCoordForBin(int bin); public long getTimeAtCoord(int xx); // returns -1 if coord out of range public long getTimeNearCoord(int xx); // always returns a valid time public int getBinAtTime(long time); } ���������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/TimelineSelectionGenericEvent.java�����������������0000644�0001750�0001750�00000001661�14517772113�025675� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; /** * A TimelineSelectionEvent object contains pointers to the objects selected in the timeline by a * single gesture. It is assumed that one state may be selected and multiple messages. */ public class TimelineSelectionGenericEvent {} �������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/CoordCalcTimeMaster.java���������������������������0000644�0001750�0001750�00000002135�14517772113�023603� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; public abstract class CoordCalcTimeMaster implements CoordCalcTimeReader { public abstract void setCanvasPixels(int visiblePixels); public abstract void edt_revalidate(); // must be called from event dispatch thread public abstract boolean isValid(); // must be called from event dispatch thread public abstract boolean isInitialized(); public abstract void setTimeRange(long start, long end); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/TimelineSelectionHistoryEvent.java�����������������0000644�0001750�0001750�00000001754�14517772113�025765� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; /** * @author ylmaruya */ public class TimelineSelectionHistoryEvent extends TimelineSelectionGenericEvent { public final boolean atMin; public final boolean atMax; public TimelineSelectionHistoryEvent(boolean atMin, boolean atMax) { this.atMin = atMin; this.atMax = atMax; } } ��������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline_common/TimelineDrawer.java��������������������������������0000644�0001750�0001750�00000005233�14517772113�022674� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline_common; import java.awt.Graphics; public interface TimelineDrawer { // consts public static final long TIME_INVALID = -1; // used by IPC public void setParent(TimelinePanel parent); // YXXX yuck, use interface // ------ get components public CoordCalcTimeMaster getTimeAxisMaster(); public CoordCalcDataMaster getDataAxisMaster(); public VerticalRowRuler getVerticalRuler(); // ------ get options public boolean getEnableZoomVertical(); public boolean getEnableZoomOverlays(); public boolean getEnableUnalignedRows(); public boolean getEnableTimeCaliper(); // ------ get X & Y max dimensions public long getAbsoluteTimeStart(); public long getAbsoluteTimeEnd(); public long getAbsoluteTimeDuration(); public int getAbsoluteRowCount(); public int getAbsoluteRowEnd(); // last valid row, or 0 if no rows. // ------ zoom public void zoomCenterSelection(); // ------ selection (cursor) public boolean selectionActive(); public long getSelectionTimeCenter(); public long getSelectionTimeStart(); public long getSelectionTimeEnd(); public double getSelectionYCenter(); public boolean getSelectionNavigationEnabled(); public void selectFirst(); public void selectLeft(); public void selectRight(); public void selectUp(); public void selectDown(); public void selectLeft(boolean ctrl, boolean shift); public void selectRight(boolean ctrl, boolean shift); public void selectUp(boolean ctrl, boolean shift); public void selectDown(boolean ctrl, boolean shift); public TimelineCaliper selectNearXY( int x, int y, boolean ctrl, boolean shift); // return TimelineCaliper only on precise hit public void notifyCaliperChange(TimelineCaliper caliper); public void notifyZoomHistoryChange(TimelineSelectionHistoryEvent e); public void addSelectionListener(TimelineSelectionListener listener); // --- fetch of data public boolean edt_fetchData(boolean forceRefetch); public boolean drawData(Graphics g); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/StatisticsView.java������������������������������������������������0000644�0001750�0001750�00000024537�14517772113�017600� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnTextIcon; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.text.DecimalFormat; import java.util.ArrayList; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.border.EtchedBorder; public final class StatisticsView extends AnDisplay implements ExportSupport, AnChangeListener { private boolean experimentAdded = false; private static final DecimalFormat statis_fmt = new DecimalFormat("0.###"); private static final Object syncFormat = new Object(); private AnTree tree; // Constructor public StatisticsView() { super(AnWindow.getInstance(), AnDisplay.DSP_Statistics, AnVariable.HELP_TabsStatistics); setAccessibility(AnLocale.getString("Statistics")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("StatisticsView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: experimentAdded = true; if (selected) { computeOnAWorkerThread(); } break; case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case FILTER_CHANGING: case FILTER_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void requestFocus() { if (tree != null) { tree.requestFocus(); } } // Initialize GUI components @Override protected void initComponents() { setLayout(new BorderLayout()); tree = new AnTree(AnLocale.getString("Experiments"), 1); tree.getAccessibleContext().setAccessibleName(AnLocale.getString("Experiments")); tree.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Experiments")); add(new AnJScrollPane(tree), BorderLayout.CENTER); } // Append added experiment private void addExperiment() { AnTextIcon[] exp_list; int last; exp_list = window.getExperimentList(); if (exp_list == null) { return; } // Add the extra node "<Sum across selected experiments>" if needed & // Get the last index last = tree.addExtra(AnLocale.getString("<Sum across selected experiments>")); // Add experiment into tree tree.addNodes(exp_list, last); } // Compute & update Statistics display @Override public void doCompute() { Object[] ov_data, st_data; String errstr; int size; AnUtility.checkIfOnAWTThread(false); // Not selected if (!selected) { return; } if (experimentAdded) { addExperiment(); experimentAdded = false; } if (!computed) { // need re-compute // Get data ov_data = getStatisOverviewList(); errstr = window.getMsg(AnUtility.ERROR_MSG); if ((ov_data != null) && (errstr == null)) { st_data = getStatisList(); errstr = window.getMsg(AnUtility.ERROR_MSG); if ((st_data != null) && (errstr == null)) { size = ov_data.length; for (int i = 1; i < size; i++) { tree.setContent(i - 1, getContent(ov_data, st_data, i)); } } } showError(errstr); } tree.setSelectionRow(0); computed = true; } @Override public java.util.List<ExportSupport.ExportFormat> getSupportedExportFormats() { java.util.List<ExportSupport.ExportFormat> formats = new ArrayList<ExportSupport.ExportFormat>(); // formats.add(ExportSupport.ExportFormat.TEXT); // formats.add(ExportSupport.ExportFormat.HTML); // formats.add(ExportSupport.ExportFormat.CSV); formats.add(ExportSupport.ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return true; } // Set container for one experiment element private JPanel getContent(Object[] ov_data, Object[] st_data, int index) { JPanel panel, inter_panel; AnList ov_list, st_list; inter_panel = new JPanel(); inter_panel.setLayout(new BoxLayout(inter_panel, BoxLayout.X_AXIS)); // Overview panel ov_list = processOVData(ov_data, index); ov_list.getAccessibleContext().setAccessibleName(AnLocale.getString("Overview")); ov_list.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Overview")); ov_list.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); inter_panel.add(ov_list); inter_panel.add(Box.createHorizontalStrut(4)); // Statistics panel st_list = processSTData(st_data, index); st_list.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); inter_panel.add(st_list); st_list.getAccessibleContext().setAccessibleName(AnLocale.getString("Statistics")); st_list.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Statistics")); panel = new JPanel(new BorderLayout(2, 2)); panel.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); panel.add( AnUtility.getHeader(AnLocale.getString("Execution statistics for entire program:")), BorderLayout.NORTH); panel.add(inter_panel, BorderLayout.CENTER); return panel; } // Process Overview data private static AnList processOVData(Object[] data, int index) { AnList ov_list; String[] label; double[] value; int size, columns; int i; double total; AnDouble dvalue; String dstr; // Compute overview data ov_list = new AnList(false); label = (String[]) data[0]; value = (double[]) data[index]; size = label.length; // Get total total = 0.0; for (i = 5; i < size; i++) { total += value[i]; } columns = (new AnDouble(total)).toString().length() + AnDouble.quote_space.length(); // Write Overview header for (i = 0; i < 5; i++) { dvalue = new AnDouble(value[i]); dstr = (dvalue.doubleValue() < 0.0) ? AnLocale.getString("N/A") : dvalue.toString(); if (label[i].equals(AnLocale.getString("Total LWP Time (sec.)"))) { total = dvalue.doubleValue(); } ov_list.add( AnUtility.getItem(label[i] + ":"), AnUtility.getNumber(dstr + AnDouble.quote_space, columns)); } // Write Overview values ov_list.add((JComponent) null, (JComponent) null); ov_list.add(AnUtility.getItem(AnLocale.getString("Process Times (sec.):")), null); for (i = 5; i < size; i++) { double percent = total == 0.0 ? total : (value[i] / total) * 100; ov_list.add( AnUtility.getItem(label[i] + ":"), AnUtility.getNumber((new AnDouble(value[i])).toPercentQuote(percent), columns)); } return ov_list; } // Process Statistics data private static AnList processSTData(Object[] data, int index) { AnList st_list; String[] label; String[] value_str; double[] value; int size, len, columns; int i; // Write statistics data st_list = new AnList(false); label = (String[]) data[0]; value = (double[]) data[index]; size = label.length; value_str = new String[size]; columns = 0; for (i = 0; i < size; i++) { synchronized (syncFormat) { // begin critical section: format is not thread safe value_str[i] = statis_fmt.format(value[i]); } // end of critical section len = value_str[i].length(); if (columns < len) { columns = len; } } for (i = 0; i < size; i++) { st_list.add(AnUtility.getItem(label[i] + ":"), AnUtility.getNumber(value_str[i], columns)); } return st_list; } // Native methods from liber_dbe.so private Object[] getStatisOverviewList() { synchronized (IPC.lock) { window.IPC().send("getStatisOverviewList"); window.IPC().send(0); return (Object[]) window.IPC().recvObject(); } } private Object[] getStatisList() { synchronized (IPC.lock) { window.IPC().send("getStatisList"); window.IPC().send(0); return (Object[]) window.IPC().recvObject(); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnShellCommand.java������������������������������������������������0000644�0001750�0001750�00000013110�14517772113�017421� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; /** * Class ShellCommand executes an external program and supports input/output functions * * <p>Main functions: run a program write to stdin read from stdout read from stderr return exit * status */ class AnShellCommand { private BufferedReader processOutput; private BufferedReader processError; private PrintStream processInput; private Runtime rt; protected boolean interrupted; protected Process thisProcess; protected String shArgs; protected String errors; protected String output; protected String remoteConnection; // NM protected static ByteArrayOutputStream lastOutput; /** Creates a new instance of ShellCommand */ public AnShellCommand() { processOutput = null; processError = null; thisProcess = null; rt = Runtime.getRuntime(); interrupted = false; shArgs = null; errors = ""; output = ""; } /** * Set the remote connection * * @param args - connection */ public void setRemoteConnection(String args) { if (null == args) { remoteConnection = null; return; } remoteConnection = new String(args); } /** * Set the arguments * * @param args - arguments */ public void setShellArgs(String args) { shArgs = new String(args); } /** Interrupt and destroy the process */ public void interrupt() { interrupted = true; thisProcess.destroy(); thisProcess = null; } /** Return exit status */ public int exitValue() { if (interrupted) { return (-1); } try { thisProcess.waitFor(); } catch (Exception e) { return (-2); } return (thisProcess.exitValue()); } /** Check if the process is running */ public boolean isRunning() { try { int ev = thisProcess.exitValue(); } catch (IllegalThreadStateException ie) { return (true); } catch (Exception ie) { return (false); } return (false); } /** * Read from a stream * * @param reader - a stream */ private String readStream(BufferedReader reader) throws Exception { String ret = null; try { if (!reader.ready()) { int ev = thisProcess.exitValue(); ret = reader.readLine(); if (ret != null) { ret += "\n"; } return (ret); } ret = reader.readLine(); if (ret != null) { ret += "\n"; } } catch (IllegalThreadStateException ie) { return (""); } return (ret); } /** * Read from standard output stream * * @param shouldWait - a flag (if true, wait while read is done) */ public String readOutput(boolean shouldWait) throws Exception { String ret; if (shouldWait) { ret = processOutput.readLine(); } else { ret = readStream(processOutput); } if (ret != null) { output += ret; } return (ret); } /** * Read from standard error stream * * @param shouldWait - a flag (if true, wait while read is done) */ public String readError(boolean shouldWait) throws Exception { String ret; if (shouldWait) { ret = processError.readLine(); } else { ret = readStream(processError); } return (ret); } /** * Write to standard input stream * * @param str - a message */ public void writeInput(String str) throws Exception { processInput.print(str); processInput.flush(); } /** * Run a program * * @param dirname - working directory * @param cmnd - command line */ public void run(String dirname, String cmnd) throws Exception { if (null != dirname) { cmnd = "cd " + dirname + " && " + cmnd; } run(cmnd); } /** * Run a program * * @param cmnd - command line */ public void run(String cmnd) throws Exception { String[] ss = new String[3]; ss[0] = "sh"; // NM ss[0] = "/bin/sh"; if (shArgs == null) { ss[1] = new String("-ec"); } else { ss[1] = new String(shArgs); } // ss[2] = new String(cmnd + " 2>&1"); if (null != remoteConnection) { cmnd = remoteConnection + " ' " + cmnd + " '"; } ss[2] = new String(cmnd); interrupted = false; try { // System.err.println("DEBUG: rt.exec(): sh -ce "+cmnd); // DEBUG (perf test) thisProcess = rt.exec(ss); InputStream os = thisProcess.getInputStream(); InputStream os_err = thisProcess.getErrorStream(); OutputStream is = thisProcess.getOutputStream(); processOutput = new BufferedReader(new InputStreamReader(os)); processError = new BufferedReader(new InputStreamReader(os_err)); processInput = new PrintStream(is, true); } catch (Exception ee) { String msg = "Command \"" + cmnd + "\" failed:\n" + ee.toString(); throw new Exception(msg); } return; } } /* End of class AnShellCommand */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/CannotFindFilePanel.java�������������������������������������������0000644�0001750�0001750�00000007135�14517772113�020411� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; public class CannotFindFilePanel extends javax.swing.JPanel { private final String path; private final String msg; private final long obj_id; public CannotFindFilePanel(final String msg, final String path, long obj_id) { this.path = path; this.msg = msg; this.obj_id = obj_id; initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); textLabel.setText(msg); resolveButton.setText(AnLocale.getString("Resolve")); resolveButton.setMnemonic(AnLocale.getString('R', "resolve_button")); resolveButton.setToolTipText(AnLocale.getString(("Resolve missing source file"))); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; textLabel = new javax.swing.JLabel(); pathTextField = new javax.swing.JTextField(); resolveButton = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); textLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; add(textLabel, gridBagConstraints); pathTextField.setEditable(false); pathTextField.setBorder(null); pathTextField.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(pathTextField, gridBagConstraints); resolveButton.setText("jButton1"); resolveButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { resolveButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(resolveButton, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void resolveButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_resolveButtonActionPerformed ResolveFilePathDialog resolveFilePathDialog = new ResolveFilePathDialog(AnWindow.getInstance().getFrame(), path, obj_id); resolveFilePathDialog.setVisible(true); } // GEN-LAST:event_resolveButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextField pathTextField; private javax.swing.JButton resolveButton; private javax.swing.JLabel textLabel; // End of variables declaration//GEN-END:variables } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�015320� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/FilterParser.java�������������������������������������������0000644�0001750�0001750�00000010277�14517772113�020476� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import java.util.ArrayList; import java.util.List; import java.util.Stack; import java.util.StringTokenizer; /** * @author thp */ public class FilterParser { public enum Type { INT, DASH, COMMA }; private String filter = null; private String filterId = null; public FilterParser(String filter, String filterId) { this.filter = filter; this.filterId = filterId; } public String go() { Stack<Elem> stack = new Stack<Elem>(); Elem save = null; List<Elem> commas = new ArrayList<Elem>(); if (filter == null) { return null; } if (filter.equals("all")) { return ""; } StringTokenizer tokenizer = new StringTokenizer(filter, "-,", true); while (tokenizer.hasMoreTokens()) { String tok = tokenizer.nextToken().trim(); // System.out.println("tok=" + tok); Elem elem; if (tok.equals("-")) { elem = new Elem(Type.DASH); } else if (tok.equals(",")) { elem = new Elem(Type.COMMA); } else { try { int val = new Integer(tok).intValue(); elem = new Elem(val); } catch (NumberFormatException e) { return null; } } if (elem.getType() == Type.INT) { if (save != null) { stack.push(elem); stack.push(save); save = null; } else { stack.push(elem); } } else if (elem.getType() == Type.DASH) { if (save != null || stack.peek() == null) { return null; // Error } save = elem; } else if (elem.getType() == Type.COMMA) { if (save != null || stack.peek() == null) { return null; // Error } commas.add(elem); // save = elem; } } for (Elem com : commas) { stack.push(com); } return generateFilter(stack); } private String generateFilter(Stack<Elem> stack) { if (stack.empty()) { return ""; } Elem elem = stack.pop(); if (elem.getType() == Type.INT) { return "(" + filterId + "==" + elem.getVal() + ")"; } else if (elem.getType() == Type.DASH) { Elem elem1 = stack.pop(); Elem elem2 = stack.pop(); return "(" + filterId + ">=" + elem2.getVal() + " && " + filterId + "<=" + elem1.getVal() + ")"; } else if (elem.getType() == Type.COMMA) { String filter1 = generateFilter(stack); String filter2 = generateFilter(stack); return "(" + filter2 + " || " + filter1 + ")"; } else { assert false; } return null; // Error } class Elem { private Type type; private int val; public Elem(int val) { this.type = Type.INT; this.val = val; } public Elem(Type type) { this.type = type; this.val = 0; } /** * @return the type */ public Type getType() { return type; } /** * @return the val */ public int getVal() { return val; } } /** * @param args the command line arguments */ public static void main(String[] args) { String in; String out; test("34-38", "Samples"); test("12,23", "Samples"); test("1,2,3", "Samples"); test("1,2-3", "Samples"); test("34-38, 12, 23", "Samples"); } private static void test(String filter, String filterId) { String res = new FilterParser(filter, filterId).go(); System.out.println(filter + "========>" + res); System.out.println(); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/FilterNavigationPanel.java����������������������������������0000644�0001750�0001750�00000004461�14517772113�022317� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnWindow; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.BorderFactory; import javax.swing.JPanel; public class FilterNavigationPanel extends JPanel { /** Creates new form FilterNavigationPanel */ public FilterNavigationPanel(AnWindow anWindow) { initComponents(); setBorder( BorderFactory.createMatteBorder(0, 0, 0, 1, AnEnvironment.NAVIGATION_PANEL_BORDER_COLOR)); setBackground(AnEnvironment.NAVIGATION_PANEL_SECTION_BACKGROUND_COLOR); setMinimumSize(new Dimension(0, 70)); FilterStatusPanel filterStatusPanel = new FilterStatusPanel(anWindow); setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); add(filterStatusPanel, gridBagConstraints); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.BorderLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/CustomPanel.java��������������������������������������������0000644�0001750�0001750�00000015076�14517772113�020330� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import java.awt.BorderLayout; import javax.swing.JPanel; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; /** * @author thp */ public class CustomPanel extends JPanel { private CustomFilterDialog customFilterDialog; private CustomEditPanel customEditPanel = null; private boolean changed = false; /** Creates new form ExperimentsPanel */ public CustomPanel(Filters filter, CustomFilterDialog customFilterDialog) { this.customFilterDialog = customFilterDialog; initComponents(); String commentText = AnLocale.getString( "The Filter Specification text box initially displays filter expressions that are" + " generated when you select predefined filters in views such as the Functions" + " view. You can customize the Filter Specification by editing the filter text" + " directly."); String commentText21 = AnLocale.getString("To filter using your customizations, click OK."); commentTextArea.setText(commentText); commentTextArea.setOpaque(false); commentTextArea.setBackground(AnEnvironment.INVISIBLE_BACKGROUND); commentTextArea2.setText(commentText21); commentTextArea2.setOpaque(false); commentTextArea2.setBackground(AnEnvironment.INVISIBLE_BACKGROUND); customEditPanel = new CustomEditPanel(filter); customEditPanel.getTextPane().getDocument().addDocumentListener(new TextDocumentListner()); editPanel.add(customEditPanel, BorderLayout.CENTER); getAccessibleContext() .setAccessibleName( AnLocale.getString("Custom filter settings", "ACCESSIBILITY_Custom_Panel")); getAccessibleContext() .setAccessibleDescription( AnLocale.getString("Custom filter settings", "ACCESSIBILITY_Custom_Panel")); commentTextArea .getAccessibleContext() .setAccessibleName(AnLocale.getString("Guidance", "ACCESSIBILITY_GUIDANCE")); commentTextArea .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Guidance", "ACCESSIBILITY_GUIDANCE")); commentTextArea2 .getAccessibleContext() .setAccessibleName(AnLocale.getString("Guidance", "ACCESSIBILITY_GUIDANCE")); commentTextArea2 .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Guidance", "ACCESSIBILITY_GUIDANCE")); } class TextDocumentListner implements DocumentListener { @Override public void changedUpdate(DocumentEvent e) {} @Override public void insertUpdate(DocumentEvent e) { changed = true; customFilterDialog.updateButtonStates(); } @Override public void removeUpdate(DocumentEvent e) { changed = true; customFilterDialog.updateButtonStates(); } } public boolean hasChanges() { return changed; } public boolean hasBeenChanged() { return customEditPanel.getTextPane().getText().length() > 0; } public void resetToFactorySetting() { customEditPanel.resetToFactorySetting(); } public void addText(String text) { customEditPanel.addText(text); } public void apply() { customEditPanel.apply(); changed = false; } public void undoToLastApply() { customEditPanel.undoToLastApply(); changed = false; } public void setFilter(String filter) { customEditPanel.setFilter(filter); changed = false; customFilterDialog.updateButtonStates(); } public String getFilter() { String filter = customEditPanel.getTextPane().getText(); return filter; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; commentTextArea = new javax.swing.JTextArea(); editPanel = new javax.swing.JPanel(); commentTextArea2 = new javax.swing.JTextArea(); setLayout(new java.awt.GridBagLayout()); commentTextArea.setEditable(false); commentTextArea.setLineWrap(true); commentTextArea.setWrapStyleWord(true); commentTextArea.setBorder(null); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; add(commentTextArea, gridBagConstraints); editPanel.setLayout(new java.awt.BorderLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(editPanel, gridBagConstraints); commentTextArea2.setEditable(false); commentTextArea2.setLineWrap(true); commentTextArea2.setWrapStyleWord(true); commentTextArea2.setBorder(null); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(commentTextArea2, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextArea commentTextArea; private javax.swing.JTextArea commentTextArea2; private javax.swing.JPanel editPanel; // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/FilterStatusPanel.form��������������������������������������0000644�0001750�0001750�00000005236�14517772113�021526� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="filterLabel"> <Properties> <Property name="text" type="java.lang.String" value="NOI18N"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="6" insetsBottom="0" insetsRight="0" anchor="23" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/Filters.java������������������������������������������������0000644�0001750�0001750�00000030662�14517772113�017504� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.ipc.IPCCancelledException; import org.gprofng.mpmt.ipc.IPCContext; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Stack; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.event.ChangeListener; public final class Filters { private static Filters instance = null; private Frame frame; private AnWindow window; private CustomFilterDialog customFilterDialog; // States private Stack<FilterClause> clausesStack = new Stack<FilterClause>(); private Stack<FilterClause> clausesUndoStack = new Stack<FilterClause>(); private Stack<FilterClause> clausesRedoStack = new Stack<FilterClause>(); // Listeners private List<ChangeListener> changeListeners = new ArrayList<ChangeListener>(); // Constructor public Filters(final AnWindow window, final Frame frame) { this.window = window; this.frame = frame; instance = this; } public static Filters getInstance() { return instance; } public CustomFilterDialog getCustomFilterDialog() { if (customFilterDialog == null) { customFilterDialog = new CustomFilterDialog(frame, window); } return customFilterDialog; } public void showCustomFilterDialog() { getCustomFilterDialog().setFilter(getStandardFilters(true)); getCustomFilterDialog().setVisible(true); } private void invalidFilterDialog(String filter) { String filterTxt = filter; if (filter.length() > 200) { filterTxt = filter.subSequence(0, 199) + "..."; } String errmsg = AnLocale.getString("Invalid filter:") + "\n" + filterTxt; AnUtility.showMessage(frame, errmsg, JOptionPane.ERROR_MESSAGE); } protected String trim(String filter) { filter = filter.replaceAll("//.*\n", " "); filter = filter.replaceAll("\n", " "); filter = filter.replaceAll(" +", " "); filter = filter.trim(); return filter; } /** Reset All filters from context menus */ public void resetAllFiltersAction() { // System.out.println("Filters:resetAllFiltersAction"); if (!isFactorySetting()) { clausesStack.removeAllElements(); clausesUndoStack.removeAllElements(); clausesRedoStack.removeAllElements(); apply(false); } } /** * Returns whether the current state of filters are the default (factory setting) * * @return true if filter state is default (factory setting) */ private boolean isFactorySetting() { boolean val; val = clausesStack.isEmpty() && clausesUndoStack.isEmpty() && clausesRedoStack.isEmpty(); return val; } public List<FilterClause> getFilters() { List<FilterClause> list1 = new ArrayList<FilterClause>(); Iterator<FilterClause> iterator = clausesStack.iterator(); while (iterator.hasNext()) { FilterClause clause = iterator.next(); if (clause.isEnabled()) { if (clause.isStandardFilter()) { list1.add(clause); } else if (clause.isCustomFilter()) { list1 = new ArrayList<FilterClause>(); // reset list list1.add(clause); } else if (clause.isNoFiltersFilter()) { list1 = new ArrayList<FilterClause>(); // reset list } else { assert true; } } } List<FilterClause> list2 = new ArrayList<FilterClause>(); for (int n = list1.size() - 1; n >= 0; n--) { list2.add(list1.get(n)); } return list2; } public boolean anyFilters() { return !getFilters().isEmpty(); } public void removeClause(FilterClause clause) { // int i = clausesUndoStack.search(clause); // if (i > 0) { // clausesUndoStack.remove(clausesUndoStack.size() - i); // } clause.setEnabled(false); clausesUndoStack.push(clause); apply(false); } /** Undoes the last filter operation back to last applied */ public void undoLastFilteraction() { if (clausesUndoStack.size() > 0) { FilterClause clause = clausesUndoStack.pop(); clause.setEnabled(!clause.isEnabled()); clausesRedoStack.push(clause); } apply(false); } /** * Returns whether there are any filters to undo * * @return true if there are more filters to undo */ public boolean canUndoLastFilter() { return clausesUndoStack.size() > 0; } /** Undoes the last filter operation back to last applied */ public void redoLastFilteraction() { if (clausesRedoStack.size() > 0) { FilterClause clause = clausesRedoStack.pop(); clause.setEnabled(!clause.isEnabled()); clausesUndoStack.push(clause); } apply(false); } /** * Returns whether there are any filters to redo * * @return true if there are more filters to redo */ public boolean canRedoLastFilter() { // return redoFilters.size() > 0; return clausesRedoStack.size() > 0; } public boolean canRemoveAllFilters() { return !getFilters().isEmpty(); } private String getStandardFilters(boolean insertNL) { StringBuilder sb = new StringBuilder(); List<FilterClause> enabledFilters = new ArrayList<FilterClause>(); for (FilterClause clause : clausesStack) { if (clause.isEnabled()) { if (clause.isStandardFilter()) { enabledFilters.add(clause); } else if (clause.isCustomFilter()) { enabledFilters = new ArrayList<FilterClause>(); // reset list enabledFilters.add(clause); } else if (clause.isNoFiltersFilter()) { enabledFilters = new ArrayList<FilterClause>(); // reset list } else { assert true; } } } int n = 0; for (FilterClause fcl : enabledFilters) { if (fcl.isEnabled()) { sb.append(fcl.getClause()); if (!fcl.isCustomFilter() && insertNL) { sb.append(" // "); sb.append(fcl.getShortNameWithSerialNumber()); sb.append("\n"); } if (n < (enabledFilters.size() - 1)) { if (!fcl.isCustomFilter() && insertNL) { sb.append("&&\n"); } else { sb.append(" && "); } } } n++; } return sb.toString(); } protected void apply(final boolean showTooltip) { if (SwingUtilities.isEventDispatchThread()) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { setFilter(showTooltip); } }, "Filter Worker Thread"); } else { setFilter(showTooltip); } } /** Construct a complete filter based on settings in all three panels and apply */ private void setFilter(boolean showTooltip) { AnUtility.checkIfOnAWTThread(false); String filterString = trim(getStandardFilters(false)); if (filterString.length() == 0) { filterString = "1"; } boolean valid = validateFilterExpression(filterString); // IPC if (!valid) { invalidFilterDialog(filterString); return; } // Apply the filter setFilter(filterString.toString().replace("\n", " "), showTooltip); return; } /** * Set filter * * @param filtertext * @param showTooltip */ private void setFilter(final String filtertext, final boolean showTooltip) { AnUtility.checkIfOnAWTThread(false); if (System.getenv("SP_ANALYZER_DUMP_FILTER") != null) { System.err.println("setFilterStr: w_id=" + 0 + " filtertext='" + filtertext + "'"); } synchronized (AnVariable.mainFlowLock) { IPCContext.newCurrentContext( AnLocale.getString("Setting filter..."), IPCContext.Scope.SESSION, false, AnWindow.getInstance()); Object progressBarHandle = AnWindow.getInstance() .getSystemProgressPanel() .progressBarStart(AnLocale.getString("Setting Filter")); String msg = null; try { msg = setFilterStr(0, filtertext); // IPC } catch (IPCCancelledException ex) { System.out.println("\nfilter cancelled..."); } final String message = msg; AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { if (message != null) { // Filter setting failed String errmsg = AnLocale.getString("Error: ") + message; AnUtility.showMessage(frame, errmsg, JOptionPane.ERROR_MESSAGE); } else { AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(showTooltip, AnChangeEvent.Type.FILTER_CHANGING)); AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(showTooltip, AnChangeEvent.Type.FILTER_CHANGED)); } } }); AnWindow.getInstance().getSystemProgressPanel().progressBarStop(progressBarHandle); IPCContext.newCurrentContext(null, IPCContext.Scope.SESSION, false, AnWindow.getInstance()); } } /** * Setting clause * * @param clause the filter clause */ public void addClause( String shortName, String longName, String clauseText, FilterClause.Kind kind) { if (clauseText == null) { return; } // System.out.println("FilterSelector:setClause: " + clause); FilterClause cl = new FilterClause(shortName, longName, clauseText, kind); addClause(cl, true); } public void addClause(FilterClause cl, boolean showTooltip) { clausesStack.push(cl); clausesUndoStack.push(cl); clausesRedoStack.removeAllElements(); apply(showTooltip); } public JMenu removeFilterMenuItem() { JMenu removeMenu = new JMenu(AnLocale.getString("Remove Filter")); List<FilterClause> filters = getFilters(); for (FilterClause filterClause : filters) { JMenuItem mi = new JMenuItem(); mi.setText(filterClause.getShortNameWithSerialNumber()); removeMenu.add(mi); final FilterClause fc = filterClause; mi.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { removeClause(fc); } }); } return removeMenu; } private String setFilterStr(final int win_id, final String filter) { synchronized (IPC.lock) { window.IPC().send("setFilterStr"); window.IPC().send(win_id); window.IPC().send(filter); String s = window.IPC().recvString(); lastFilterStr = null; lastFilterStr = getFilterStr(win_id); // Optimization return s; } } private static String lastFilterStr = null; // Optimization. Important for context menu. public String getFilterStr(final int win_id) { if (null != lastFilterStr) { return lastFilterStr; // Optimization } synchronized (IPC.lock) { window.IPC().send("getFilterStr"); window.IPC().send(win_id); lastFilterStr = window.IPC().recvString(); // Optimization return lastFilterStr; } } public boolean validateFilterExpression(final String str_expr) { synchronized (IPC.lock) { window.IPC().send("validateFilterExpression"); window.IPC().send(str_expr); int val = window.IPC().recvInt(); return val != 0; } } public Object[] getFilterKeywords() { synchronized (IPC.lock) { window.IPC().send("getFilterKeywords"); window.IPC().send(0); Object[] obj = (Object[]) window.IPC().recvObject(); return obj; } } } ������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/FilterTextField.java����������������������������������������0000644�0001750�0001750�00000014107�14517772113�021126� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.util.gui.ActionTextField; import org.gprofng.mpmt.util.gui.ToolTipPopup; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; /** * @author tpreisle */ public class FilterTextField extends ActionTextField { private Color background; private FilterClause clause; private Filters filter; private ToolTipPopup tooltipPopup = null; public FilterTextField(Filters filter, Color background, FilterClause clause) { this.filter = filter; this.background = background; this.clause = clause; setForeground(AnEnvironment.FILTER_FOREGROUND_COLOR); setBackground(background); setFont(getFont().deriveFont(Font.BOLD)); setBorder(null); setEditable(false); setActionToolTipText(AnLocale.getString("Remove this filter")); String clauseTT = clause.getClause(); if (clauseTT.length() > 100) { clauseTT = clauseTT.substring(0, 100) + "..."; } setToolTipText( "<html><b>" + (clause.getLongName() != null ? clause.getLongName() : "???") + "</b>" + ": " + clauseTT + "</html>"); } @Override public void paint(Graphics g) { if (focused) { setBackground(AnEnvironment.FILTER_BACKGROUND_SELECTED_COLOR); } else { setBackground(background); } super.paint(g); } // @Override @Override public void mouseClicked(MouseEvent me) { if (me.getButton() == MouseEvent.BUTTON3) { showContextMenu(FilterTextField.this, me.getPoint().x + 5, me.getPoint().y + 5); } } // @Override @Override public void mouseExited(MouseEvent me) { super.mouseExited(me); hideTooltipPopup(); } // @Override @Override public void mouseReleased(MouseEvent me) { super.mouseReleased(me); if (!me.isConsumed()) { showTooltipPopup(); } } private void showTooltipPopup() { if (tooltipPopup != null) { return; } JPanel panel = new JPanel(); panel.setOpaque(false); panel.setLayout(new GridBagLayout()); Font font = getFont().deriveFont(Font.PLAIN); int gridy = 0; GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; JLabel label1 = new JLabel(); label1.setFont(label1.getFont().deriveFont(Font.BOLD)); String viewName = clause.getViewName(); if (viewName != null) { label1.setText(viewName + ": " + clause.getLongName()); } else { label1.setText(clause.getLongName()); } label1.setForeground(AnEnvironment.FILTER_FOREGROUND_COLOR); gridBagConstraints.gridy = gridy++; gridBagConstraints.insets = new Insets(0, 0, 0, 0); panel.add(label1, gridBagConstraints); JLabel label2 = new JLabel(); label2.setFont(font); label2.setText(AnLocale.getString("Expression: ") + clause.getClause(110)); label2.setForeground(AnEnvironment.TOOLTIP_POPUP_FOREGROUND_COLOR); gridBagConstraints.gridy = gridy++; gridBagConstraints.insets = new Insets(4, 0, 0, 0); panel.add(label2, gridBagConstraints); tooltipPopup = new ToolTipPopup(this, panel, ToolTipPopup.Location.EAST, false); tooltipPopup.show(); } private void hideTooltipPopup() { if (tooltipPopup != null) { tooltipPopup.hide(); tooltipPopup = null; } } protected void showTooltipPopupAdded() { JPanel panel = new JPanel(); panel.setOpaque(false); panel.setLayout(new GridBagLayout()); int gridx = 0; GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; JLabel label0 = new JLabel(); label0.setText(AnLocale.getString("New filter added:")); label0.setForeground(AnEnvironment.TOOLTIP_POPUP_FOREGROUND_COLOR); label0.setFont(label0.getFont().deriveFont(Font.BOLD)); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 0, 0, 0); panel.add(label0, gridBagConstraints); JLabel label1 = new JLabel(); label1.setFont(label1.getFont().deriveFont(Font.BOLD)); label1.setText(clause.getShortName()); label1.setForeground(AnEnvironment.FILTER_FOREGROUND_COLOR); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 4, 0, 0); panel.add(label1, gridBagConstraints); ToolTipPopup toolTipPopup = new ToolTipPopup(this, panel, ToolTipPopup.Location.EAST, true); toolTipPopup.show(0, 3000); } protected void removeButtonActionPerformed(java.awt.event.ActionEvent evt) { filter.removeClause(clause); hideTooltipPopup(); } private void showContextMenu(Component component, int x, int y) { JPopupMenu popup = new JPopupMenu(); JMenuItem removeItem = new JMenuItem(AnLocale.getString("Remove this filter")); popup.add(removeItem); removeItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { removeButtonActionPerformed(null); } }); popup.show(component, x, y); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/CustomPanel.form��������������������������������������������0000644�0001750�0001750�00000011031�14517772113�020335� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,48,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JTextArea" name="commentTextArea"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="lineWrap" type="boolean" value="true"/> <Property name="wrapStyleWord" type="boolean" value="true"/> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="null"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="editPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Container> <Component class="javax.swing.JTextArea" name="commentTextArea2"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="lineWrap" type="boolean" value="true"/> <Property name="wrapStyleWord" type="boolean" value="true"/> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="null"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="25" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/UndoFilterAction.java���������������������������������������0000644�0001750�0001750�00000002361�14517772113�021300� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JMenuItem; /** * @author tpreisle */ public class UndoFilterAction extends AbstractAction { public JMenuItem jmi = null; public UndoFilterAction() { super(AnLocale.getString("Undo Filter Action") /*, AnUtility.back_filt_icon*/); } @Override public void actionPerformed(ActionEvent ev) { AnWindow anWindow = AnWindow.getInstance(); anWindow.getFilters().undoLastFilteraction(); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/FilterNavigationPanel.form����������������������������������0000644�0001750�0001750�00000003741�14517772113�022341� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Form> �������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/CustomFilterAction.java�������������������������������������0000644�0001750�0001750�00000002464�14517772113�021651� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JMenuItem; /** * @author tpreisle */ public class CustomFilterAction extends AbstractAction { public JMenuItem jmi = null; public CustomFilterAction() { super(AnLocale.getString("Add Filter: Advanced Custom Filter...")); } public CustomFilterAction(String name) { super(AnLocale.getString(name)); } public void actionPerformed(ActionEvent ev) { AnWindow anWindow = AnWindow.getInstance(); anWindow.getFilters().showCustomFilterDialog(); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/FilterClause.java�������������������������������������������0000644�0001750�0001750�00000005563�14517772113�020460� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; /** * @author tpreisle */ public class FilterClause { public enum Kind { STANDARD, CUSTOM, NO_FILTERS }; private static int serialNumberCounter = 1; private String shortName; private String longName; private String clause; private boolean enabled; private Kind kind; private int serialNumber = 0; public FilterClause(String shortName, String longName, String clause, FilterClause.Kind kind) { this.shortName = shortName; this.longName = longName; this.clause = clause; this.enabled = true; this.kind = kind; if (kind != Kind.NO_FILTERS) { this.serialNumber = serialNumberCounter++; } } public static FilterClause getNoFiltersClause() { return new FilterClause(null, null, "1", Kind.NO_FILTERS); } /** * @return the kind */ public Kind getKind() { return kind; } /** * @return the displayName */ public String getShortName() { return shortName; } /** * @return the displayName */ public String getShortNameWithSerialNumber() { return serialNumber + ": " + shortName; } public String getViewName() { String viewName = null; if (getShortName() != null) { int i = getShortName().indexOf(':'); if (i > 0) { viewName = getShortName().substring(0, i); } } return viewName; } /** * @return the clause */ public String getClause() { return clause; } public String getClause(int maxCharacters) { String shortClause = getClause(); if (clause.length() > maxCharacters) { shortClause = shortClause.substring(0, maxCharacters) + "..."; } return shortClause; } /** * @return the enabled */ public boolean isEnabled() { return enabled; } public boolean isStandardFilter() { return getKind() == Kind.STANDARD; } public boolean isCustomFilter() { return getKind() == Kind.CUSTOM; } public boolean isNoFiltersFilter() { return getKind() == Kind.NO_FILTERS; } /** * @param enabled the enabled to set */ public void setEnabled(boolean enabled) { this.enabled = enabled; } /** * @return the longName */ public String getLongName() { return longName; } } ���������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/CustomFilterDialog.java�������������������������������������0000644�0001750�0001750�00000010735�14517772113�021633� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.mpmt.AnDialog; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dialog; import java.awt.Dimension; import java.awt.Frame; import java.awt.event.ActionEvent; import javax.swing.JOptionPane; import javax.swing.JPanel; /** * @author tpreisle */ public class CustomFilterDialog extends AnDialog { private Frame frame; private AnWindow window; private JPanel mainPanel; private CustomPanel customPanel; private static int customFilterNumber = 1; public CustomFilterDialog(Frame frame, AnWindow window) { super( window, frame, AnLocale.getString("Advanced Custom Filter"), false, null, null, AnVariable.HELP_Filter); this.window = window; setModalityType(Dialog.ModalityType.APPLICATION_MODAL); customPanel = new CustomPanel(window.getFilters(), this); mainPanel = new JPanel(); mainPanel.setLayout(new BorderLayout()); mainPanel.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Custom Filter")); mainPanel.getAccessibleContext().setAccessibleName(AnLocale.getString("Custom Filter")); mainPanel.add(customPanel, BorderLayout.CENTER); mainPanel.setPreferredSize(new Dimension(700, 500)); setAccessory(mainPanel); updateButtonStates(); close.setText(AnLocale.getString("Cancel")); // close.setMnemonic(AnLocale.getString('C', "MNEM_DIALOG_CANCEL")); apply.setVisible(false); } public void setFilter(String filters) { customPanel.setFilter(filters); } public String getFilter() { return customPanel.getFilter(); } @Override public void setVisible(boolean val) { super.setVisible(val); updateButtonStates(); } @Override public void actionPerformed(final ActionEvent event) { final String cmd = event.getActionCommand(); if (cmd.equals(AnLocale.getString("Cancel", "FILTER_DATA_CANCEL"))) { setVisible(false); } else if (cmd.equals(AnLocale.getString("OK", "FILTER_DATA_OK"))) { createCustomFilterFromDialog(); } } @Override protected boolean vetoClose() { return true; } protected final void updateButtonStates() { boolean hasChanges = customPanel.hasChanges(); ok.setEnabled(hasChanges); } private void createCustomFilterFromDialog() { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { String customFilter = getFilter(); if (customFilter.length() > 0) { if (!window .getFilters() .validateFilterExpression(window.getFilters().trim(customFilter))) { // IPC invalidFilterDialog(customFilter); return; } } window .getFilters() .addClause( AnLocale.getString("Custom Filter " + customFilterNumber), AnLocale.getString("Custom Filter " + customFilterNumber), customFilter, FilterClause.Kind.CUSTOM); customFilterNumber++; AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { setVisible(false); } }); } }, "Filter Worker Thread"); } private void invalidFilterDialog(String filter) { String filterTxt = filter; if (filter.length() > 200) { filterTxt = filter.subSequence(0, 199) + "..."; } String errmsg = AnLocale.getString("Invalid filter:") + "\n" + filterTxt; AnUtility.showMessage(frame, errmsg, JOptionPane.ERROR_MESSAGE); } } �����������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/KeywordsPanel.java������������������������������������������0000644�0001750�0001750�00000010335�14517772113�020656� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import java.util.Formatter; import javax.swing.border.LineBorder; /** * @author thp */ public class KeywordsPanel extends javax.swing.JPanel { public KeywordsPanel(Filters filter) { initComponents(); scrollPane.setBorder(new LineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR, 1)); String text = computeKeywords(filter); textArea.setText(text); textArea.setCaretPosition(0); textArea.setBackground(AnEnvironment.DEFAULT_TEXT_PANE_RO_BACKGROUND); textArea.setBorder(null); textArea.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Keywords")); textArea.getAccessibleContext().setAccessibleName(AnLocale.getString("Keywords")); } private String computeKeywords(Filters filter) { String empty = ""; Object[] obj = filter.getFilterKeywords(); if (obj == null) { return empty; // weird } String[] kwCategory = (String[]) (obj[0]); String[] kwCategoryI18N = (String[]) (obj[1]); String[] kwDataType = (String[]) (obj[2]); String[] kwKeyword = (String[]) (obj[3]); String[] kwFormula = (String[]) (obj[4]); String[] kwDescrip = (String[]) (obj[5]); Object[] kwEnumDescs = (Object[]) (obj[6]); String sectionFormat = "------ %s ------\n"; String categoryFormat = "%s\n"; String keywordFormat = " %-20s %s\n"; String previousCategory = empty; StringBuilder stringBuffer = new StringBuilder(); for (int i = 0; i < kwKeyword.length; i++) { if (kwKeyword[i] == null) { stringBuffer.append(new Formatter().format(sectionFormat, kwCategoryI18N[i])); continue; } String cat = kwCategoryI18N[i]; if (previousCategory.compareTo(cat) != 0) { stringBuffer.append(new Formatter().format(categoryFormat, cat)); } previousCategory = cat; String[] enumDescs = (String[]) kwEnumDescs[i]; String keyword = kwKeyword[i]; if (kwDescrip[i] != null) { stringBuffer.append(new Formatter().format(keywordFormat, keyword, kwDescrip[i])); keyword = empty; } if (kwFormula[i] != null) { stringBuffer.append(new Formatter().format(keywordFormat, keyword, kwFormula[i])); keyword = empty; } int numEnums = enumDescs != null ? enumDescs.length : 0; for (int jj = 0; jj < numEnums; jj++) { stringBuffer.append(new Formatter().format(keywordFormat, keyword, enumDescs[jj])); keyword = empty; } } return stringBuffer.toString(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { scrollPane = new javax.swing.JScrollPane(); textArea = new javax.swing.JTextArea(); setLayout(new java.awt.BorderLayout()); textArea.setColumns(20); textArea.setEditable(false); textArea.setFont(new java.awt.Font("Monospaced", 0, 12)); textArea.setRows(10); textArea.setWrapStyleWord(true); scrollPane.setViewportView(textArea); add(scrollPane, java.awt.BorderLayout.CENTER); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JScrollPane scrollPane; private javax.swing.JTextArea textArea; // End of variables declaration//GEN-END:variables } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/KeywordsPanel.form������������������������������������������0000644�0001750�0001750�00000006333�14517772113�020703� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> <SubComponents> <Container class="javax.swing.JScrollPane" name="scrollPane"> <AuxValues> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout" value="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout$BorderConstraintsDescription"> <BorderConstraints direction="Center"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <SubComponents> <Component class="javax.swing.JTextArea" name="textArea"> <Properties> <Property name="columns" type="int" value="20"/> <Property name="editable" type="boolean" value="false"/> <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> <Font name="Monospaced" size="12" style="0"/> </Property> <Property name="rows" type="int" value="10"/> <Property name="wrapStyleWord" type="boolean" value="true"/> </Properties> </Component> </SubComponents> </Container> </SubComponents> </Form> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/RedoFilterAction.java���������������������������������������0000644�0001750�0001750�00000002360�14517772113�021263� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JMenuItem; /** * @author tpreisle */ public class RedoFilterAction extends AbstractAction { public JMenuItem jmi = null; public RedoFilterAction() { super(AnLocale.getString("Redo Filter Action") /*, AnUtility.fwd_filt_icon*/); } @Override public void actionPerformed(ActionEvent ev) { AnWindow anWindow = AnWindow.getInstance(); anWindow.getFilters().redoLastFilteraction(); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/FilterStatusPanel.java��������������������������������������0000644�0001750�0001750�00000041400�14517772113�021475� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnIconButton; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.statuspanel.StatusLabelValueHandle; import org.gprofng.mpmt.util.gui.AnGradientPanel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; public class FilterStatusPanel extends JPanel implements AnChangeListener { private JButton undoButton; private JButton resetButton; private JButton redoButton; private JButton manageButton; private JTextArea infoArea; private final AnWindow anWindow; private List<FilterTextField> filterTextFields = new ArrayList<FilterTextField>(); private JPanel listPanel; private JScrollPane scrollPane; private int gridy = 0; /** Creates new form FilterStatusPanel */ public FilterStatusPanel(final AnWindow anWindow) { this.anWindow = anWindow; initComponents(); filterLabel.setFont(filterLabel.getFont().deriveFont(Font.BOLD)); filterLabel.setForeground(AnEnvironment.FILTER_HEADER_COLOR); // setBackground(AnEnvironment.NAVIGATION_PANEL_BACKGROUND_2_COLOR); setOpaque(false); // setOpaque(true); // setBackground(Color.yellow); updateLabel(0); GridBagConstraints gridBagConstraints; // Button panel undoButton = new AnIconButton(AnUtility.undo_icon); undoButton.setToolTipText(AnLocale.getString("Undo filter action")); undoButton.addActionListener(new UndoFilterAction()); resetButton = new AnIconButton(AnUtility.restore_icon); resetButton.setToolTipText(AnLocale.getString("Remove all filters")); resetButton.addActionListener(new RemoveAllFilterAction()); redoButton = new AnIconButton(AnUtility.redo_icon); redoButton.setToolTipText(AnLocale.getString("Redo filter action")); redoButton.addActionListener(new RedoFilterAction()); manageButton = new AnIconButton(AnUtility.compareHamburgerIcon); manageButton.setToolTipText(AnLocale.getString("Add or remove filters")); manageButton.addActionListener( new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { anWindow.getViews().getCurrentViewDisplay().showFilterPopup(manageButton); } }); JPanel buttonPanel = new AnGradientPanel( AnEnvironment.FILTER_TOOLBAR_BACKGROUND1_COLOR, AnEnvironment.FILTER_TOOLBAR_BACKGROUND2_COLOR); buttonPanel.setBackground(AnEnvironment.NAVIGATION_PANEL_SECTION_BACKGROUND_COLOR); buttonPanel.setLayout(new GridBagLayout()); buttonPanel.setBorder( BorderFactory.createMatteBorder(1, 1, 1, 1, AnEnvironment.FILTER_STATUS_BORDER_COLOR)); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(3, 3, 2, 0); buttonPanel.add(undoButton, gridBagConstraints); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(3, 3, 2, 0); buttonPanel.add(redoButton, gridBagConstraints); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(3, 3, 2, 0); buttonPanel.add(resetButton, gridBagConstraints); gridBagConstraints.anchor = GridBagConstraints.EAST; gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(3, 0, 2, 3); buttonPanel.add(manageButton, gridBagConstraints); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; // add(buttonPanel, gridBagConstraints); // Scroll pane scrollPane = new JScrollPane(); scrollPane.setBorder( BorderFactory.createMatteBorder(0, 1, 1, 1, AnEnvironment.FILTER_STATUS_BORDER_COLOR)); scrollPane.setHorizontalScrollBarPolicy( javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; // add(scrollPane, gridBagConstraints); // Buttons and filters panel JPanel buttonAndFiltersPanel = new JPanel(new GridBagLayout()); buttonAndFiltersPanel.setBackground(AnEnvironment.NAVIGATION_PANEL_SECTION_BACKGROUND_COLOR); // buttonAndFiltersPanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, // AnEnvironment.NAVIGATION_SPLIT_PANE_DIVIDER_COLOR)); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(3, 5, 0, 4); buttonAndFiltersPanel.add(buttonPanel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(0, 5, 5, 4); buttonAndFiltersPanel.add(scrollPane, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); add(buttonAndFiltersPanel, gridBagConstraints); // List panel listPanel = new JPanel(); listPanel.setLayout(new java.awt.GridBagLayout()); listPanel.setBackground(AnEnvironment.FILTER_BACKGROUND1_COLOR); // Info text area String infoText = AnLocale.getString( "To add a filter, select a row from a view (such as Functions) and then click on the" + " toolbar Filters icon."); infoArea = new JTextArea(); AnUtility.setAccessibleContext( infoArea.getAccessibleContext(), AnLocale.getString("Info Area")); infoArea.setEditable(false); infoArea.setWrapStyleWord(true); infoArea.setLineWrap(true); infoArea.setBackground(AnEnvironment.FILTER_BACKGROUND1_COLOR); infoArea.setForeground(AnEnvironment.FILTER_INFO_TEXT_COLOR); infoArea.setMargin(new Insets(2, 2, 2, 2)); infoArea.setText(infoText); infoArea.setToolTipText(infoText); infoArea.setFont(getFont().deriveFont((float) (getFont().getSize() - 1))); AnEventManager.getInstance().addListener(this); updateStatus(false); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getInputMap(JComponent.WHEN_FOCUSED) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getActionMap() .put( KeyboardShortcuts.helpActionShortcut, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { Analyzer.getInstance().showHelp(null); } }); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("FilterStatusPanel stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: undoButton.setEnabled(false); resetButton.setEnabled(false); redoButton.setEnabled(false); manageButton.setEnabled(false); removeAllFilterTextFields(); listPanel.validate(); listPanel.repaint(); break; case EXPERIMENTS_LOADED_FAILED: case EXPERIMENTS_LOADED: manageButton.setEnabled(true); // Nothing break; case FILTER_CHANGED: Boolean showTooltip = (Boolean) e.getSource(); updateStatus(showTooltip); break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SETTING_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } private void debug() { System.out.println(this.getClass().getSimpleName()); } private void removeAllFilterTextFields() { listPanel.removeAll(); filterTextFields = new ArrayList<FilterTextField>(); gridy = 0; } private FilterTextField addFilterTextField(FilterClause clause) { Color background; if (gridy % 2 == 0) { background = AnEnvironment.FILTER_BACKGROUND1_COLOR; } else { background = AnEnvironment.FILTER_BACKGROUND2_COLOR; } FilterTextField filterTextField = new FilterTextField(anWindow.getFilters(), background, clause); filterTextField.setText(clause.getShortNameWithSerialNumber()); // filterTextField.setToolTipText((clause.getLongName() != null ? clause.getLongName() : // "???") + ": " + clause.getClause()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridy++; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(0, 2, 0, 0); listPanel.add(filterTextField, gridBagConstraints); filterTextFields.add(filterTextField); return filterTextField; } private void addFiller() { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 100; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; listPanel.add(new JLabel(), gridBagConstraints); } private void updateLabel(int noFilters) { StringBuilder text = new StringBuilder(); text.append(AnLocale.getString("Filters")); if (noFilters == 1) { text.append(": " + noFilters + " "); text.append(AnLocale.getString("active filter")); } else if (noFilters > 1) { text.append(": " + noFilters + " "); text.append(AnLocale.getString("active filters")); } filterLabel.setText(text.toString()); AnUtility.setAccessibleContext(filterLabel.getAccessibleContext(), filterLabel.getText()); filterLabel.setDisplayedMnemonic(AnLocale.getString('i', "FilterPanelActiveFiltersMN")); filterLabel.setLabelFor(manageButton); } private void updateStatus(final boolean showTooltip) { // The IPC call below should be done on a worker thread // if (!anWindow.getAnalyzer().IPC_started) { // return; // } AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { final List<FilterClause> list = anWindow.getFilters().getFilters(); AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { undoButton.setEnabled(anWindow.getFilters().canUndoLastFilter()); redoButton.setEnabled(anWindow.getFilters().canRedoLastFilter()); if (list.isEmpty()) { resetButton.setEnabled(false); anWindow .getFilterStatusHandle() .update(AnLocale.getString("off"), StatusLabelValueHandle.Mode.DEFAULT); } else { resetButton.setEnabled(true); anWindow .getFilterStatusHandle() .update(AnLocale.getString("on"), StatusLabelValueHandle.Mode.SET); } removeAllFilterTextFields(); if (list.isEmpty()) { scrollPane.setVerticalScrollBarPolicy( javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); scrollPane.setViewportView(infoArea); } else { scrollPane.setVerticalScrollBarPolicy( javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); scrollPane.setViewportView(listPanel); for (FilterClause clause : list) { addFilterTextField(clause); } addFiller(); } updateLabel(list.size()); validate(); repaint(); if (showTooltip && filterTextFields.size() > 0) { filterTextFields.get(0).showTooltipPopupAdded(); } } }); } }, "Filter_thread"); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; filterLabel = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); filterLabel.setText("NOI18N"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(3, 6, 0, 0); add(filterLabel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel filterLabel; // End of variables declaration//GEN-END:variables } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/RemoveAllFilterAction.java����������������������������������0000644�0001750�0001750�00000002426�14517772113�022263� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JMenuItem; /** * @author tpreisle */ public class RemoveAllFilterAction extends AbstractAction { public JMenuItem jmi = null; public RemoveAllFilterAction() { super(AnLocale.getString("Remove All Filters") /*, AnUtility.restore_icon*/); } @Override public void actionPerformed(ActionEvent ev) { AnWindow anWindow = AnWindow.getInstance(); anWindow.getFilters().addClause(FilterClause.getNoFiltersClause(), false); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/filter/CustomEditPanel.java����������������������������������������0000644�0001750�0001750�00000024671�14517772113�021137� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.filter; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnIconButton; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextPane; import javax.swing.KeyStroke; import javax.swing.border.LineBorder; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.text.BadLocationException; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import javax.swing.undo.UndoManager; import javax.swing.undo.UndoableEdit; public class CustomEditPanel extends JPanel { private static final String help_id = AnVariable.HELP_Filter; MyUndoManager manager = null; JTextPane pane = null; Action undoAction = null; Action redoAction = null; Action clearAction = null; public CustomEditPanel(Filters filter) { pane = new JTextPane(); pane.setEditable(true); // Editable pane.setBorder(new LineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR, 1)); pane.setForeground(AnEnvironment.FILTER_FOREGROUND_COLOR); setLayout(new BorderLayout()); add(new AnJScrollPane(pane), BorderLayout.CENTER); // Create the undo manager and actions manager = new MyUndoManager(); pane.getDocument().addUndoableEditListener(manager); undoAction = new UndoAction(manager); redoAction = new RedoAction(manager); clearAction = new ClearAction(manager); // Add the actions to buttons JButton undoButton = new AnIconButton(AnUtility.undo_icon); undoButton.setToolTipText(AnLocale.getString("Undo")); JButton redoButton = new AnIconButton(AnUtility.redo_icon); redoButton.setToolTipText(AnLocale.getString("Redo")); undoButton.addActionListener(undoAction); redoButton.addActionListener(redoAction); JPanel panel = new JPanel(); panel.setLayout(new java.awt.GridBagLayout()); GridBagConstraints gridBagConstraints; JLabel keywordsLabel = new JLabel(); AnUtility.setTextAndAccessibleContext(keywordsLabel, AnLocale.getString("Keywords:")); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(8, 0, 0, 0); gridBagConstraints.anchor = GridBagConstraints.WEST; panel.add(keywordsLabel, gridBagConstraints); AnUtility.checkIPCOnWrongThread(false); KeywordsPanel keywordsPanel = new KeywordsPanel(filter); AnUtility.checkIPCOnWrongThread(true); keywordsPanel.setPreferredSize(new Dimension(100, 180)); keywordsLabel.setLabelFor(keywordsPanel); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; panel.add(keywordsPanel, gridBagConstraints); add(panel, BorderLayout.SOUTH); panel = new JPanel(); panel.setLayout(new java.awt.GridBagLayout()); JLabel filterSpecLabel; gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(8, 0, 0, 0); gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; filterSpecLabel = new JLabel(); AnUtility.setTextAndAccessibleContext( filterSpecLabel, AnLocale.getString("Filter Specification:")); AnUtility.setTextAndAccessibleContext(keywordsLabel, AnLocale.getString("Keywords:")); panel.add(filterSpecLabel, gridBagConstraints); filterSpecLabel.setDisplayedMnemonic( AnLocale.getString('F', "MNEMONIC_FILTER_SPECIFICATION_BUTTON")); filterSpecLabel.setLabelFor(pane); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(4, 4, 2, 0); gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; gridBagConstraints.weightx = 1.0; panel.add(undoButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(4, 4, 2, 0); gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST; panel.add(redoButton, gridBagConstraints); add(panel, BorderLayout.NORTH); // Assign the actions to keys pane.registerKeyboardAction( undoAction, KeyStroke.getKeyStroke(KeyEvent.VK_Z, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED); pane.registerKeyboardAction( redoAction, KeyStroke.getKeyStroke(KeyEvent.VK_Y, InputEvent.CTRL_MASK), JComponent.WHEN_FOCUSED); getAccessibleContext() .setAccessibleName( AnLocale.getString("Custom filter settings", "ACCESSIBILITY_Custom_Panel")); getAccessibleContext() .setAccessibleDescription( AnLocale.getString("Custom filter settings", "ACCESSIBILITY_Custom_Panel")); undoButton .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Undo button", "ACCESSIBILITY_Undo_button")); redoButton .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Redo button", "ACCESSIBILITY_Redo_button")); } // class AnIconButton extends JButton implements MouseListener, FocusListener { // // public AnIconButton(Icon icon) { // super(icon); // setBorder(javax.swing.BorderFactory.createLineBorder(Color.LIGHT_GRAY)); // setOpaque(false); // setContentAreaFilled(false); // setBorderPainted(false); // // addMouseListener(this); // addFocusListener(this); // } // // public Insets getInsets() { // return new Insets(3,3,3,3); // } // // public void mouseExited(MouseEvent e) { // setBorderPainted(false); // validate(); // repaint(); // } // // public void mouseClicked(MouseEvent e) { // } // // public void mouseEntered(MouseEvent e) { // setBorderPainted(true); // validate(); // repaint(); // } // // public void mousePressed(MouseEvent e) { // } // // public void mouseReleased(MouseEvent e) { // } // // public void focusGained(FocusEvent e) { // setBorderPainted(true); // validate(); // repaint(); // } // // public void focusLost(FocusEvent e) { // setBorderPainted(false); // validate(); // repaint(); // } // } class MyUndoManager extends UndoManager { boolean applied = true; UndoableEdit applyEdit = null; public MyUndoManager() { getTextPane() .getDocument() .addUndoableEditListener( new UndoableEditListener() { public void undoableEditHappened(UndoableEditEvent evt) { UndoableEdit anEdit = evt.getEdit(); if (applied) { applyEdit = anEdit; applied = false; } } }); } public void undoToLastApply() { if (applyEdit != null) { applied = true; undoTo(applyEdit); } applyEdit = null; } public void apply() { applied = true; applyEdit = null; } } public JTextPane getTextPane() { return pane; } public void resetToFactorySetting() { clearAction.actionPerformed(null); } public void setFilter(String filter) { pane.setText(filter); } public void addText(String text) { int pos = pane.getDocument().getLength(); try { pane.getDocument().insertString(pos, text, null); } catch (BadLocationException ble) { } } public void apply() { manager.apply(); } public void undoToLastApply() { manager.undoToLastApply(); } // The Undo action public class UndoAction extends AbstractAction { private UndoManager manager; public UndoAction(UndoManager manager) { this.manager = manager; } public void actionPerformed(ActionEvent evt) { try { manager.undo(); } catch (CannotUndoException e) { Toolkit.getDefaultToolkit().beep(); } } } // The Redo action public class RedoAction extends AbstractAction { private UndoManager manager; public RedoAction(UndoManager manager) { this.manager = manager; } public void actionPerformed(ActionEvent evt) { try { manager.redo(); } catch (CannotRedoException e) { Toolkit.getDefaultToolkit().beep(); } } } // The Clear action public class ClearAction extends AbstractAction { private UndoManager manager; public ClearAction(UndoManager manager) { this.manager = manager; } public void actionPerformed(ActionEvent evt) { try { int pos = pane.getDocument().getLength(); pane.getDocument().remove(0, pos); // pane.getDocument().insertString(pos, "dsadsada", null); } catch (BadLocationException be) { } } } } �����������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnLong.java��������������������������������������������������������0000644�0001750�0001750�00000005256�14517772113�015766� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.AnObject.format_group_integer; public final class AnLong extends AnObject implements Comparable { private long value; private Long obj; public AnLong(long value) { this.value = value; obj = new Long(this.value); } // Analyzer Long printing format @Override public String toString() { if (sign) { return String.format("%+d", value); } return obj.toString(); } // Analyzer formatted printing format @Override public String toFormString() { if (value == 0) { if (!showZero) { return quote_space; } } if (sign) { return format_group_sinteger.format(value); } return format_group_integer.format(value); } // Percent printing @Override public String toPercent(double total) { if (value == 0) { if (!showZero) { return quote_space; } return zero_percent; } return format_percent.format(value * total); } // Time printing @Override public String toTime(double clock) { if (value == 0) { return get_zero_decimal(); } AnDouble d = new AnDouble(value * clock); d.showSign(sign); d.showZero(showZero); return d.toString(); } // Time formatted printing format @Override public String toFormTime(double clock) { if (value == 0) { return get_zero_decimal(); } AnDouble d = new AnDouble(value * clock); d.showSign(sign); d.showZero(showZero); return d.toFormString(); } // To Long public Long toLong() { return obj; } // To double @Override public double doubleValue() { return value; } // As Long.compareTo @Override public int compareTo(Object o) { return obj.compareTo(((AnLong) o).toLong()); } // Convert long[] to AnLong[] public static AnLong[] toArray(long[] list) { int length = list.length; AnLong[] new_list = new AnLong[length]; for (int i = 0; i < length; i++) { new_list[i] = new AnLong(list[i]); } return new_list; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/NoMetricsSelectedPanel.java����������������������������������������0000644�0001750�0001750�00000007172�14517772113�021143� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import javax.swing.JPopupMenu; public class NoMetricsSelectedPanel extends javax.swing.JPanel { private int dtype; public NoMetricsSelectedPanel(int dtype) { this.dtype = dtype; initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); textLabel.setText(AnLocale.getString("No metrics selected for this view.")); resolveButton.setText(AnLocale.getString("Select Metrics")); resolveButton.setMnemonic(AnLocale.getString('S', "select_metrics_button")); resolveButton.setToolTipText(AnLocale.getString(("Select metrics"))); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; textLabel = new javax.swing.JLabel(); pathTextField = new javax.swing.JTextField(); resolveButton = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); textLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; add(textLabel, gridBagConstraints); pathTextField.setEditable(false); pathTextField.setBorder(null); pathTextField.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(pathTextField, gridBagConstraints); resolveButton.setText("jButton1"); resolveButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { resolveButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(resolveButton, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void resolveButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_resolveButtonActionPerformed JPopupMenu popup = new JPopupMenu(); AnWindow.getInstance() .getSettings() .getMetricsSetting() .addMetricsPopupSelector(popup, dtype, true); popup.show(resolveButton, resolveButton.getWidth(), 0 /*resolveButton.getHeight()*/); } // GEN-LAST:event_resolveButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextField pathTextField; private javax.swing.JButton resolveButton; private javax.swing.JLabel textLabel; // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/CallTreeView.java��������������������������������������������������0000644�0001750�0001750�00000375042�14517772113�017141� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.util.gui.AnUtility.getImageIconBar; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.filter.FilterClause; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.settings.ViewModeSetting; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Vector; import java.util.concurrent.atomic.AtomicBoolean; import javax.accessibility.AccessibleContext; import javax.swing.AbstractAction; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.JViewport; import javax.swing.KeyStroke; import javax.swing.event.PopupMenuEvent; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; public final class CallTreeView extends AnDisplay implements ExportSupport, AnChangeListener { private boolean updated = false; protected boolean convertHWCtoTime = false; // Temporary fix for patch (CR 6985920) protected double clock_frequency = 1.0; // Temporary fix for patch (CR 6985920) protected long sel_func, sel_src; protected int name_col, sort_col, metric_col; private AnTable caller; private Object[][] caller_data, func_data, callee_data; private JTree calltree; // Call tree private final Object CallTreeLock = new Object(); // global lock to synchronize call tree modifications private JScrollPane tree_jsp; // Call tree scrollable pane private JScrollPane errorPane = null; private JLabel tree_label; // Call tree label private CT_TreeNode tnTotal = null; // Call tree node <Total> private boolean show_inclusive = true; private boolean show_exclusive = false; private boolean show_percentage = true; private boolean show_colorbars = true; private boolean show_tooltips = true; private boolean stop_expanding = false; private boolean stop_expanding_enabled = false; private final AtomicBoolean skip_build_subtree = new AtomicBoolean(false); // Optimization flag private boolean skip_update_summary = false; // Optimization flag private boolean sortByName = false; private int previous_metric_col = -1; // used in "Sort by Name" case private DefaultMutableTreeNode rootnode; // Call tree root node private long[] ids_callers = null; private long[] ids_callees = null; private CT_CallStack ct_callstack; private MetricLabel[] caller_label; private AnMetric[] available_metrics = new AnMetric[0]; private String metricName; // To show metric name in the Title private String metricCommandName; // To get colors for icons final String mlistStr = "MET_CALL_AGR"; final String typeStrFunction = "FUNCTION"; final String subtypeStr = "0"; final String stab_callers = "CALLERS"; final String stab_callees = "CALLEES"; final String stab_self = "SELF"; private AnMenuListener menuListener; // Menu actions final String STR_ACTION_SHOWSOURCE = AnLocale.getString("Show Source"); final String STR_ACTION_SHOWDISASM = AnLocale.getString("Show Disassembly"); final String STR_ACTION_EXPANDNODE = AnLocale.getString("Expand Node"); final String STR_ACTION_EXPANDBRANCH = AnLocale.getString("Expand Branch"); final String STR_ACTION_EXPANDHOTTEST = AnLocale.getString("Expand Hottest Branch"); final String STR_ACTION_EXPANDHOT = AnLocale.getString("Expand Hot Branches"); final String STR_ACTION_EXPANDTREE = AnLocale.getString("Expand All Branches"); final String STR_ACTION_STOPEXPANDING = AnLocale.getString("Stop Expanding"); final String STR_ACTION_COLLAPSEBRANCH = AnLocale.getString("Collapse Branch"); final String STR_ACTION_COLLAPSENODE = AnLocale.getString("Collapse Node"); final String STR_ACTION_COLLAPSETREE = AnLocale.getString("Collapse All Branches"); final String STR_ACTION_SETROOT = AnLocale.getString("Set Root"); final String STR_ACTION_RESET = AnLocale.getString("Reset Root"); final String STR_ACTION_SETMETRIC = AnLocale.getString("Set Metric"); final String STR_ACTION_REFRESH = AnLocale.getString("Refresh Tree"); final String STR_ACTION_COPY_ALL = AnLocale.getString("Copy All"); final String STR_ACTION_SETTINGS = AnLocale.getString("Call Tree Settings"); private static final String STR_SORT_BY_METRIC = AnLocale.getString("Sort By Metric"); private static final String STR_SORT_BY_NAME = AnLocale.getString("Sort By Name"); private static final String ADD_FILTER = AnLocale.getString("Add Filter: "); static final String FILTER_NAME_ACTION_NAME = "filterNameinStack"; static final String FILTER_NAME_LONG_NAME = AnLocale.getString("Include only stacks containing name"); static final String FILTER_NAME_SHORT_NAME = AnLocale.getString("Name in Stack"); static final String FILTER_SELECTED_BRANCH_ACTION_NAME = "filterSelectedBranch"; static final String FILTER_SELECTED_BRANCH_LONG_NAME = AnLocale.getString("Include only stacks containing the selected branch"); static final String FILTER_SELECTED_BRANCH_SHORT_NAME = AnLocale.getString("Selected Branch"); static final String FILTER_NOT_SELECTED_BRANCH_ACTION_NAME = "filterNotSelectedBranch"; static final String FILTER_NOT_SELECTED_BRANCH_LONG_NAME = AnLocale.getString("Include only stacks not containing the selected branch"); static final String FILTER_NOT_SELECTED_BRANCH_SHORT_NAME = AnLocale.getString("Not Selected Branch"); static final String FILTER_SELECTED_FUNCTION_ACTION_NAME = "filterSelectedfunction"; static final String FILTER_SELECTED_FUNCTION_LONG_NAME = AnLocale.getString("Include only stacks containing the selected function"); static final String FILTER_SELECTED_FUNCTION_SHORT_NAME = AnLocale.getString("Selected Function"); static final String FILTER_SELECTED_LEAF_ACTION_NAME = "filterSelectedLeaf"; static final String FILTER_SELECTED_LEAF_LONG_NAME = AnLocale.getString("Include only stacks with the selected function as leaf"); static final String FILTER_SELECTED_LEAF_SHORT_NAME = AnLocale.getString("Selected Leaf"); final String STR_ACTION_UNDO_FILTER = AnLocale.getString("Undo Filter Action"); final String STR_ACTION_REDO_FILTER = AnLocale.getString("Redo Filter Action"); final String STR_ACTION_REMOVE_ALL_FILTERS = AnLocale.getString("Remove All Filters"); final String STR_ACTION_CUSTOM_FILTER = ADD_FILTER + AnLocale.getString("Advanced Custom Filter..."); final String STR_ACTION_SHOWNEXT = AnLocale.getString("Show Next Reference To Function"); final String STR_ACTION_SHOWALL = AnLocale.getString("Show All References To Function"); final String STR_ACTION_HIDE_INCLUSIVE = AnLocale.getString("Hide Inclusive Metric"); final String STR_ACTION_SHOW_INCLUSIVE = AnLocale.getString("Show Inclusive Metric"); final String STR_ACTION_SHOW_EXCLUSIVE = AnLocale.getString("Show Exclusive Metric"); final String STR_ACTION_HIDE_PERCENTAGE = AnLocale.getString("Hide Percentage"); final String STR_ACTION_SHOW_PERCENTAGE = AnLocale.getString("Show Percentage"); final String STR_ACTION_HIDE_COLORBARS = AnLocale.getString("Hide Color Bars"); final String STR_ACTION_SHOW_COLORBARS = AnLocale.getString("Show Color Bars"); final String STR_ACTION_HIDE_TOOLTIPS = AnLocale.getString("Hide Tool tips"); final String STR_ACTION_SHOW_TOOLTIPS = AnLocale.getString("Show Tool tips"); private String STR_TREE_TITLE_FUNCTIONS; private String STR_TREE_TITLE_COMPLETE_VIEW; private String STR_TREE_TITLE_PARTIAL; private String STR_TREE_TITLE_FILTER; private String acName; private String acDesc; private String lastFilter = null; // Constructor public CallTreeView() { super(AnWindow.getInstance(), AnDisplay.DSP_CallTree, AnVariable.HELP_TabsCallTree); // System.err.println("XXX In CallTreeDisp() type: " + type + " subtype: " + subtype); STR_TREE_TITLE_FUNCTIONS = AnLocale.getString("Call Tree: FUNCTIONS."); STR_TREE_TITLE_COMPLETE_VIEW = AnLocale.getString("Complete view."); STR_TREE_TITLE_PARTIAL = AnLocale.getString("Partial view."); STR_TREE_TITLE_FILTER = AnLocale.getString("Filtered view."); // Accessibility acName = AnLocale.getString("Call Tree"); acDesc = AnLocale.getString("Functions Call Tree"); if (null != calltree) { calltree.getAccessibleContext().setAccessibleName(acName); calltree.getAccessibleContext().setAccessibleDescription(acDesc); } if (null != tree_jsp) { tree_jsp.getAccessibleContext().setAccessibleName(acName); tree_jsp.getAccessibleContext().setAccessibleDescription(acDesc); } if (null != tree_label) { String text = STR_TREE_TITLE_FUNCTIONS; tree_label.getAccessibleContext().setAccessibleName(text); tree_label.getAccessibleContext().setAccessibleDescription(text); } name_col = -1; sort_col = -1; setAccessibility(AnLocale.getString("Call Tree")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("CallTreeView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.CALL_TREE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void requestFocus() { if (calltree != null) { calltree.requestFocus(); } } @Override public JPopupMenu getFilterPopup() { return initPopup(true); } /** Initialize GUI components */ @Override protected void initComponents() { // System.err.println("XXX In CallTreeDisp.initComponents()"); setLayout(new BorderLayout()); // This is just a minimal initialization // The remaining part is in reset(). } /** Reset GUI components */ public @Override void reset() { // System.err.println("XXX In CallTreeDisp.reset()"); // Remove Call Tree if (null != tree_jsp) { // Remove selection listener CallTreeSelectionListener[] cts_listeners = calltree.getListeners(CallTreeSelectionListener.class); for (CallTreeSelectionListener listener : cts_listeners) { calltree.removeTreeSelectionListener(listener); } // Remove expansion listener CallTreeExpansionListener[] cte_listeners = calltree.getListeners(CallTreeExpansionListener.class); for (CallTreeExpansionListener listener : cte_listeners) { calltree.removeTreeExpansionListener(listener); } // CT_CollapseTree(); tnTotal = null; remove(tree_jsp); } // Init Call Tree initCallTree(); // Add Call Tree tree_jsp = new AnJScrollPane(calltree); tree_jsp.add(tree_label); add(tree_jsp, BorderLayout.CENTER); // Popup menu menuListener = new AnMenuListener(this, calltree); calltree.addMouseListener(menuListener); // this.addMouseListener(menuListener); // Do we need it? KeyStroke ks = KeyboardShortcuts.contextMenuActionShortcut; calltree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, ks); calltree .getActionMap() .put( ks, new AbstractAction() { public void actionPerformed(ActionEvent ev) { JPopupMenu popup = initPopup(false); if (popup != null) { JTree src = (JTree) ev.getSource(); Rectangle cellRect, visRect; visRect = src.getVisibleRect(); cellRect = visRect; int selrow = src.getMaxSelectionRow(); if (selrow >= 0) { cellRect = src.getRowBounds(selrow); } // if current view doesn't include selected row, scroll if (!visRect.contains(cellRect)) { // calculate middle based on selected row // being below or above current visible rows if (visRect.y < cellRect.y) { cellRect.y += visRect.height / 2; } else { cellRect.y -= visRect.height / 2; } src.scrollRectToVisible(cellRect); } popup.show(src, cellRect.x, cellRect.y + cellRect.height); } } }); } // Init Call Tree private void initCallTree() { String text = STR_TREE_TITLE_FUNCTIONS; rootnode = new DefaultMutableTreeNode(STR_TREE_TITLE_FUNCTIONS, true); calltree = new CT_Tree(rootnode); tree_label = new JLabel(text); tree_label.setDisplayedMnemonic(AnLocale.getString('A', "MNEM_CALLTREEFUNCTIONS")); tree_label.setLabelFor(calltree); tree_label.setVisible(false); // Add a selection listener, to listen for selected nodes calltree.addTreeSelectionListener(new CallTreeSelectionListener()); // Add an expansion listener, to listen for expanded nodes calltree.addTreeExpansionListener(new CallTreeExpansionListener()); // Allow only a single node to be selected (default) calltree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); if (show_tooltips) { // Show tooltips javax.swing.ToolTipManager.sharedInstance().registerComponent(calltree); } } // Clear display public @Override void clear() { // System.err.println("XXX In CallTreeDisp.clear()"); } /** Copy all lines to the system clipboard */ protected void copyAll() { String text = exportAsText(null, ExportFormat.TEXT, null); copyToClipboard(text); } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String text = CT_PrintTree(); return text; } // Get new selected func index & compare to the old one // Note: must be called from doCompute private final long getFuncObj() { final long func_obj; if (sel_func <= 0) { // not initialized yet // need Total/Maximum from func-list data window .getFunctionsView() .computeIfNeeded(); // on worker thread and synchronized (AnVariable.mainFlowLock) } func_obj = window.getSelectedObject().getSelObjV2(typeStrFunction); // API V2 if (sel_func != func_obj) { updated = false; } return func_obj; } private static int ThreadID = 0; // Semaphore private final Object shortLock = new Object(); // For short critical sections /** Compute & update call tree */ @Override public void doCompute() { synchronized (shortLock) { if (inCompute) { return; } inCompute = true; } // Only one thread at a time doCompute_internal(); synchronized (shortLock) { inCompute = false; } } // Compute & update call tree private void doCompute_internal() { long ID_to_expand; AnUtility.checkIfOnAWTThread(false); if (!selected) { return; // Not selected - nothing to do. } if (window .getSettings() .getCompareModeSetting() .comparingExperiments()) { // XXXX show error when compare is on, needs simplified, but the // situation is different for different views reset(); JLabel error_label = new JLabel(); error_label.setHorizontalAlignment(JLabel.CENTER); error_label.getAccessibleContext().setAccessibleName(AnLocale.getString("Error message")); error_label .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Error message")); JViewport error_view = new JViewport(); error_view.setView(error_label); String msg = AnLocale.getString("Not available when comparing experiments"); error_label.setText(msg); if (errorPane == null) { errorPane = new AnJScrollPane(); add(errorPane, BorderLayout.CENTER); } errorPane.setViewportView(error_view); errorPane.setVisible(true); if (tree_jsp != null) { tree_jsp.setVisible(false); } return; } if (errorPane != null) { errorPane.setVisible(false); } if (tree_jsp != null) { tree_jsp.setVisible(true); } long starttime = System.currentTimeMillis(); long t = starttime; sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) // TEMPORARY // long my_sel_func = sel_func; // System.out.println("CallTree step 1 time: " + (System.currentTimeMillis() - t) + " ms"); // // DEBUG t = System.currentTimeMillis(); int progress = 1; int version = 1; if (!computed) { // need re-compute reset(); // window.setBusyCursor(true); // Repeat after reset() DefaultMutableTreeNode dn; if (ct_callstack == null) { ct_callstack = new CT_CallStack(); } else { ct_callstack.reset(); sel_func = my_sel_func; // reset() sets sel_func to <Total> } ID_to_expand = sel_func; sort_col = window.getSettings().getMetricsSetting().getSortColumnByDType(DSP_CallTree); int buildlevel = 2; // min tree depth int maxlevel = 5; // tree depth int threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % window .getSystemProgressPanel() .setProgress(progress, AnLocale.getString("Initializing call tree")); dn = CT_BuildTree(calltree, buildlevel, threshold, ID_to_expand); // System.out.println("CallTree step 1a time: " + (System.currentTimeMillis() - t) + " ms // buildlevel = " + buildlevel); // DEBUG t = System.currentTimeMillis(); long curtime = System.currentTimeMillis() - starttime; /* if (0 == version) { // old version if (curtime < 2000) { // Minimal building took less than 2 seconds - try to build more if (curtime > 0) { int dynmaxlevel = (int) (2000 / curtime); if (dynmaxlevel < maxlevel) { maxlevel = dynmaxlevel; } } if (maxlevel > 1) { buildlevel = maxlevel; progress = 20; threshold = current_threshold; // % window.setProgress(progress, "Initializing call tree"); dn = CT_BuildTree(calltree, buildlevel, threshold, ID_to_expand); System.out.println("CallTree step 2a time: " + (System.currentTimeMillis() - t) + " ms buildlevel = " + buildlevel); // DEBUG t = System.currentTimeMillis(); } } } // end of old version */ progress = 80; window .getSystemProgressPanel() .setProgress(progress, AnLocale.getString("Expanding call tree")); if (0 == version) { // old version // Expand Call Tree int expandlevel = 1; // min tree depth CT_TreeNode n = CT_ExpandTree(calltree, tnTotal, expandlevel, threshold, ID_to_expand); curtime = System.currentTimeMillis() - starttime; if (curtime < 5000) { // Total time is less than 5 seconds - try to expand more long expt = System.currentTimeMillis() - t; expandlevel = 30; // 20; // default tree depth if (expt > 0) { int dynmaxlevel = (int) (2000 / expt); if (dynmaxlevel < expandlevel) { expandlevel = dynmaxlevel; } } if (expandlevel > 1) { n = CT_ExpandTree(calltree, tnTotal, expandlevel, threshold, ID_to_expand); } } System.out.println( "CallTree step 3a time: " + (System.currentTimeMillis() - t) + " ms expandlevel = " + expandlevel); // DEBUG t = System.currentTimeMillis(); if (null == n) { if (null != dn) { progress = 90; window .getSystemProgressPanel() .setProgress(progress, AnLocale.getString("Expanding call tree")); expandlevel = dn.getDepth(); // adjusted tree depth CT_ExpandTree(calltree, dn, expandlevel, threshold, ID_to_expand); System.out.println( "CallTree step 4a time: " + (System.currentTimeMillis() - t) + " ms"); // DEBUG t = System.currentTimeMillis(); final int row = findFirst(ID_to_expand); AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { long t = System.currentTimeMillis(); calltree.setSelectionRow(row); showSelectedRow(row); System.out.println( "CallTree step 5a time: " + (System.currentTimeMillis() - t) + " ms"); // DEBUG t = System.currentTimeMillis(); } }); } } } // end of old version CT_TreeNode n = null; if (ID_to_expand > 0) { // Selected object final long[] cstack = CT_FindCallStackForID(ID_to_expand); // IPC if ((cstack != null) && (cstack.length > 0)) { long id = cstack[cstack.length - 1]; n = CT_ExpandBranch( calltree, tnTotal, cstack.length + 1 /*level*/, 0 /*no threshold*/, id, cstack); } } if (null == n) { // fall back to the old code int level = 100; // some big value CT_DynamicExpandCallTree( /*JTree tree,*/ dn, level, threshold, ID_to_expand, starttime, progress); } CT_UpdateTitle(); // TEMPORARY progress = 100; window.getSystemProgressPanel().setProgress(100, AnLocale.getString("Expanding call tree")); } else if (!updated) { // need update int minlevel = 1; // min tree depth int maxlevel = 5; // tree depth int threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % ID_to_expand = sel_func; sort_col = window.getSettings().getMetricsSetting().getSortColumnByDType(DSP_CallTree); DefaultMutableTreeNode dn = CT_RebuildTree(minlevel, threshold, ID_to_expand); // System.out.println("CallTree step 1b time: " + (System.currentTimeMillis() - t) + " ms // minlevel = " + minlevel); // DEBUG t = System.currentTimeMillis(); long curtime = System.currentTimeMillis() - starttime; if (0 == version) { // old version if (t < 2000) { // Minimal building took less than 2 seconds - try to build more if (curtime > 0) { int dynmaxlevel = (int) (2000 / curtime); if (dynmaxlevel < maxlevel) { maxlevel = dynmaxlevel; } } if (maxlevel > 0) { // progress = 20; threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % // window.setProgress(progress, "Initializing call tree"); dn = CT_RebuildTree(maxlevel, threshold, ID_to_expand); System.out.println( "CallTree step 2b time: " + (System.currentTimeMillis() - t) + " ms maxlevel = " + maxlevel); // DEBUG t = System.currentTimeMillis(); } } CT_TreeNode n = CT_ExpandTree(calltree, dn, maxlevel, threshold, ID_to_expand); System.out.println( "CallTree step 3b time: " + (System.currentTimeMillis() - t) + " ms"); // DEBUG t = System.currentTimeMillis(); final int row = findFirst(ID_to_expand); System.out.println( "CallTree step 4b time: " + (System.currentTimeMillis() - t) + " ms"); // DEBUG t = System.currentTimeMillis(); AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { long t = System.currentTimeMillis(); calltree.setSelectionRow(row); showSelectedRow(row); System.out.println( "CallTree step 5b time: " + (System.currentTimeMillis() - t) + " ms"); // DEBUG t = System.currentTimeMillis(); } }); } // end of old version CT_TreeNode n = null; if (ID_to_expand > 0) { // Selected object final long[] cstack = CT_FindCallStackForID(ID_to_expand); if ((cstack != null) && (cstack.length > 0)) { long id = cstack[cstack.length - 1]; n = CT_ExpandBranch( calltree, tnTotal, cstack.length + 1 /*level*/, 0 /*no threshold*/, id, cstack); } } if (null == n) { // fall back to the old code int level = 100; // some big value CT_DynamicExpandCallTree( /*JTree tree,*/ dn, level, threshold, ID_to_expand, starttime, progress); } CT_UpdateTitle(); // TEMPORARY } available_metrics = window.getSettings().getMetricsSetting().getMetricListByMType(MetricsSetting.MET_CALL_AGR); window.getSystemProgressPanel().setProgress(0, ""); // Update selection? // ... computed = true; updated = true; // System.out.println("CallTree doCompute time: " + (System.currentTimeMillis() - starttime) + " // ms"); // DEBUG } /* * Experimental code to localize performance and responsiveness issues */ private int CT_DynamicExpandCallTree( /*JTree tree,*/ DefaultMutableTreeNode dn, int level, int threshold, long ID_to_expand, long starttime, int progress) { // Expand Call Tree int expandlevel = 1; // min tree depth CT_TreeNode n = CT_ExpandTree(calltree, tnTotal, expandlevel, threshold, ID_to_expand); long t = System.currentTimeMillis(); long curtime = System.currentTimeMillis() - starttime; if (curtime < 5000) { // Total time is less than 5 seconds - try to expand more long expt = System.currentTimeMillis() - t; expandlevel = level; // 20; // default tree depth if (expt > 0) { int dynmaxlevel = (int) (2000 / expt); if (dynmaxlevel < expandlevel) { expandlevel = dynmaxlevel; } } if (expandlevel > 1) { n = CT_ExpandTree(calltree, tnTotal, expandlevel, threshold, ID_to_expand); } } // System.out.println("CallTree step 3a time: " + (System.currentTimeMillis() - t) + " ms // expandlevel = " + expandlevel); // DEBUG t = System.currentTimeMillis(); if (null == n) { if (null != dn) { progress = 90; window .getSystemProgressPanel() .setProgress(progress, AnLocale.getString("Expanding call tree")); expandlevel = dn.getDepth(); // adjusted tree depth CT_ExpandTree(calltree, dn, expandlevel, threshold, ID_to_expand); // System.out.println("CallTree step 4a time: " + (System.currentTimeMillis() - t) + " ms"); // // DEBUG t = System.currentTimeMillis(); final int row = findFirst(ID_to_expand); AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { long t = System.currentTimeMillis(); calltree.setSelectionRow(row); showSelectedRow(row); // System.out.println("CallTree step 5a time: " + (System.currentTimeMillis() - t) + // " ms"); // DEBUG t = System.currentTimeMillis(); } }); } } return progress; } @Override protected boolean supportsFindText() { return true; } /** * Find a tree node that contains the specified string * * @param str * @param forward Direction: true - forward, false - backward * @return row */ @Override public int find(final String str, final boolean forward, boolean caseSensitive) { final boolean do_selection = true; int sel_row = -1; long id = -1; boolean wrap_around = true; return (find(str, forward, id, sel_row, wrap_around, do_selection, caseSensitive)); } /** * Find a tree node that contains the specified ID * * @param id * @param sel_row * @param forward * @param wrap_around * @return row */ private int find_not_used( long id, int sel_row, final boolean forward, final boolean wrap_around, boolean caseSensitive) { final boolean do_selection = true; final String str = null; return (find(str, forward, id, sel_row, wrap_around, do_selection, caseSensitive)); } /** * Find a tree node that contains the specified ID * * @param id * @param sel_row * @return row */ private int find(long id, int sel_row, final boolean do_selection, boolean caseSensitive) { final boolean forward = true; final boolean wrap_around = true; final String str = null; // Expand all branches that contain this id CT_ExpandAllCallStacksForID(id); // Update selected row sel_row = calltree.getMaxSelectionRow(); return (find(str, forward, id, sel_row, wrap_around, do_selection, caseSensitive)); } /** * Find a tree node that contains the specified string or specified ID * * @param str * @param forward * @param sel_row * @param id * @param wrap_around * @return row */ private int find( String str, final boolean forward, long id, int sel_row, final boolean wrap_around, final boolean do_selection, boolean caseSensitive) { final JTree t = calltree; int found_row = -1; int last_found_row = -1; int row = 0; int selected_row = t.getMaxSelectionRow(); if (sel_row >= 0) { selected_row = sel_row; } CT_TreeNode total = tnTotal; if (total == null) { return found_row; } if (!caseSensitive && null != str) { str = str.toLowerCase(); } CT_TreeNode ctn = total; CT_TreeNode found_node = ctn; Enumeration num = ctn.depthFirstEnumeration(); // ctn.breadthFirstEnumeration(); while (num.hasMoreElements()) { ctn = (CT_TreeNode) num.nextElement(); TreePath path = new TreePath(ctn.getPath()); row = t.getRowForPath(path); if ((row == selected_row) || (row < 0) /* not expanded */) { continue; } if (!wrap_around) { // Skip these checks for "Wrap around" if (row < selected_row) { if (forward) { continue; } } else { if (!forward) { continue; } } } boolean found = false; if (null != str) { // Compare strings String text = ctn.getUserObject().toString(); if (!caseSensitive) { text = text.toLowerCase(); } if (text.contains(str)) { found = true; } } else { // Compare IDs if (ctn.ID == id) { found_node = ctn; found = true; } } if (found) { if (wrap_around) { if (found_row < 0) { // nothing found yet found_row = row; } } if (!forward) { if ((row > last_found_row) || (last_found_row == -1)) { if (row < selected_row) { // for "Wrap around" last_found_row = row; // System.out.println("Found prev: "+ctn.getUserObject().toString()+" ID="+ctn.ID); } } if (wrap_around) { if (found_row < row) { found_row = row; } } } else { // forward if ((row < last_found_row) || (last_found_row == -1)) { if (row > selected_row) { // for "Wrap around" last_found_row = row; } } if (wrap_around) { if (found_row > row) { found_row = row; } } } } } if (last_found_row >= 0) { found_row = last_found_row; } if (do_selection) { // select the row if (found_row >= 0) { final int select_row = found_row; AnUtility.dispatchOnSwingThread( new Runnable() { // @Override public void run() { t.setSelectionRow(select_row); showSelectedRow(select_row); } }); // Set Selected Object and update Summary final long ID = found_node.ID; AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { ct_callstack.setSelectedObject(ID); window.getSelectionManager().updateSelection(); } }, "call tree selection"); } } return found_row; } /** * Find the first tree node that contains the specified ID * * @param id * @param do_selection * @return row */ private int findFirst(long id) { final JTree t = calltree; int found_row = -1; int row = 0; CT_TreeNode total = tnTotal; if (total == null) { return found_row; } CT_TreeNode ctn = total; Enumeration num = ctn.depthFirstEnumeration(); while (num.hasMoreElements()) { ctn = (CT_TreeNode) num.nextElement(); TreePath path = new TreePath(ctn.getPath()); row = t.getRowForPath(path); if ((row < 0) /* not expanded */) { continue; } if (ctn.ID == id) { found_row = row; break; } } return found_row; } /** Show selected row via scrolling up or down Note: use AWT Thread to call this method */ public void showSelectedRow(int row) { final Rectangle cellRect, visRect; if (row < 0) { return; } cellRect = calltree.getRowBounds(row); visRect = calltree.getVisibleRect(); // if (cellRect == null) { // return; // } // if (visRect == null) { // return; // } if (visRect.x + visRect.width > cellRect.x) { // Visible area is wide enough to show the object cellRect.x = visRect.x; } // if current view doesn't include selected row, scroll if (!visRect.contains(cellRect)) { // calculate middle based on selected row // being below or above current visible rows if (visRect.y < cellRect.y) { cellRect.y += visRect.height / 2; } else { cellRect.y -= visRect.height / 2; } calltree.scrollRectToVisible(cellRect); } // Set row selection if (calltree.getMaxSelectionRow() != row) { calltree.setSelectionRow(row); } } /** * Sorting is not allowed in the Call Tree * * @param index */ public void sort(final int index) { // No sorting } Object[][] MaximumValues = null; // Process the raw data from mixed Primary/Object to pure Object array. // Creates and updates MaximumValues. protected Object[][] localProcessData(final Object[] raw_data) { int i; AnAddress aa = new AnAddress(0); AnDouble ad = new AnDouble(0.0); AnInteger ai = new AnInteger(0); AnLong al = new AnLong(0); AnString as = new AnString(""); final int nc = raw_data.length - 1; final Object[][] data = new Object[nc][]; MaximumValues = new Object[2][nc]; for (i = 0; i < nc; i++) { if (raw_data[i] instanceof double[]) { data[i] = AnDouble.toArray((double[]) raw_data[i]); MaximumValues[1][i] = ad; } else if (raw_data[i] instanceof int[]) { data[i] = AnInteger.toArray((int[]) raw_data[i]); MaximumValues[1][i] = ai; } else if (raw_data[i] instanceof long[]) { if ((((long[]) raw_data[i]).length == 0) || !AnAddress.isAddress(((long[]) raw_data[i])[0])) { data[i] = AnLong.toArray((long[]) raw_data[i]); MaximumValues[1][i] = al; } else { data[i] = AnAddress.toArray((long[]) raw_data[i]); MaximumValues[1][i] = aa; } } else { data[i] = (Object[]) raw_data[i]; MaximumValues[1][i] = as; } updateTotalMax(data[i], i); } for (i = 0; i < nc; i++) { // make sure there are no null elements in MaximumValues[1] if (MaximumValues[1][i] == null) { MaximumValues[1][i] = ad; } } return data; } /* * Updates MaximumValues (Total and Max values) * Note: Total is not used, so only Maximum is updated. */ void updateTotalMax(Object[] table_column, int index) { for (int i = 0; i < table_column.length; i++) { if (MaximumValues[1][index] == null) { MaximumValues[1][index] = table_column[i]; continue; } int j = MaximumValues[1][index].toString().length(); int k = table_column[i].toString().length(); if (j < k) { MaximumValues[1][index] = table_column[i]; } } } /* * Returns MaximumValues (Total and Max values), calculated by processData() */ Object[] getTotalMax() { return MaximumValues; } // Create the filter clause based on the selected objects public String createFilterClause(String action) { long ID = -1; long[] cstack = null; String clause = null; // int selected = calltree.getLeadSelectionRow(); TreePath tp = calltree.getSelectionPath(); DefaultMutableTreeNode dn; if ((tp != null) && (tp.getPathCount() > 1)) { dn = (DefaultMutableTreeNode) tp.getLastPathComponent(); if (dn instanceof CT_TreeNode) { ID = ((CT_TreeNode) dn).ID; cstack = ((CT_TreeNode) dn).stack; } } if (ID >= 0) { clause = "(" + ID + ")"; String stack = "USTACK"; if (window.getSettings().getViewModeSetting().get() == ViewModeSetting.ViewMode.MACHINE) { stack = "MSTACK"; } if (window.getSettings().getViewModeSetting().get() == ViewModeSetting.ViewMode.EXPERT) { stack = "XSTACK"; } if (action.equals(STR_ACTION_REMOVE_ALL_FILTERS)) { clause = "1"; } if (action.equals(FILTER_NAME_ACTION_NAME)) { clause = window.getObjNameV2(ID); clause = "(FNAME(\".*" + clause + ".*\") SOME IN " + stack + ")"; } if (action.equals(FILTER_SELECTED_FUNCTION_ACTION_NAME)) { clause = "(" + clause + " IN " + stack + ")"; } if (action.equals(FILTER_SELECTED_LEAF_ACTION_NAME)) { // clause = "(LEAF IN " + clause + ")"; clause = "((" + stack + "+0) IN " + clause + ")"; } if (action.equals(FILTER_SELECTED_BRANCH_ACTION_NAME)) { if ((cstack != null) && (cstack.length > 0)) { clause = "("; for (int i = 0; ; ) { clause = clause + cstack[i]; if (++i < cstack.length) { clause = clause + ","; } else { clause = clause + ")"; break; } } clause = "(" + clause + " ORDERED IN " + stack + ")"; } } if (action.equals(FILTER_NOT_SELECTED_BRANCH_ACTION_NAME)) { if ((cstack != null) && (cstack.length > 0)) { clause = "("; for (int i = 0; ; ) { clause = clause + cstack[i]; if (++i < cstack.length) { clause = clause + ","; } else { clause = clause + ")"; break; } } clause = "(!(" + clause + " ORDERED IN " + stack + "))"; } } } return clause; } // CallTree tree private class CT_Tree extends JTree { private CT_TreeRenderer renderer; public CT_Tree() { super(); init(); } public CT_Tree(TreeNode root) { super(root); init(); } private void init() { AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Call Tree")); if (AnEnvironment.isLFNimbus()) { setBackground(AnEnvironment.NIMBUS_TREE_BACKGROUND); } ((DefaultTreeCellRenderer) getCellRenderer()).setLeafIcon(null); ((DefaultTreeCellRenderer) getCellRenderer()).setClosedIcon(null); ((DefaultTreeCellRenderer) getCellRenderer()).setOpenIcon(null); renderer = new CT_TreeRenderer(); setCellRenderer(renderer); } // Call Tree cell renderer private final class CT_TreeRenderer extends DefaultTreeCellRenderer { public Component getTreeCellRendererComponent( final JTree tree, Object value, final boolean sel, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) { final Object object; Icon icon = null; setLeafIcon(null); setClosedIcon(null); setOpenIcon(null); if (value instanceof DefaultMutableTreeNode) { object = value; // NM ((DefaultMutableTreeNode) value).getUserObject(); if (object instanceof CT_TreeNode) { final CT_TreeNode item = (CT_TreeNode) object; value = item.getText(); if (show_colorbars) { icon = item.getIcon(); } if (show_tooltips) { setToolTipText(metricName + value); } } else if (object instanceof JComponent) { // FINDBUGS: reports this is always false. Is there a JComponent that is a // DefaultMutableTreeNode? return (Component) object; } } super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); if (icon != null) { setIcon(icon); } return this; } } } // CallTree icons private static ImageIcon p_icon[] = new ImageIcon[101]; private static void cleanMetricIcons() { for (int i = 0; i < p_icon.length; i++) { p_icon[i] = null; } } // CallTree node private class CT_TreeNode extends DefaultMutableTreeNode { private String sname; private long ID; private long[] stack; private double inclusive = 0.0; private AnObject incValue; private double exclusive; private int callees; private int inc_percent = 0; private String text = null; private javax.swing.Icon icon = null; public CT_TreeNode(String name, boolean b) { super(name, b); this.sname = name; callees = -1; } // To String public String toString() { return getText(); } // Get text public String getText() { if (null == text) { text = generateTextAndIcon(); } return text; } // Get icon public Icon getIcon() { if (null == icon) { int n = inc_percent; if (n < 1) { return null; } if (n > 100) { n = 100; } if (null == p_icon[n]) { String metric = metricCommandName; int height = 10; // 10 should be replaced with Font height p_icon[n] = getImageIconBar(metric, n, height); } icon = p_icon[n]; } return icon; } /** * Set Inclusive Value * * @param value */ public void setInclusiveValue(AnObject value) { this.incValue = value; if (null != incValue) { inclusive = incValue.doubleValue(); } } // Set Exclusive Value public void setExclusiveValue(double value) { exclusive = value; } // Set Name public void setName(String name) { sname = name; } public String generateTextAndIcon() { double adjustment = 0.0005; double inclusive_value = inclusive; if (inclusive_value > 0.0) { inclusive_value = inclusive_value + adjustment; } // Code to generate visible node name String m = ""; if (convertHWCtoTime) { inclusive_value = inclusive_value * clock_frequency; // "clock_frequency" is 1/frequency } if (show_inclusive) { m = " " + incValue.toString(); } if (show_percentage) { int percentage = 0; if (tnTotal != null) { double total_incValue = tnTotal.incValue.doubleValue(); if (total_incValue > 0.) { if (total_incValue != inclusive) { double d = inclusive * 100 / total_incValue; percentage = (int) (d + 0.49); } else { percentage = 100; } m += " (" + percentage + "%) "; } } inc_percent = percentage; // To pick appropriate icon } String s = " " + m + " " + sname; // + " (ID=" + ID + ")"; return s; } } /* * Add a node to the Call Tree */ private void CT_AddTreeNode(final DefaultMutableTreeNode parent, final CT_TreeNode tn) { AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { parent.add(tn); // PERFORMANCE: 30% real time, call from CT_BuildSubTree } }); } /* * Add nodes to the Call Tree */ private void CT_AddTreeNodes(final CT_TreeNode parent, final CT_TreeNode[] tns) { AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { if (parent.callees < 0) { parent.callees = 0; } parent.callees += tns.length; for (int i = 0; i < tns.length; i++) { parent.add(tns[i]); // PERFORMANCE: ?% real time, call from CT_BuildSubTree } } }); } /* * Remove a node from the Call Tree */ private void CT_RemoveTreeNode_notused(final DefaultMutableTreeNode parent, final int nodeIndex) { AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { parent.remove(nodeIndex); } }); } /** Collapse all tree nodes */ public void CT_CollapseTree() { final JTree t = calltree; AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { int row = t.getMaxSelectionRow(); if (row < 1) { row = 1; // Do not collapse root node } for (; row >= 1; row--) { t.collapseRow(row); } } }); } /** Collapse selected node */ public void CT_CollapseNode() { final JTree t = calltree; AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { int row = t.getMaxSelectionRow(); if (row < 1) { row = 1; // Do not collapse root node } t.collapseRow(row); } }); } /** Build the Call Tree */ public DefaultMutableTreeNode CT_BuildTree( JTree tree, int maxlevel, int threshold, long ID_to_expand) { Object[] raw_data; CT_TreeNode tn; DefaultMutableTreeNode anode; DefaultMutableTreeNode node_to_expand = null; Vector nextNodes; Vector prevNodes; String nodeName; double minValue = 0.0; AnObject[] incMetrics = null; // long t = System.currentTimeMillis(); // DEBUG anode = rootnode; if (anode.getChildCount() > 0) { // Collapse all tree nodes CT_CollapseTree(/*calltree*/ ); // Reset selection calltree.clearSelection(); } // Step 1: add <Total> // get call stack with one element: <Total> ct_callstack = new CT_CallStack(); raw_data = getCalleeList(null); ct_callstack.append(0); // get callers of <Total> - this is necessary to initialize data long[] cstack = ct_callstack.getIDs(); raw_data = getCallerList(cstack); // to initialize name_col, metric_col and sort_col CT_UpdateTitle(); cstack = ct_callstack.getIDs(); String[] names = ct_callstack.getNames(); nodeName = names[0]; raw_data = getFuncItemData(cstack); // getFuncItemData() creates func_data if (func_data[metric_col] instanceof AnObject[]) { incMetrics = (AnObject[]) func_data[metric_col]; show_inclusive = true; show_percentage = true; if (incMetrics instanceof AnAddress[]) { show_percentage = false; } // If sort metric is IPC or CPI - don't show percentage if (null != metricName) { String mn1 = "Instructions Per Cycle"; String mn2 = AnLocale.getString("Attributed ") + mn1; if (metricName.equals(mn1) || metricName.equals(mn2)) { show_percentage = false; } if (false != show_percentage) { mn1 = "Cycles Per Instruction"; mn2 = AnLocale.getString("Attributed ") + mn1; if (metricName.equals(mn1) || metricName.equals(mn2)) { show_percentage = false; } } } } else { // Names only. Don't show metric value and percentage show_inclusive = false; show_percentage = false; } // build the node as CT_TreeNode. We need a synchronization here if (tnTotal == null) { tnTotal = new CT_TreeNode(nodeName, true); } tnTotal.ID = cstack[0]; tnTotal.stack = cstack; if ((incMetrics != null) && (incMetrics.length > 0) && (incMetrics[0] != null)) { tnTotal.setInclusiveValue(incMetrics[0]); } // System.out.println("DEBUG: CallTreeDisp.CT_BuildTree: tnTotal.ID=" + tnTotal.ID); // Remove all children // tnTotal.removeAllChildren(); if (tnTotal.getParent() == null) { CT_AddTreeNode(rootnode, tnTotal); // Should be here only once! } if (node_to_expand == null) { if (tnTotal.ID == ID_to_expand) { node_to_expand = tnTotal; } } prevNodes = new Vector(1); prevNodes.add(tnTotal); int nrows = prevNodes.size(); int progress = 1; window .getSystemProgressPanel() .setProgress(progress, AnLocale.getString("Initializing call tree")); // Step 2: add callees to tnTotal node nextNodes = new Vector(0); // Next level nodes int level = 1; for (int row = 0; /* row < nrows */ ; ) { // We don't know yet how many rows this tree will have CT_TreeNode dn = (CT_TreeNode) prevNodes.elementAt(row); CT_TreeNode[] tns = getChildrenOfTreeNode(dn, false); if (++progress > 98) { progress = 98; } else { window .getSystemProgressPanel() .setProgress(progress, AnLocale.getString("Initializing call tree")); } // add children for (int i = 0; i < tns.length; i++) { tn = tns[i]; // Add this node to the Call Tree // NM ((DefaultMutableTreeNode) prevNodes.elementAt(row)).add(tn); // NM Use AWT-thread to add nodes final DefaultMutableTreeNode parent; final CT_TreeNode child = tn; parent = ((DefaultMutableTreeNode) prevNodes.elementAt(row)); CT_AddTreeNode(parent, child); if ((minValue > 0.0) && (tn.inclusive < minValue)) { // TEMPORARY // Do not expand this node - // its value is less than threshold // try to add its children addChildren(tn); } else { // Save for the next level nextNodes.add(tn); } if (ID_to_expand > 0) { if (node_to_expand == null) { // Not found yet if (tn.ID == ID_to_expand) { node_to_expand = tn; } } } } if (++row == nrows) { // this level is done, go one level deeper // System.out.println("DEBUG: CallTreeDisp.CT_BuildTree: level=" + level + " is done."); if (++level > maxlevel) { // We are done, the tree is built deep enough // NM Add fake child to each "leaf" node for future for (int i = 0; i < nextNodes.size(); i++) { tn = (CT_TreeNode) nextNodes.elementAt(i); // try to add its children addChildren(tn); } break; } nrows = nextNodes.size(); if (nrows == 0) { // We are done, the tree is built break; } prevNodes = nextNodes; nextNodes = new Vector(0); // Next level nodes row = 0; } cstack = (long[]) ((CT_TreeNode) prevNodes.elementAt(row)).stack; ct_callstack.setIDs(cstack); } // t = System.currentTimeMillis() - t; // System.out.println("DEBUG: CallTreeDisp.CT_BuildTree(maxlevel=" + maxlevel + "): time=" + t + // " mls."); // Finally add all nodes to the tree // Probably we have to use EventDispatchThread there // ((DefaultMutableTreeNode)tree.getModel().getRoot()).add(tnTotal); window.getSystemProgressPanel().setProgress(99, AnLocale.getString("Initializing call tree")); return node_to_expand; } private void CT_ExpandAllCallStacksForID(long id) { // Expand all branches that contain this id final Vector<long[]> cstacks = CT_FindAllCallStacksForID(id); // IPC if (cstacks != null) { int len = cstacks.size(); for (int i = 0; i < len; i++) { long[] cstack = cstacks.elementAt(i); if ((cstack != null) && (cstack.length > 0)) { CT_ExpandBranch( calltree, tnTotal, cstack.length + 1 /*level*/, 0 /*no threshold*/, -1 /*no select*/, cstack); } } } } /** * Find Call Stack For ID * * @param id * @return stack */ private long[] CT_FindCallStackForID(long id) { if (id <= 0) { return null; } long[] stack = new long[1]; stack[0] = id; long[] cstack = CT_FindCallStackForStackFragment(stack); return cstack; } /** * Find Call Stack For Stack Fragment * * @return stack */ private long[] CT_FindCallStackForStackFragment(long[] stack) { if (null == stack || stack.length <= 0) { return null; } CT_TreeNode total = tnTotal; if (null == total) { return null; } long totalID = total.ID; // build call stack up to <Total> CT_CallStack callstack = new CT_CallStack(); long[] cstack = stack; // new long[1]; callstack.setIDs(cstack); Object[] raw_data = getCallerList(cstack); // IPC, updates ids_callers while ((ids_callers != null) && (ids_callers.length > 0)) { callstack.prepend(0); cstack = callstack.getIDs(); if (cstack[0] == totalID) { break; } raw_data = getCallerList(cstack); // IPC, updates ids_callers } return cstack; } /** * Find All Call Stacks For ID * * @param id * @return Vector */ private Vector<long[]> CT_FindAllCallStacksForID(long id) { // Get all callers long[] stack = new long[1]; stack[0] = id; CT_TreeNode total = tnTotal; if (null == total) { return null; } long totalID = total.ID; Vector v = new Vector(); CT_FindAllCallStacksForStackFragment(stack, totalID, v); return (v); } /** * Find All Call Stacks For StackFragment. Recursive. Updates Vector. * * @param stack * @param total * @param Vector */ private void CT_FindAllCallStacksForStackFragment(long[] stack, long total, Vector<long[]> v) { CT_CallStack callstack = new CT_CallStack(); callstack.setIDs(stack); getCallerList(stack); // IPC. Updates ids_callers if ((ids_callers == null) || (0 >= ids_callers.length)) { return; } long[] callers = new long[ids_callers.length]; // need a copy for (int i = 0; i < ids_callers.length; i++) { callers[i] = ids_callers[i]; } // Get all call stacks for (int i = 0; i < callers.length; i++) { long[] cstack = new long[stack.length + 1]; // a copy + caller cstack[0] = callers[i]; for (int j = 0; j < stack.length; j++) { cstack[j + 1] = stack[j]; } if (total == callers[i]) { v.add(cstack); // Add call stack continue; } CT_FindAllCallStacksForStackFragment(cstack, total, v); } return; } /* * Rebuild the Call Tree */ public DefaultMutableTreeNode CT_RebuildTree(int maxlevel, int threshold, long ID_to_expand) { Object[] raw_data; CT_TreeNode tn; DefaultMutableTreeNode anode; DefaultMutableTreeNode node_to_expand = null; Vector nextNodes; Vector prevNodes; // double minValue = 0.0; AnObject[] incMetrics = null; // long t = System.currentTimeMillis(); // DEBUG // Initialize name_col, metric_col and sort_col if (ct_callstack == null) { ct_callstack = new CT_CallStack(); } else { ct_callstack.reset(); } long[] cstack = ct_callstack.getIDs(); raw_data = getCallerList(cstack); if ((rootnode == null) || (tnTotal == null)) { return node_to_expand; // The tree is not initialized yet } CT_UpdateTitle(); anode = rootnode; if (anode.getChildCount() > 0) { // Collapse all tree nodes // CT_CollapseTree(); // Reset selection // calltree.clearSelection(); } // Step 1: update <Total> cstack = new long[1]; cstack[0] = tnTotal.ID; /* raw_data = */ getFuncItemData(cstack); // getFuncItemData() creates func_data if (func_data[metric_col] instanceof AnObject[]) { incMetrics = (AnObject[]) func_data[metric_col]; show_inclusive = true; show_percentage = true; if (incMetrics instanceof AnAddress[]) { show_percentage = false; } // If sort metric is IPC or CPI - don't show percentage if (null != metricName) { String mn1 = "Instructions Per Cycle"; String mn2 = AnLocale.getString("Attributed ") + mn1; if (metricName.equals(mn1) || metricName.equals(mn2)) { show_percentage = false; } if (false != show_percentage) { mn1 = "Cycles Per Instruction"; mn2 = AnLocale.getString("Attributed ") + mn1; if (metricName.equals(mn1) || metricName.equals(mn2)) { show_percentage = false; } } } } else { // Names only. Don't show metric value and percentage show_inclusive = false; show_percentage = false; } // tnTotal.ID = cstack[0]; // tnTotal.stack = cstack; if ((incMetrics != null) && (incMetrics.length > 0) && (incMetrics[0] != null)) { tnTotal.setInclusiveValue(incMetrics[0]); } // Step 2: update tnTotal children prevNodes = new Vector(1); prevNodes.add(tnTotal); int nrows = prevNodes.size(); nextNodes = new Vector(0); // Next level nodes int level = 1; for (int row = 0; /* row < nrows */ ; ) { { // new version CT_TreeNode pn = (CT_TreeNode) prevNodes.elementAt(row); CT_TreeNode[] tns = getChildrenOfTreeNode(pn, false); // update children CT_TreeNode child = null; int k = pn.getChildCount(); for (int i = 0; i < k; i++) { boolean found = false; child = (CT_TreeNode) pn.getChildAt(i); for (int j = 0; j < tns.length; j++) { tn = tns[j]; if (child.ID == tn.ID) { child.setInclusiveValue(tn.incValue); child.inclusive = tn.inclusive; child.exclusive = tn.exclusive; child.sname = tn.sname; child.stack = tn.stack; found = true; break; } } nextNodes.add(child); if (!found) { // Child is filtered out. Ideally we shall remove it. child.inclusive = 0.0; // TEMPORARY child.exclusive = 0.0; // TEMPORARY continue; } if (ID_to_expand > 0) { if (node_to_expand == null) { if (child.ID == ID_to_expand) { node_to_expand = child; } } } } } // end of new version if (++row == nrows) { // this level is done, go one level deeper // System.out.println("DEBUG: CallTreeDisp.CT_RebuildTree: level=" + level + " is done."); if (++level > maxlevel) { break; } nrows = nextNodes.size(); if (nrows == 0) { // We are done, the tree is rebuilt break; } prevNodes = nextNodes; nextNodes = new Vector(0); // Next level nodes row = 0; } cstack = (long[]) ((CT_TreeNode) prevNodes.elementAt(row)).stack; ct_callstack.setIDs(cstack); } // t = System.currentTimeMillis() - t; // System.out.println("DEBUG: CallTreeDisp.CT_BuildTree(maxlevel=" + maxlevel + "): time=" + t + // " mls."); return node_to_expand; } /* * Build a subtree of the Call Tree */ public void CT_BuildSubTree(DefaultMutableTreeNode start_node, int maxlevel) { long[] cstack; CT_TreeNode tn; CT_TreeNode[] tns; Vector<CT_TreeNode> nextNodes; Vector<CT_TreeNode> prevNodes; if (!(start_node instanceof CT_TreeNode)) { // root node return; } CT_TreeNode sn = (CT_TreeNode) start_node; // long t = System.currentTimeMillis(); // DEBUG // Step 1: add start_node prevNodes = new Vector<CT_TreeNode>(); prevNodes.add(sn); int nrows = prevNodes.size(); cstack = (long[]) sn.stack; ct_callstack.setIDs(cstack); // Step 2: add callees to start_node node nextNodes = new Vector<CT_TreeNode>(); // Next level nodes int level = 1; boolean already_has_children; for (int row = 0; /* row < nrows */ ; ) { CT_TreeNode dn = prevNodes.elementAt(row); // addChildren(dn); // To make sure this node is initialized int len = dn.getChildCount(); already_has_children = false; if (len == 0) { // try to get children tns = getChildrenOfTreeNode(dn, false); len = tns.length; } else { already_has_children = true; tns = new CT_TreeNode[len]; for (int i = 0; i < len; i++) { tns[i] = (CT_TreeNode) dn.getChildAt(i); } } // add children if ((!already_has_children) && (len > 0)) { CT_AddTreeNodes(dn, tns); // PERFORMANCE: ?% Total Thread Time } for (int i = 0; i < len; i++) { tn = tns[i]; // Add this node to the Call Tree // ((DefaultMutableTreeNode)prevNodes.elementAt(row)).add(tn); // if (!already_has_children) { // //NM dn.add(tn); // //NM Use AWT-thread to add nodes // final DefaultMutableTreeNode parent = dn; // final CT_TreeNode child = tn; // CT_AddTreeNode(parent, child); // PERFORMANCE: 60% Total Thread Time // } // Save for the next level nextNodes.add(tn); } if (++row == nrows) { // this level is done, go one level deeper // System.out.println("DEBUG: CallTreeDisp.CT_BuildTree: level=" + level + " is done."); if (++level > maxlevel) { // We are done, the tree is built deep enough break; } nrows = nextNodes.size(); if (nrows == 0) { // We are done, the tree is built break; } prevNodes = nextNodes; nextNodes = new Vector<CT_TreeNode>(); // Next level nodes row = 0; } cstack = (long[]) ((CT_TreeNode) prevNodes.elementAt(row)).stack; ct_callstack.setIDs(cstack); } // t = System.currentTimeMillis() - t; // System.out.println("DEBUG: CallTreeDisp.CT_BuildSubTree(maxlevel=" + maxlevel + "): time=" + // t + " mls."); } /* * Get Children */ private CT_TreeNode[] getChildrenOfTreeNode(CT_TreeNode dn, boolean addFakeChild) { CT_TreeNode[] children = new CT_TreeNode[0]; long[] cstack = dn.stack; long ID = -1; AnObject[] incMetrics = null; Object[] raw_data = getCalleeList(cstack); // IPC if ((callee_data != null) && (callee_data.length > 0)) { if (callee_data[metric_col] instanceof AnObject[]) { incMetrics = (AnObject[]) callee_data[metric_col]; } int len = callee_data[0].length; children = new CT_TreeNode[len]; for (int i = 0; i < len; i++) { // Get my ID if (raw_data[raw_data.length - 1] instanceof long[]) { ID = ((long[]) raw_data[raw_data.length - 1])[i]; } // Create my stack long[] my_stack = new long[cstack.length + 1]; my_stack[cstack.length] = ID; for (int k = 0; k < cstack.length; k++) { my_stack[k] = cstack[k]; } // build the node as CT_TreeNode String nodeName = (String) callee_data[name_col][i]; CT_TreeNode tn = new CT_TreeNode(nodeName, true); tn.ID = ID; tn.stack = my_stack; if (incMetrics != null && incMetrics.length > i) { tn.setInclusiveValue(incMetrics[i]); } tn.exclusive = 0.0; // TEMPORARY // Add this node to the Call Tree children[i] = tn; } dn.callees = callee_data.length; } else { dn.callees = 0; } return children; } /* * Expand the Call Tree */ public CT_TreeNode CT_ExpandTree( JTree tree, DefaultMutableTreeNode dn, int level, int threshold, long id) { if (dn == null) { dn = tnTotal; } long[] cstack = null; return (CT_ExpandBranch( tree, dn, level, threshold, id, cstack)); // PERFORMANCE: 60% real time, call from CT_ExpandAllBranches } /** * Expand the selected branch of the Call Tree * * @param tree * @param anode - node to expand * @param level * @param threshold * @param id * @return node with specified id */ public CT_TreeNode CT_ExpandBranch( JTree tree, DefaultMutableTreeNode anode, int level, int threshold, final long id, final long[] cstack) { CT_TreeNode select_node = null; if (anode == null) { return select_node; // Branch is not specified } if (anode instanceof CT_TreeNode) { if (id >= 0) { if (((CT_TreeNode) anode).ID == id) { select_node = (CT_TreeNode) anode; } } } int csindex = 0; int K = 1000; // will be increased in the loop if necessary CT_TreeNode total = tnTotal; if (total == null) { return null; // nothing to expand } double minValue = (total.inclusive / 100.0) * threshold; // TEMPORARY // int progress = 0; // window.setProgress(progress, "Expanding branch"); for (int i = 1; ; ) { CT_BuildSubTree(anode, 2); // NM Need 2 levels deep if (anode.getChildCount() == 0) { // try to add its children addChildren(anode); // NM Not needed anymore? } // if (++progress > 98) { // progress = 98; // } // window.setProgress(progress, "Expanding branch"); if (anode.getChildCount() > 0) { if (cstack != null) { // Find next node csindex++; if (csindex >= cstack.length) { break; // we are done } try { CT_TreeNode tn = (CT_TreeNode) anode.getChildAt(0); int len = anode.getChildCount(); for (int k = 1; k < len; k++) { if (tn.ID == cstack[csindex]) { break; // found } tn = (CT_TreeNode) anode.getChildAt(k); } if (tn.ID == cstack[csindex]) { anode = tn; // Found next node } else { return null; // Should never be here } } catch (Exception e) { // Not a CT_TreeNode in the tree return null; // Should never be here } } else { // Follow top node anode = (DefaultMutableTreeNode) anode.getChildAt(0); } if (level > 0) { if (i >= level) { CT_BuildSubTree(anode, 2); if (anode.getChildCount() == 0) { // try to add its children addChildren(anode); } break; } } if (++i >= K) { // System.out.println("DEBUG: CallTreeDisp.expandBranch(level=" + K + ")"); K += K; } if (anode instanceof CT_TreeNode) { if (id >= 0) { if (((CT_TreeNode) anode).ID == id) { if (null == select_node) { select_node = (CT_TreeNode) anode; } } } double d = ((CT_TreeNode) anode).inclusive; if (d < minValue) { CT_BuildSubTree(anode, 2); if (anode.getChildCount() == 0) { // try to add its children addChildren(anode); } break; } } if (!selected) { // TEMPORARY code to interrupt break; } if (stop_expanding) { // Stop expanding break; } continue; } break; } TreeNode[] pathnodes = anode.getPath(); if (null != select_node) { pathnodes = select_node.getPath(); } TreePath anodepath = new TreePath(pathnodes); if (tree == null) { // old code calltree.expandPath(anodepath); calltree.setSelectionPath(anodepath); } else { // use AWT final JTree t = calltree; final TreePath ap = anodepath; final boolean preserve_select; if (null == select_node) { preserve_select = true; } else { preserve_select = false; } // Use SwingUtilities to update tree AnUtility.dispatchOnSwingThread( new Runnable() { // @Override public void run() { // PERFORMANCE: 60% real time, call from CT_ExpandTree (Expand All Branches) try { skip_build_subtree.set(true); // NM TEMPORARY Protection against infinite loop try { TreePath sp = t.getSelectionPath(); t.expandPath(ap); t.setSelectionPath(ap); // Scroll if necessary if (null != cstack) { // Not a good check, need a special flag for this int select_row = t.getRowForPath(ap); showSelectedRow(select_row); } // Restore selection if necessary if (preserve_select && null != sp) { t.setSelectionPath(sp); } } finally { skip_build_subtree.set(false); // NM TEMPORARY Remove protection } } catch (Exception exc) { System.err.println("CallTreeDisp.CT_ExpandBranch() exception: " + exc); exc.printStackTrace(); } } }); } // window.setProgress(100, "Expanding branch"); return select_node; } /** * Expands All Branches * * @param tree * @param anode * @param level * @param threshold * @param id * @return node to select */ public CT_TreeNode CT_ExpandAllBranches( JTree tree, DefaultMutableTreeNode anode, int level, int threshold, long id) { CT_TreeNode select_node = null; CT_TreeNode found_node = null; CT_TreeNode top_level_node; TreePath select_path = null; if (anode == null) { anode = tnTotal; if (anode == null) { return null; } } // int progress = 0; // window.setProgress(progress, "Expanding all branches"); if (id >= 0) { top_level_node = (CT_TreeNode) anode; if (top_level_node.ID == id) { select_node = top_level_node; } } else { // Remember selected path select_path = calltree.getLeadSelectionPath(); } CT_TreeNode total = tnTotal; if (total == null) { return null; // nothing to expand } double minValue = (total.inclusive / 100.0) * threshold; // TEMPORARY int max = calltree.getRowCount(); skip_update_summary = true; // Optimization // Experiment: first, expand hottest branch long[] cstack = null; CT_ExpandBranch(calltree, tnTotal, level, threshold, id, cstack); for (int i = 1; i < max; i++) { if (stop_expanding) { // Stop expanding break; } TreePath tp = calltree.getPathForRow(i); if (!(tp.getLastPathComponent() instanceof CT_TreeNode)) { continue; } CT_TreeNode node = (CT_TreeNode) tp.getLastPathComponent(); double d = node.inclusive; if ((id >= 0) && (select_node == null)) { if (node.ID == id) { select_node = node; } } if (d < minValue) { continue; } if (node.callees < 0) { // try to add its children addChildren(node); } if (node.getChildCount() == 0) { max = calltree.getRowCount(); continue; } int exp_threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % int exp_level = 1; // 1 level long exp_id = -1; if (null == found_node) { exp_id = id; } found_node = CT_ExpandTree(calltree, node, exp_level, exp_threshold, exp_id); // need CT_ExpandNode() max = calltree.getRowCount(); } // End of loop - the tree is expanded skip_update_summary = false; // Restore selected object if (null == select_node) { if (null != select_path) { calltree.setLeadSelectionPath(select_path); int row = calltree.getLeadSelectionRow(); if ((tree.getLastSelectedPathComponent() instanceof CT_TreeNode)) { // Set Selected Object and update Summary CT_TreeNode ctn = (CT_TreeNode) tree.getLastSelectedPathComponent(); final long ID = ctn.ID; AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { ct_callstack.setSelectedObject(ID); window.getSelectionManager().updateSelection(); } }, "call tree selection"); } // calltree.setSelectionRow(row); showSelectedRow(row); } } // window.setProgress(100, "Expanding all branches"); return select_node; } /* * Switch to the Source view */ private void CT_ShowSource() { window.setSelectedView(AnDisplay.DSP_Source); } /* * Switch to the Disassembly view */ private void CT_ShowDisasm() { window.setSelectedView(AnDisplay.DSP_Disassembly); } /** Performs default action for double click */ private void performDefaultAction() { CT_ShowSource(); } // ==================================================== // // Listeneres and event handlers // // ==================================================== // /** * Inner class which listens for expansion events on the tree. When one is received, it will get * the path of the selected node and add sub directory nodes, if any, to it. */ class CallTreeExpansionListener implements TreeExpansionListener { /** Called whenever an item in the tree has been expanded. */ public void treeExpanded(TreeExpansionEvent event) { valueChanged(event); } /** Called whenever an item in the tree has been collapsed. */ public void treeCollapsed(TreeExpansionEvent event) { // valueChanged(event); } public void valueChanged(final TreeExpansionEvent tee) { // NM TEMPORARY Protection against infinite loop: // check that we are expanding a freshly built tree if (skip_build_subtree.get()) { return; } // NM TEMPORARY Cannot use a worker thread - desynchronization with AWT thread: // final boolean use_thread = true; // AnUtility.dispatchOnAWorkerThread(new Runnable() { // @Override // public void run() { // valueChanged(tee, use_thread); // } // }, "CallTree_thread"); // } // // private void valueChanged(TreeExpansionEvent tee, boolean use_thread) { // get the selected tree path TreePath path = tee.getPath(); // check that a path is in fact selected if (path == null) { return; } // get the last node DefaultMutableTreeNode curNode = (DefaultMutableTreeNode) path.getLastPathComponent(); // add children to the selected node if (curNode.getChildCount() == 0) { addChildren(curNode); } for (int i = 0; i < curNode.getChildCount(); i++) { addChildren((DefaultMutableTreeNode) curNode.getChildAt(i)); } } } /** * Inner class which listens for selection events on the tree. When one is received, it will get * the path of the selected node and add sub directory nodes, if any, to it. */ class CallTreeSelectionListener implements TreeSelectionListener { @Override public void valueChanged(final TreeSelectionEvent tse) { // NM TEMPORARY Protection against infinite loop: // check that we are expanding a freshly built tree if (skip_build_subtree.get()) { return; } // NM TEMPORARY Cannot use a worker thread - desynchronization with AWT thread: // final boolean use_thread = true; // AnUtility.dispatchOnAWorkerThread(new Runnable() { // @Override // public void run() { // valueChanged(tse, use_thread); // } // }, "CallTree_thread"); // } // // private void valueChanged(TreeSelectionEvent tse, boolean use_thread) { // get the selected tree path TreePath path = tse.getNewLeadSelectionPath(); // check that a path is in fact selected if (path == null) { return; } // get the selected node DefaultMutableTreeNode curNode = (DefaultMutableTreeNode) path.getLastPathComponent(); // get all the nodes in the selected tree path // Object nodes[] = path.getPath(); if (!(curNode instanceof CT_TreeNode)) { // root node return; } // add children to the selected node if (curNode.getChildCount() == 0) { addChildren(curNode); } if (!skip_update_summary) { // Update Summary final long ID = ((CT_TreeNode) curNode).ID; AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { ct_callstack.setSelectedObject(ID); window.getSelectionManager().updateSelection(); } }, "call tree selection"); } } } /** * Adds the subnodes, if any, of the given path to the given node. * * @param node tree node to add sub directory nodes to */ protected void addChildren(DefaultMutableTreeNode node) { synchronized (CallTreeLock) { if (!(node instanceof CT_TreeNode)) { return; // Not our node } final CT_TreeNode dn = (CT_TreeNode) node; // add sub nodes to given node if (dn != null) { if (dn.callees < 0) { // Not initialized yet // try to get children final CT_TreeNode[] tns = getChildrenOfTreeNode(dn, true); // IPC dn.callees = tns.length; // update internal children counter if (tns.length > 0) { AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { for (int i = 0; i < tns.length; i++) { dn.add(tns[i]); } } }); } } } } } // ==================================================== // // Wrappers for native methods from liber_dbe.so // // ==================================================== // // Get row Table Data private Object[] getTableData( final String mlistStr, final String modeStr, final String typeStr, final String subtypeStr, final long[] cstack) { // long t = System.currentTimeMillis(); AnUtility.checkIPCOnWrongThread(false); Object[] data = window.getTableDataV2(mlistStr, modeStr, typeStr, subtypeStr, cstack); AnUtility.checkIPCOnWrongThread(true); // t = System.currentTimeMillis() - t; // if (t > 100) { // System.out.println("DEBUG: CallTreeDisp.getTableData(" + modeStr + "): time=" + t + " mls."); // } return data; } /** * Get Callee List. Uses IPC call. * * @param cstack * @return list */ private Object[] getCalleeList(final long[] cstack) { Object[] raw_data_with_ids = getTableData(mlistStr, stab_callees, typeStrFunction, subtypeStr, cstack); ids_callees = (long[]) raw_data_with_ids[raw_data_with_ids.length - 1]; Object[] raw_data = new Object[raw_data_with_ids.length]; for (int i = 0; i < raw_data.length; i++) { raw_data[i] = raw_data_with_ids[i]; } raw_data[raw_data.length - 1] = null; callee_data = localProcessData(raw_data); name_col = window.getSettings().getMetricsSetting().getNameColumnIndexByDType(type); if (name_col < 0) { name_col = 0; } if ((callee_data.length > name_col) && (callee_data[name_col] instanceof String[])) { // Ok. } else { // Hack: find name column for (int i = 0; i < callee_data.length; i++) { if (callee_data[i] instanceof String[]) { name_col = i; } } } return raw_data_with_ids; } // Get function item data private Object[] getFuncItemData(final long[] cstack) { Object[] raw_data_with_ids = getTableData(mlistStr, stab_self, typeStrFunction, subtypeStr, cstack); Object[] raw_data = new Object[raw_data_with_ids.length]; for (int i = 0; i < raw_data.length; i++) { raw_data[i] = raw_data_with_ids[i]; } raw_data[raw_data.length - 1] = null; func_data = localProcessData(raw_data); return raw_data_with_ids; } // Get callers data list private Object[] getCallerList(final long[] cstack) { Object[] raw_data_with_ids = getTableData(mlistStr, stab_callers, typeStrFunction, subtypeStr, cstack); ids_callers = (long[]) raw_data_with_ids[raw_data_with_ids.length - 1]; Object[] raw_data = new Object[raw_data_with_ids.length]; for (int i = 0; i < raw_data.length; i++) { raw_data[i] = raw_data_with_ids[i]; } raw_data[raw_data.length - 1] = null; caller_data = localProcessData(raw_data); caller_label = window .getSettings() .getMetricsSetting() .getLabel(caller_data, getTotalMax(), DSP_CallTree, caller); name_col = window.getSettings().getMetricsSetting().getNameColumnIndexByDType(type); if (name_col < 0) { name_col = 0; } if ((caller_data.length > name_col) && (caller_data[name_col] instanceof String[])) { // Ok. } else { for (int i = 0; i < caller_data.length; i++) { if (caller_label[i].getAnMetric().isNameMetric()) { name_col = i; } } } if ((sort_col < 0) || (caller_data.length <= sort_col)) { sort_col = window.getSettings().getMetricsSetting().getSortColumnByDType(DSP_CallTree); if ((sort_col < 0) || (caller_data.length <= sort_col)) { sort_col = 0; // NM: Can we ever get there? Why? } } metric_col = sort_col; if (name_col == metric_col) { if (previous_metric_col >= 0 && (caller_data.length > previous_metric_col)) { metric_col = previous_metric_col; // Set previous metric } } else { previous_metric_col = metric_col; // Save metric column } // Check if cycles should be converted to time convertHWCtoTime = false; if (caller_label.length > metric_col) { if (caller_label[metric_col].getClock() != -1.0) { clock_frequency = caller_label[metric_col].getClock(); convertHWCtoTime = true; } } metricName = caller_label[metric_col].getAnMetric().getName(); if ((null == metricCommandName) || !metricCommandName.equals(caller_label[metric_col].getAnMetric().getComd())) { metricCommandName = caller_label[metric_col].getAnMetric().getComd(); cleanMetricIcons(); } return raw_data_with_ids; } // ==================================================== // // CallStack actions // // ==================================================== // private final class CT_CallStack { long[] ids = new long[0]; String[] names = new String[0]; long selectionTime = 0; // NM String lastFilter = null; long last_ID = -1; AnTable last_selected_table = null; int last_selected_row = -1; public void append(int index) { if ((ids_callees == null) || (index >= ids_callees.length)) { // System.err.println("ERROR: CT_CallStack.append(" + index + ")"); return; } long ID = ids_callees[index]; long[] new_cstack = new long[ids.length + 1]; for (int i = 0; i < ids.length; i++) { new_cstack[i] = ids[i]; } new_cstack[new_cstack.length - 1] = ID; ids = new_cstack; String[] new_ids_names = new String[names.length + 1]; for (int i = 0; i < names.length; i++) { new_ids_names[i] = names[i]; } new_ids_names[names.length] = (String) callee_data[name_col][index]; names = new_ids_names; // Save selection // saveSelection(ID, func_item, ids.length - 1); } public void prepend(int index) { if ((ids_callers == null) || (index >= ids_callers.length)) { // System.err.println("ERROR: CT_CallStack.prepend(" + index + ")"); return; } long ID = ids_callers[index]; // last_ID = ID; long[] new_cstack = new long[ids.length + 1]; new_cstack[0] = ID; for (int i = 1; i < new_cstack.length; i++) { new_cstack[i] = ids[i - 1]; } ids = new_cstack; String[] new_ids_names = new String[names.length + 1]; for (int i = 0; i < names.length; i++) { new_ids_names[i + 1] = names[i]; } new_ids_names[0] = (String) caller_data[name_col][index]; names = new_ids_names; // Save selection // saveSelection(ID, func_item, 0); } public void remove(int index) { if ((index == 0) && (ids.length > 1)) { // Remove top function long[] new_cstack = new long[ids.length - 1]; for (int i = 1; i < ids.length; i++) { new_cstack[i - 1] = ids[i]; } // NM long ID = ids[0]; ids = new_cstack; String[] new_names = new String[names.length - 1]; for (int i = 1; i < names.length; i++) { new_names[i - 1] = names[i]; } names = new_names; // Save selection // NM saveSelection(ID, caller, -1); } if ((index > 0) && (ids.length - 1 == index)) { // Remove bottom function long[] new_cstack = new long[ids.length - 1]; for (int i = 0; i < new_cstack.length; i++) { new_cstack[i] = ids[i]; } // NM long ID = ids[ids.length - 1]; ids = new_cstack; String[] new_names = new String[names.length - 1]; for (int i = 0; i < new_names.length; i++) { new_names[i] = names[i]; } names = new_names; // Save selection // NM saveSelection(ID, callee, -1); } } public void replace(long[] stack, int index) { long ID = stack[index]; long[] new_cstack = new long[1]; new_cstack[0] = ID; ids = new_cstack; // Get name String fname = window.getObjNameV2(ID); String[] new_names = new String[1]; new_names[0] = fname; names = new_names; // Save selection // NM saveSelection(ID, func_item, 0); } public void reset() { ids = new long[0]; names = new String[0]; } public long[] getIDs() { if ((ids == null) || (ids.length == 0)) { // Get ID long ID = window.getSelectedObject().getSelObjV2(typeStrFunction); long[] new_cstack = new long[1]; new_cstack[0] = ID; ids = new_cstack; // Get name String fname = window.getObjNameV2(ID); String[] new_names = new String[1]; new_names[0] = fname; names = new_names; // Get Filter // NM lastFilter = window.getFilterStr(); // Save selection // NM saveSelection(ID, func_item, 0); } return ids; } public void setIDs(long[] stack) { ids = stack; } public String[] getNames() { if ((names == null) || (names.length == 0)) { getIDs(); } return names; } public void setNames(String[] names) { this.names = names; } public void saveSelection(long ID, AnTable table, int index) { last_ID = ID; last_selected_table = table; last_selected_row = index; } /* * Set selected object and save selection time */ private void setSelectedObject(long ID) { window.getSelectedObject().setSelObjV2(ID); selectionTime = window.getSelectedObject().getSelObjectSelectionTime(); sel_func = ID; // Save selection // NM saveSelection(ID, func_item, 0); // last_ID = ID; // last_selected_table = null; // last_selected_row = -1; } /* * Quick and durty hack to check if reset is needed */ // public boolean needReset() { // String fs = window.getFilterStr(); // if (fs != null) { // if (!fs.equals(lastFilter)) { // // Filter changed // boolean res = true; //return true; // } // } // if (selectionTime != window.getSelectedObject().getSelObjectSelectionTime()) { // // Selected Object was changed in another tab // if ((ids == null) || (ids.length <= 1)) { // // Stack is only one function // return true; // } // } // return false; // } } // CT_CallStack private String getSelectedViewDisplayName() { String ret = "Timeline"; // fallback if (window != null) { ret = window.getSelectedView().getDisplayName(); } return ret; } private void setClause(String shortName, String longName, String clause) { window .getFilters() .addClause( getSelectedViewDisplayName() + ": " + shortName, longName, clause, FilterClause.Kind.STANDARD); } /** * Update tree in CalTree tab Possible actions: Set Root - set the selected function as root (not * implemented yet). Reset Root - set <Total> as root (not implemented yet). Set Filter: Name in * Stack - set the selected function name as filter. Set Filter: Call Path in Stack - set the call * path to the selected function as filter. Set Filter: Function in Stack - set the selected * function as filter. Set Filter: Function is Leaf - set the selected function as filter. Show * Next Reference - show next node related to the selected function (same ID). Show All References * - show all nodes related to the selected function (not implemented yet). Expand Branch - expand * selected branch (with respect to current threshold). Expand Hottest Branch - expand the hottest * branch (with respect to current threshold). Expand Hot Branches - expand all hot branches (top * node >= 10%) (not implemented yet). Expand All Branches - expand all branches (with respect to * current threshold). Show Inclusive Metric - show inclusive metric (default). Show Exclusive * Metric - show exclusive metric (not implemented yet). Show Percentage - show percentage (with * respect to Total inclusive) (default). * * <p>Note: this method is invoked on a "worker" thread */ private void CT_UpdateTree(String actionName, ActionEvent ev) { DefaultMutableTreeNode dn; Object progressBarHandle = window.getSystemProgressPanel().progressBarStart(AnLocale.getString("Call Tree Update")); Choices: { if (actionName.equals(FILTER_SELECTED_BRANCH_ACTION_NAME)) { String clause = createFilterClause(actionName); setClause(FILTER_SELECTED_BRANCH_SHORT_NAME, FILTER_SELECTED_BRANCH_LONG_NAME, clause); break Choices; } else if (actionName.equals(FILTER_NOT_SELECTED_BRANCH_ACTION_NAME)) { String clause = createFilterClause(actionName); setClause( FILTER_NOT_SELECTED_BRANCH_SHORT_NAME, FILTER_NOT_SELECTED_BRANCH_LONG_NAME, clause); break Choices; } else if (actionName.equals(FILTER_SELECTED_FUNCTION_ACTION_NAME)) { String clause = createFilterClause(actionName); setClause(FILTER_SELECTED_FUNCTION_SHORT_NAME, FILTER_SELECTED_FUNCTION_LONG_NAME, clause); break Choices; } else if (actionName.equals(FILTER_SELECTED_LEAF_ACTION_NAME)) { String clause = createFilterClause(actionName); setClause(FILTER_SELECTED_LEAF_SHORT_NAME, FILTER_SELECTED_LEAF_LONG_NAME, clause); break Choices; } // if (actionName.equals(FILTER_NAME_ACTION_NAME)) { // String[] clause = new String[4]; // clause[0] = createFilterClause(FILTER_NAME_ACTION_NAME); // clause[1] = createFilterClause(FILTER_SELECTED_BRANCH_ACTION_NAME); // clause[2] = createFilterClause(FILTER_SELECTED_FUNCTION_ACTION_NAME); // clause[3] = createFilterClause(FILTER_SELECTED_LEAF_ACTION_NAME); //// window.filter.showDialog(); //// window.filter.setSelectedTab(1); // Select advanced filter tab // //window.filter.setClause(clause); // Put strings in combo box // window.filter.setClause(CALL_TREE + FILTER_NAME_SHORT_NAME, CALL_TREE + // FILTER_NAME_LONG_NAME, clause[0], true); // Put the string in text field // } // This must be done on AWT thread (see actionPerformed) if (actionName.equals(STR_ACTION_CUSTOM_FILTER)) { window.getFilters().showCustomFilterDialog(); break Choices; } if (actionName.equals(STR_ACTION_REMOVE_ALL_FILTERS)) { window.getFilters().addClause(FilterClause.getNoFiltersClause(), false); break Choices; } if (actionName.equals(STR_ACTION_UNDO_FILTER)) { window.getFilters().undoLastFilteraction(); break Choices; } if (actionName.equals(STR_ACTION_REDO_FILTER)) { window.getFilters().redoLastFilteraction(); break Choices; } if (actionName.equals(STR_ACTION_RESET)) { break Choices; } if (actionName.equals(STR_ACTION_SHOWSOURCE)) { CT_ShowSource(); break Choices; } if (actionName.equals(STR_ACTION_SHOWDISASM)) { CT_ShowDisasm(); break Choices; } if (actionName.equals(STR_ACTION_EXPANDBRANCH)) { stop_expanding_enabled = true; stop_expanding = false; final DefaultMutableTreeNode fdn; fdn = (DefaultMutableTreeNode) calltree.getLastSelectedPathComponent(); int threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % int level = 0; // unlimited long id = -1; long[] cstack = null; CT_ExpandBranch(calltree, fdn, level, threshold, id, cstack); stop_expanding = false; stop_expanding_enabled = false; break Choices; } if (actionName.equals(STR_ACTION_EXPANDHOTTEST)) { stop_expanding_enabled = true; stop_expanding = false; int threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % int level = 0; // unlimited long id = -1; long[] cstack = null; CT_ExpandBranch(calltree, tnTotal, level, threshold, id, cstack); stop_expanding = false; stop_expanding_enabled = false; break Choices; } if (actionName.equals(STR_ACTION_EXPANDHOT)) { stop_expanding_enabled = true; stop_expanding = false; int threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % int level = 0; // unlimited long id = -1; CT_ExpandTree(calltree, tnTotal, level, threshold, id); stop_expanding = false; stop_expanding_enabled = false; break Choices; } if (actionName.equals(STR_ACTION_EXPANDTREE)) { stop_expanding_enabled = true; stop_expanding = false; int threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % int level = 0; // unlimited long id = -1; // long time = System.currentTimeMillis(); CT_ExpandAllBranches(calltree, tnTotal, level, threshold, id); // time = System.currentTimeMillis() - time; // System.out.println("CT_ExpandAllBranches: time = "+time); stop_expanding = false; stop_expanding_enabled = false; break Choices; } if (actionName.equals(STR_ACTION_COPY_ALL)) { // Copy all lines copyAll(); break Choices; } if (actionName.equals(STR_ACTION_SETTINGS)) { window.getSettings().showDialog(window.getSettings().settingsCalltreeIndex); break Choices; } if (actionName.equals(STR_SORT_BY_METRIC)) { if (null != metricName) { for (int i = 0; i < available_metrics.length; i++) { String mn1 = available_metrics[i].getUserName(); String mn2 = AnLocale.getString("Attributed ") + mn1; if (metricName.equals(mn1) || metricName.equals(mn2)) { window.getSettings().getMetricsSetting().setSortMetricByDType(this, i, type); computed = false; computeOnAWorkerThread(); sortByName = false; break; } } } break Choices; } if (actionName.equals(STR_SORT_BY_NAME)) { sortByName = true; window.getSettings().getMetricsSetting().setSortMetricByDType(this, name_col, type); computed = false; if (selected) { computeOnAWorkerThread(); } break Choices; } if (actionName.equals(STR_ACTION_EXPANDNODE)) { dn = (DefaultMutableTreeNode) calltree.getLastSelectedPathComponent(); int threshold = window.getSettings().getCallTreeSetting().getThreshold(); // % int level = 1; // 1 level long id = -1; CT_ExpandTree(calltree, dn, level, threshold, id); break Choices; } if (actionName.equals(STR_ACTION_SHOWNEXT)) { dn = (DefaultMutableTreeNode) calltree.getLastSelectedPathComponent(); if (null != dn) { if (dn instanceof CT_TreeNode) { CT_TreeNode n = (CT_TreeNode) dn; long id = n.ID; int row = calltree.getMaxSelectionRow(); boolean do_selection = true; find(id, row, do_selection, true); } } break Choices; } if (actionName.equals(STR_ACTION_SHOWALL)) { dn = (DefaultMutableTreeNode) calltree.getLastSelectedPathComponent(); if (null != dn) { if (dn instanceof CT_TreeNode) { CT_TreeNode n = (CT_TreeNode) dn; long id = n.ID; CT_ExpandAllCallStacksForID(id); } } break Choices; } if (actionName.equals(STR_ACTION_HIDE_COLORBARS)) { show_colorbars = false; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_SHOW_COLORBARS)) { show_colorbars = true; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_HIDE_TOOLTIPS)) { show_tooltips = false; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_SHOW_TOOLTIPS)) { show_tooltips = true; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_REFRESH)) { updated = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_SHOW_INCLUSIVE)) { show_inclusive = true; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_HIDE_INCLUSIVE)) { show_inclusive = false; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_SHOW_EXCLUSIVE)) { show_exclusive = true; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_SHOW_PERCENTAGE)) { show_percentage = true; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_HIDE_PERCENTAGE)) { show_percentage = false; computed = false; computeOnAWorkerThread(); break Choices; } if (actionName.equals(STR_ACTION_STOPEXPANDING)) { stop_expanding = true; break Choices; } if (actionName.equals(STR_ACTION_COLLAPSENODE)) { CT_CollapseNode(); break Choices; } if (actionName.equals(STR_ACTION_COLLAPSETREE)) { CT_CollapseTree(); break Choices; } // if (actionName.equals(STR_ACTION_COLLAPSEBRANCH)) { // dn = (DefaultMutableTreeNode) calltree.getLastSelectedPathComponent(); // CT_CollapseBranch(calltree, dn); // } // Set metric, perhaps? if (available_metrics.length > 1) { for (int i = 0; i < available_metrics.length; i++) { if (actionName.equals(available_metrics[i].getUserName())) { sortByName = false; window .getSettings() .getMetricsSetting() .setSortMetricByDType(this, i, DSP_CallTree); // Will fire change event.... break; } } break Choices; } } // End of Choices window.getSystemProgressPanel().progressBarStop(progressBarHandle); } /** Update title */ private synchronized void CT_UpdateTitle() { String titletext = STR_TREE_TITLE_FUNCTIONS; final String threeSpaces = " "; final String STR_PERCENT = "%"; final String STR_NO_FILTER = "1"; final String STR_METRIC = AnLocale.getString("Metric: "); final String STR_THRESHOLD = AnLocale.getString("Threshold: "); final String STR_SORT_BY_NAME = AnLocale.getString("Sort by: name."); final String STR_SORT_BY_METRIC = AnLocale.getString("Sort by: metric."); lastFilter = window.getFilterStr(); // IPC CALL! Perhaps there is a better place? if ((lastFilter != null) && (!lastFilter.equals(STR_NO_FILTER))) { titletext += threeSpaces + STR_TREE_TITLE_FILTER; } else { titletext += threeSpaces + STR_TREE_TITLE_COMPLETE_VIEW; } titletext += threeSpaces + STR_THRESHOLD + window.getSettings().getCallTreeSetting().getThreshold() + STR_PERCENT; int nc = AnWindow.getInstance().getSettings().getMetricsSetting().getNameColumnIndexByDType(type); int si = AnWindow.getInstance().getSettings().getMetricsSetting().getSortColumnByDType(type); if (nc == si) { sortByName = true; } if (sortByName) { titletext += threeSpaces + STR_SORT_BY_NAME; } else { titletext += threeSpaces + STR_SORT_BY_METRIC; } if (null != metricName) { String metrictext = threeSpaces + STR_METRIC + metricName; titletext += metrictext; } final String text = titletext; AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { rootnode.setUserObject(text); calltree.repaint(); } }); } /** Variable to check if the node is expanded */ static int print_row; /** Create text presentation of the tree and print it. Calls CT_PrintChildren(). */ private String CT_PrintTree() { // Prepare text presentation of the tree String text; text = rootnode.getUserObject().toString(); String prefix = "\n"; print_row = 1; text += CT_PrintChildren(tnTotal, prefix); text += prefix; // Print it // System.out.println(text); return text; } /* * Recursively print all children */ private String CT_PrintChildren(CT_TreeNode node, String prefix) { String buf = ""; String P0 = "+-"; String P2 = " |"; String P1 = " "; // Print prefix buf = prefix + P0; if (prefix.endsWith(P2)) { buf = prefix.substring(0, prefix.length() - 1) + P0; } // Print current node info buf += node.toString(); // TEMPORARY: check if print_row is correct TreePath tp = calltree.getPathForRow(print_row); if (null == tp) { // System.err.println("WARNING: empty tree"); return buf; } CT_TreeNode n = (CT_TreeNode) tp.getLastPathComponent(); String s1 = n.toString(); String s2 = node.toString(); if (!s1.equals(s2)) { System.err.println("ERROR: node does not match the row"); return buf; } // If node is not expanded - return if (!calltree.isExpanded(print_row)) { return buf; } // Get children int nc = node.getChildCount(); if (nc <= 0) { return buf; } // Print children String ch_prefix = prefix + P2; for (int i = 0; i < nc - 1; i++) { print_row++; buf += CT_PrintChildren((CT_TreeNode) node.getChildAt(i), ch_prefix); } ch_prefix = prefix + P1; print_row++; buf += CT_PrintChildren((CT_TreeNode) node.getChildAt(nc - 1), ch_prefix); return buf; } public JPopupMenu initPopup(boolean filterOnly) { AccessibleContext ac; JMenuItem mi; JPopupMenu popup = new JPopupMenu(); String txt; boolean row_selected = false; int row = calltree.getLeadSelectionRow(); if (row >= 0) { row_selected = true; } if (!filterOnly) { // Add "Show Source" action txt = STR_ACTION_SHOWSOURCE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); popup.add(mi); // Add "Show Disassembly" action txt = STR_ACTION_SHOWDISASM; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); popup.add(mi); // Add separator popup.addSeparator(); // Add "Expand Node" action txt = STR_ACTION_EXPANDNODE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); if (calltree.isExpanded(row)) { mi.setEnabled(false); } // popup.add(mi); // TEMPORARY // Add "Expand Branch" action txt = STR_ACTION_EXPANDBRANCH; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); // Add "Expand Hottest Branch" action txt = STR_ACTION_EXPANDHOTTEST; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); // Add "Expand All Branches" action txt = STR_ACTION_EXPANDTREE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); // mi.setEnabled(true); mi.setEnabled(true); popup.add(mi); // Add separator popup.addSeparator(); // Add "Stop Expanding" action txt = STR_ACTION_STOPEXPANDING; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(stop_expanding_enabled); popup.add(mi); // Add "Collapse Node" action txt = STR_ACTION_COLLAPSENODE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); // popup.add(mi); // TEMPORARY // Add "Collapse All Branches" action txt = STR_ACTION_COLLAPSETREE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); popup.add(mi); // Add separator // popup.addSeparator(); // Add "Set Root" action txt = STR_ACTION_SETROOT; UpdateAction ua = new UpdateAction(txt); mi = new JMenuItem(ua); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (row <= 1) { mi.setEnabled(false); } else { mi.setEnabled(true); } mi.setEnabled(false); // TEMPORARY // popup.add(mi); // TEMPORARY // Add "Reset Root" action txt = STR_ACTION_RESET; UpdateAction rsa = new UpdateAction(txt); mi = new JMenuItem(rsa); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); // if root node is <Total> // mi.setEnabled(false); mi.setEnabled(false); // TEMPORARY // popup.add(mi); // TEMPORARY // // Add separator // popup.addSeparator(); // // Add "Set Threshold 0%" action // txt = STR_SET_THRESHOLD_0; // UpdateAction st0 = new UpdateAction(txt); // mi = new JMenuItem(st0); // ac = mi.getAccessibleContext(); // ac.setAccessibleDescription(txt); // if (0 == window.getSettings().getCallTreeSetting().getThreshold()) { // mi.setEnabled(false); // } else { // mi.setEnabled(true); // } // popup.add(mi); // // Add "Set Threshold 1%" action // txt = STR_SET_THRESHOLD_1; // UpdateAction st1 = new UpdateAction(txt); // mi = new JMenuItem(st1); // ac = mi.getAccessibleContext(); // ac.setAccessibleDescription(txt); // if (0 == window.getSettings().getCallTreeSetting().getThreshold()) { // mi.setEnabled(true); // } else { // mi.setEnabled(false); // } // popup.add(mi); // Add separator popup.addSeparator(); } // Add "Set Filter: Call Path in Stack ..." action txt = ADD_FILTER + FILTER_SELECTED_BRANCH_LONG_NAME; mi = new JMenuItem(new UpdateAction(txt, FILTER_SELECTED_BRANCH_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Call Path not in Stack ..." action txt = ADD_FILTER + FILTER_NOT_SELECTED_BRANCH_LONG_NAME; mi = new JMenuItem(new UpdateAction(txt, FILTER_NOT_SELECTED_BRANCH_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Function in Stack ..." action txt = ADD_FILTER + FILTER_SELECTED_FUNCTION_LONG_NAME; mi = new JMenuItem(new UpdateAction(txt, FILTER_SELECTED_FUNCTION_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); // Add "Set Filter: Function is Leaf ..." action txt = ADD_FILTER + FILTER_SELECTED_LEAF_LONG_NAME; mi = new JMenuItem(new UpdateAction(txt, FILTER_SELECTED_LEAF_ACTION_NAME)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); // // Add "Set Filter: Name in Stack ..." action // txt = ADD_FILTER + FILTER_NAME_LONG_NAME; // mi = new JMenuItem(new UpdateAction(txt, FILTER_NAME_ACTION_NAME)); // ac = mi.getAccessibleContext(); // ac.setAccessibleDescription(txt); // mi.setEnabled(row_selected); // popup.add(mi); // Add "Undo Last Filter ..." action // Add "Manage Filters..." action txt = STR_ACTION_CUSTOM_FILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); popup.add(mi); if (filterOnly) { popup.addSeparator(); } txt = STR_ACTION_UNDO_FILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(window.getFilters().canUndoLastFilter()); popup.add(mi); // Add "Redo Last Filter ..." action txt = STR_ACTION_REDO_FILTER; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(window.getFilters().canRedoLastFilter()); popup.add(mi); // Add "Restore Default Filter ..." action txt = STR_ACTION_REMOVE_ALL_FILTERS; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(window.getFilters().canRemoveAllFilters()); popup.add(mi); // Add "Remove Filter" action if (window.getFilters().anyFilters()) { popup.add(window.getFilters().removeFilterMenuItem()); } // if (filterOnly) { // popup.addSeparator(); // } if (!filterOnly) { // Add separator popup.addSeparator(); // Add "Show Next Reference To Function" action txt = STR_ACTION_SHOWNEXT; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); String hotkey = "CTRL_N"; KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_N, InputEvent.CTRL_DOWN_MASK, false); calltree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, hotkey); UpdateAction act = new UpdateAction(txt); calltree.getActionMap().put(hotkey, act); mi.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_N, ActionEvent.CTRL_MASK)); mi.setEnabled(true); popup.add(mi); // Add "Show All References To Function" action txt = STR_ACTION_SHOWALL; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); mi.setEnabled(true); popup.add(mi); // Add separator popup.addSeparator(); // Add "Hide/Show Color Bars" action if (show_colorbars) { txt = STR_ACTION_HIDE_COLORBARS; } else { txt = STR_ACTION_SHOW_COLORBARS; } mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); if (true == show_percentage) { mi.setEnabled(true); } else { mi.setEnabled(false); } popup.add(mi); // Add "Hide/Show Tool Tips" action if (show_tooltips) { txt = STR_ACTION_HIDE_TOOLTIPS; } else { txt = STR_ACTION_SHOW_TOOLTIPS; } mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); mi.setEnabled(true); popup.add(mi); // Add "Hide/Show Inclusive Metric" action if (show_inclusive) { txt = STR_ACTION_HIDE_INCLUSIVE; } else { txt = STR_ACTION_SHOW_INCLUSIVE; } mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); // popup.add(mi); // not ready yet // Add "Show Exclusive Metric" action txt = STR_ACTION_SHOW_EXCLUSIVE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(false); // TEMPORARY // popup.add(mi); // not ready yet // Add "Hide/Show Percentage" action txt = STR_ACTION_SHOW_PERCENTAGE; if (show_percentage) { txt = STR_ACTION_HIDE_PERCENTAGE; } else { txt = STR_ACTION_SHOW_PERCENTAGE; } mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(row_selected); // popup.add(mi); // not ready yet // Add separator popup.addSeparator(); // Add "Sort By Metric" action txt = STR_SORT_BY_METRIC; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (sortByName) { mi.setEnabled(true); } else { mi.setEnabled(false); } popup.add(mi); // Add "Sort By Name" action txt = STR_SORT_BY_NAME; UpdateAction st1 = new UpdateAction(txt); mi = new JMenuItem(st1); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (sortByName) { mi.setEnabled(false); } else { mi.setEnabled(true); } popup.add(mi); // Add separator popup.addSeparator(); // Add "Set Metric" action txt = STR_ACTION_SETMETRIC; UpdateAction sm = new UpdateAction(txt); mi = new JMenuItem(sm); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); if (available_metrics.length <= 1) { mi.setEnabled(false); popup.add(mi); } else { JMenu submenu1; submenu1 = new JMenu(txt); for (int i = 0; i < available_metrics.length; i++) { txt = available_metrics[i].getUserName(); sm = new UpdateAction(txt); mi = new JMenuItem(sm); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(STR_ACTION_SETMETRIC + ":" + txt); if (available_metrics[i].isNameMetric()) { mi.setEnabled(false); } else { mi.setEnabled(true); } submenu1.add(mi); } popup.add(submenu1); } // Add "Refresh Tree" action txt = STR_ACTION_REFRESH; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(true); // popup.add(mi); } // Add separator popup.addSeparator(); // Add menu item "Copy All" txt = STR_ACTION_COPY_ALL; UpdateAction cs = new UpdateAction(txt); mi = new JMenuItem(cs); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); popup.add(mi); // Add separator popup.addSeparator(); // Add "Settings" action txt = STR_ACTION_SETTINGS; UpdateAction st0 = new UpdateAction(txt); mi = new JMenuItem(st0); mi.setAccelerator(KeyboardShortcuts.settingsActionShortcut); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); popup.add(mi); return popup; } @Override public List<ExportFormat> getSupportedExportFormats() { List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.TEXT); // formats.add(ExportFormat.HTML); // formats.add(ExportFormat.CSV); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return false; } // ------- Private classes to implement popup menu items ------- // private class AnMenuListener extends MouseAdapter { private boolean debug; // NM private AnTable anTable; CallTreeView callTreeDisp; JTree tree; AnMenuListener(CallTreeView callTreeDisp, JTree tree) { this.callTreeDisp = callTreeDisp; this.tree = tree; debug = false; } // Experimental code, mostly "quick and dirty hack" public JPopupMenu initPopup(MouseEvent event) { // Experimental code // NM if (parent != null) { // NM try { // NM parent.changeSelection(anTable, table.rowAtPoint(event.getPoint())); // NM } catch (Exception exc) { // NM System.out.println("AnTable.init_popup() exception: " + exc); // NM exc.printStackTrace(); // NM } // NM } // NM setSelectedRowNow(table.rowAtPoint(event.getPoint())); return callTreeDisp.initPopup(false); } /** Check for double click to performs default action */ @Override public void mouseClicked(final MouseEvent e) { if (e.getClickCount() == 2) { performDefaultAction(); } } public void mousePressed(MouseEvent e) { maybeShowPopup(e); } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { if (!Analyzer.getInstance().normalSelection) { int row = tree.getClosestRowForLocation(e.getX(), e.getY()); if (row != -1 && !tree.isRowSelected(row)) { // if (tree.getRowCount() <= (row-1)) { // System.out.println("row="+row+" max="+tree.getRowCount()); // } tree.setSelectionRow(row); // fireAnEvent(new AnEvent(fl_table, AnEvent.EVT_SELECT, row, null)); } } JPopupMenu popup = initPopup(e); if (popup != null) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeInvisible(" + e + ")"); } } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeVisible(" + e + ")"); } } public void popupMenuCanceled(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuCanceled(" + e + ")"); } } } /* * Generic action for context menu items. * Action name is passed as String. */ class UpdateAction extends AbstractAction { String actionName = null; public UpdateAction(String name) { super(name); this.actionName = name; } public UpdateAction(String name, String actionName) { super(name); this.actionName = actionName; } @Override public void actionPerformed(ActionEvent ev) { // Use AWT thread to perform some actions // if (actionName.equals(STR_ACTION_MANAGEFILTERS)) { // window.filter.setSelectedTab(0); // window.filter.showDialog(); // return; // } if (actionName.equals(STR_ACTION_SHOW_EXCLUSIVE)) { show_exclusive = true; return; } if (actionName.equals(FILTER_SELECTED_BRANCH_ACTION_NAME) || actionName.equals(FILTER_NOT_SELECTED_BRANCH_ACTION_NAME) || actionName.equals(FILTER_SELECTED_FUNCTION_ACTION_NAME) || actionName.equals(FILTER_SELECTED_LEAF_ACTION_NAME) || actionName.equals(STR_ACTION_CUSTOM_FILTER) || actionName.equals(STR_ACTION_REMOVE_ALL_FILTERS) || actionName.equals(STR_ACTION_UNDO_FILTER) || actionName.equals(STR_ACTION_REDO_FILTER)) { // Do these actions on AWT CT_UpdateTree(actionName, ev); return; } // Use a "worker" thread to perform other actions final String an = actionName; final ActionEvent ae = ev; AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { CT_UpdateTree(an, ae); } }, "CallTree_thread"); } } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); list.add(window.getTimelineCallStackSubview()); list.add(window.getIoCallStackSubview()); return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ExperimentPickLists.java�������������������������������������������0000644�0001750�0001750�00000004675�14517772113�020562� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.picklist.PickListEvent; import org.gprofng.mpmt.picklist.PickListListener; import java.util.HashMap; import java.util.List; import java.util.Map; public class ExperimentPickLists implements PickListListener { private int MAX = 25; private Map<String, ExperimentPickList> picklistMap = new HashMap<String, ExperimentPickList>(); public ExperimentPickList getPicklist() { String host = Analyzer.getInstance().getHost(); ExperimentPickList instance = getPicklistMap().get(host); if (instance == null) { instance = new ExperimentPickList(MAX); getPicklistMap().put(host, instance); instance.addPicklistListener(this); } return instance; } public void add(String host, List<ExperimentPickListElement> list) { ExperimentPickList instance = new ExperimentPickList(MAX); if (list != null) { for (int i = list.size() - 1; i >= 0; i--) { instance.addElement(list.get(i)); } } getPicklistMap().put(host, instance); instance.addPicklistListener(this); } @Override public void contentsChanged(PickListEvent e) { fireContentsChanged(this); } private void fireContentsChanged(Object source) { AnChangeEvent anChangeevent = new AnChangeEvent(this, AnChangeEvent.Type.MOST_RECENT_EXPERIMENT_LIST_CHANGED); AnEventManager.getInstance().fireAnChangeEvent(anChangeevent); } /** * @return the picklistMap */ public Map<String, ExperimentPickList> getPicklistMap() { return picklistMap; } /** * @param picklistMap the picklistMap to set */ public void setPicklistMap(Map<String, ExperimentPickList> picklistMap) { this.picklistMap = picklistMap; } } �������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnFile.java��������������������������������������������������������0000644�0001750�0001750�00000041760�14517772113�015746� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.ipc.IPCLogger; import java.io.File; import java.io.IOException; /** AnFile extends File, overwrites method exists() */ public class AnFile extends File { public static final char separatorChar = '/'; boolean attributesReady = false; boolean isDirectoryFlag = true; boolean existsFlag = true; private String directory = null; private String fullpath = null; private static final String SLASH = "/"; private static final String DOT = "."; /** * Default constructor: expects full path * * @param pathname */ public AnFile(String pathname) { super(pathname); if (Analyzer.getInstance().remoteConnection == null) { File f = new File(pathname); if (f.exists()) { if (!f.isDirectory()) { isDirectoryFlag = false; } } else { existsFlag = false; isDirectoryFlag = false; } fullpath = f.getAbsolutePath(); directory = f.getParent(); attributesReady = true; return; } pathname = AnFileSystemView.slashifyPath(pathname); if (pathname.equals(SLASH)) { fullpath = SLASH; directory = SLASH; // NM TEMPORARY return; // Special case: leave directory = null } if (pathname.startsWith(SLASH)) { fullpath = pathname; int next = pathname.lastIndexOf(SLASH); if (next > 0) { directory = pathname.substring(0, next + 1); // include last / } else { directory = SLASH; } } else { if (Analyzer.getInstance().remoteConnection != null) { AnWindow aw = AnWindow.getInstance(); directory = aw.getCurrentRemoteDirectory(); if (directory == null) { directory = DOT; // NM TEMPORARY } if (!directory.endsWith(SLASH)) { directory += SLASH; } } else { directory = SLASH; // ? BUG! } fullpath = directory + pathname; } fullpath = AnFileSystemView.slashifyPath(fullpath); // Now let's check if everything is correct int error = 0; if (fullpath.equals(SLASH)) { // System.err.println("AnFile: error = 1; fullpath="+fullpath); IPCLogger.logTrace("\n" + "AnFile: error = 1; fullpath=" + fullpath); error = 1; // should not come here } if (null == directory) { // System.err.println("AnFile: error = 2; fullpath="+fullpath+" directory="+directory); IPCLogger.logTrace( "\n" + "AnFile: error = 2; fullpath=" + fullpath + " directory=" + directory); error = 2; // should not come here } if (directory.endsWith(SLASH)) { String fn = directory + getName(); if (!fullpath.equals(fn)) { // System.err.println("AnFile: error = 3; fullpath="+fullpath+" directory="+directory+" // fn="+fn); // Exception e = new Exception(); // e.printStackTrace(); IPCLogger.logTrace( "\n" + "AnFile: error = 3; fullpath=" + fullpath + " directory=" + directory + " fn=" + fn); error = 3; } } else { // System.err.println("AnFile: error = 4; fullpath="+fullpath+" directory="+directory); IPCLogger.logTrace( "\n" + "AnFile: error = 4; fullpath=" + fullpath + " directory=" + directory); error = 4; String fn = directory + SLASH + getName(); if (!fullpath.equals(fn)) { // System.err.println("AnFile: error = 5; fullpath="+fullpath+" directory="+directory); IPCLogger.logTrace( "\n" + "AnFile: error = 5; fullpath=" + fullpath + " directory=" + directory); error = 5; } } } /** * Constructor: expects full directory path and short file name * * @param dir * @param name */ public AnFile(String dir, String name) { this(dir + SLASH + name); } @Override public File[] listFiles() { File[] ret; if (Analyzer.getInstance().remoteConnection == null) { ret = super.listFiles(); } else { ret = AnFileSystemView.getFileSystemView() .getFiles(this, false); // FIXUP: how tp pass isFileHidingEnabled? } return ret; } /** * Checks if remote file exists. * * @return */ @Override public boolean exists() { if (!attributesReady) { updateAttributes(); } return existsFlag; } /** * Checks if remote file is a directory. * * @return */ @Override public boolean isDirectory() { if (!attributesReady) { updateAttributes(); } return isDirectoryFlag; } /** * Checks if remote file is a regular file. * * @return */ @Override public boolean isFile() { if (!attributesReady) { updateAttributes(); } return !isDirectoryFlag; } /** * Check if file path is absolute * * @return */ @Override public boolean isAbsolute() { String pathname = getPath(); if (pathname.startsWith(SLASH)) { return true; } return false; } /** * Gets path * * @return path */ @Override public String getPath() { return this.fullpath; } /** * Returns the absolute form of this abstract pathname. Equivalent to <code> * new AnFile(this.{@link #getAbsolutePath})</code>. * * @return The absolute abstract pathname denoting the same file or directory as this abstract * pathname */ @Override public File getAbsoluteFile() { if (Analyzer.getInstance().remoteConnection == null) { // Optimization return super.getAbsoluteFile(); } // NM why not return this? if (!attributesReady) { updateAttributes(); } String absPath = getAbsolutePath(); AnFile af = new AnFile(absPath); af.setAttributes(directory, isDirectoryFlag, existsFlag); return (af); } @Override public File getCanonicalFile() throws IOException { if (Analyzer.getInstance().remoteConnection == null) { // Optimization return super.getCanonicalFile(); } return (getAbsoluteFile()); } @Override public String getCanonicalPath() /* throws IOException */ { return (getAbsolutePath()); } /** * Returns the absolute pathname string of this abstract pathname. * * @return The absolute pathname string denoting the same file or directory as this abstract * pathname */ @Override public String getAbsolutePath() { String pathname = getPath(); if (pathname.startsWith(SLASH)) { // Temporary fix for Windows pathname = AnFileSystemView.slashifyPath(pathname); return pathname; } if (null == directory) { // System.err.println("getAbsolutePath: error: directory=null fullpath="+fullpath); // BUG IPCLogger.logTrace("\n" + "getAbsolutePath: error: directory=null fullpath=" + fullpath); return super.getAbsolutePath(); // This is not AnFile, which means this is the bug! } if (!directory.endsWith(SLASH)) { directory = directory + SLASH; // BUG! } pathname = directory + pathname; // Temporary fix for Windows pathname = AnFileSystemView.slashifyPath(pathname); return pathname; } /** * Returns the pathname string of this abstract pathname's parent, or <code>null</code> if this * pathname does not name a parent directory. * * <p>The <em>parent</em> of an abstract pathname consists of the pathname's prefix, if any, and * each name in the pathname's name sequence except for the last. If the name sequence is empty * then the pathname does not name a parent directory. * * @return The pathname string of the parent directory named by this abstract pathname, or <code> * null</code> if this pathname does not name a parent */ @Override public String getParent() { if (Analyzer.getInstance().remoteConnection == null) { // Optimization return super.getParent(); } String parent = directory; if (null == parent) { // System.err.println("AnFile: error: getParent(); fullpath="+fullpath+" // directory="+directory); // BUG IPCLogger.logTrace( "\n" + "AnFile: error: getParent(); fullpath=" + fullpath + " directory=" + directory); return null; } if (parent.length() > 1) { if (parent.endsWith(SLASH)) { parent = parent.substring(0, parent.length() - 1); } } return parent; } /** * Returns the abstract pathname of this abstract pathname's parent, or <code>null</code> if this * pathname does not name a parent directory. * * <p>The <em>parent</em> of an abstract pathname consists of the pathname's prefix, if any, and * each name in the pathname's name sequence except for the last. If the name sequence is empty * then the pathname does not name a parent directory. * * @return The abstract pathname of the parent directory named by this abstract pathname, or * <code>null</code> if this pathname does not name a parent * @since 1.2 */ @Override public File getParentFile() { if (fullpath == null) { fullpath = SLASH; } if (fullpath.equals(SLASH)) { // Special case to make MetalFileChooser happy: return null return null; } String p = getParent(); if (p == null) { return null; } AnFile af = new AnFile(p); // directory return (af); // return new AnFile(p, this.prefixLength); } /** * Returns the parent directory of <code>dir</code>. * * @param dir the <code>File</code> being queried * @return the parent directory of <code>dir</code>, or <code>null</code> if <code>dir</code> is * <code>null</code> */ public File getParentDirectory(File dir) { if (dir == null || !dir.exists()) { return null; } String psf = dir.getParent(); if (psf == null) { return null; } AnFile pdir = new AnFile(dir.getParent()); return pdir; } /** * Gets path * * @return path */ public String getDirectoryName() { return this.directory; } /** * Renames the file denoted by this abstract pathname. * * <p>Many aspects of the behavior of this method are inherently platform-dependent: The rename * operation might not be able to move a file from one filesystem to another, it might not be * atomic, and it might not succeed if a file with the destination abstract pathname already * exists. The return value should always be checked to make sure that the rename operation was * successful. * * <p>Note that the {@link java.nio.file.Files} class defines the {@link java.nio.file.Files#move * move} method to move or rename a file in a platform independent manner. * * @param dest The new abstract pathname for the named file * @return <code>true</code> if and only if the renaming succeeded; <code>false</code> otherwise * @throws SecurityException If a security manager exists and its <code>{@link * java.lang.SecurityManager#checkWrite(java.lang.String)}</code> method denies write * access to either the old or new pathnames * @throws NullPointerException If parameter <code>dest</code> is <code>null</code> */ @Override public boolean renameTo(File dest) { if (dest == null) { // throw new NullPointerException(); return false; } // if (this.isInvalid() || dest.isInvalid()) { // return false; // } boolean ret = false; if (dest instanceof AnFile) { AnFile newFile = (AnFile) dest; String srcName = getAbsolutePath(); String destName = newFile.getAbsolutePath(); // System.out.println("Rename to: " + newFile.getAbsolutePath()); // ret = AnWindow.getInstance().renameFile(srcName, destName); // Not implemented yet String res = AnWindow.getInstance().createDirectories(destName); if (null == res || res.length() <= 0) { // created res = AnWindow.getInstance().deleteFile(srcName); if (null == res || res.length() <= 0) { // deleted ret = true; } } } return ret; } /** * Sets flag isDirectoryFlag * * @param directory * @param isDirectory * @param exists */ public void setAttributes(String directory, boolean isDirectory, boolean exists) { if (null != directory) { if (!directory.endsWith(SLASH)) { directory = directory + SLASH; // BUG! } this.directory = directory; } isDirectoryFlag = isDirectory; existsFlag = exists; attributesReady = true; } /** * Gets flag attributesReady * * @return boolean attributesReady */ public boolean getAttributesReady() { return attributesReady; } /** Update attributes of this remote file */ public void updateAttributes() { if (!attributesReady) { if (Analyzer.getInstance().remoteConnection != null) { AnWindow aw = AnWindow.getInstance(); AnFileSystemView afsv = null; AnChooser ac = null; // aw.getAnChooserRemote(); if (null != ac) { afsv = ac.getAnFileSystemView(); } else { afsv = AnFileSystemView.getFileSystemView(); if (null != afsv) { afsv.setAnWindow(aw); } } if (null != afsv) { afsv.updateFileAttributes(this); attributesReady = true; } } } } /** * Tests this abstract pathname for equality with the given object. Returns <code>true</code> if * and only if the argument is not <code>null</code> and is an abstract pathname that denotes the * same file or directory as this abstract pathname. Whether or not two abstract pathnames are * equal depends upon the underlying system. On UNIX systems, alphabetic case is significant in * comparing pathnames; on Microsoft Windows systems it is not. * * @param obj The object to be compared with this abstract pathname * @return <code>true</code> if and only if the objects are the same; <code>false</code> otherwise */ @Override public boolean equals(Object obj) { if ((obj != null) && (obj instanceof AnFile)) { return compareTo((AnFile) obj) == 0; } return super.equals(obj); } /** * Compares two abstract pathnames lexicographically. The ordering defined by this method depends * upon the underlying system. On UNIX systems, alphabetic case is significant in comparing * pathnames; on Microsoft Windows systems it is not. * * @param pathname The abstract pathname to be compared to this abstract pathname * @return Zero if the argument is equal to this abstract pathname, a value less than zero if this * abstract pathname is lexicographically less than the argument, or a value greater than zero * if this abstract pathname is lexicographically greater than the argument * @since 1.2 */ @Override public int compareTo(File pathname) { if ((pathname != null) && (pathname instanceof AnFile)) { return ((pathname.getPath()).compareTo(this.getPath())); } return super.compareTo(pathname); } /** * Deletes the file or directory denoted by this abstract pathname. If this pathname denotes a * directory, then the directory must be empty in order to be deleted. * * @return <code>true</code> if and only if the file or directory is successfully deleted; <code> * false</code> otherwise */ @Override public boolean delete() { if (!exists()) { return true; } if (Analyzer.getInstance().remoteConnection != null) { AnWindow aw = AnWindow.getInstance(); String error = aw.deleteFile(fullpath); if (error != null && error.length() > 0) { return false; } } else { return super.delete(); } attributesReady = false; return true; } /** * Creates the directory named by this abstract pathname, including any necessary but nonexistent * parent directories. Note that if this operation fails it may have succeeded in creating some of * the necessary parent directories. * * @return <code>true</code> if and only if the directory was created, along with all necessary * parent directories; <code>false</code> otherwise */ @Override public boolean mkdirs() { if (exists()) { return false; } if (Analyzer.getInstance().remoteConnection != null) { AnWindow aw = AnWindow.getInstance(); String error = aw.createDirectories(fullpath); if (error != null && error.length() > 0) { return false; } } else { return super.mkdirs(); } attributesReady = false; return true; } } ����������������gprofng-gui-1.0/org/gprofng/mpmt/AnTree.java��������������������������������������������������������0000644�0001750�0001750�00000015110�14517772113�015754� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.util.gui.AnJTree; import org.gprofng.mpmt.util.gui.AnTextIcon; import java.awt.Component; import java.awt.event.MouseEvent; import java.util.EventObject; import javax.swing.Icon; import javax.swing.JComponent; import javax.swing.JTree; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeCellEditor; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; public final class AnTree extends AnJTree { private final DefaultMutableTreeNode root; private final DefaultTreeModel model; private final int expand_row; private final AnTreeRenderer renderer; // Constructor public AnTree(final String name, final int row) { super(); root = new DefaultMutableTreeNode(name, true); model = new DefaultTreeModel(root); expand_row = row; model.setAsksAllowsChildren(true); setModel(model); putClientProperty("JTree.lineStyle", "Angled"); setShowsRootHandles(true); setEditable(true); setCellRenderer(renderer = new AnTreeRenderer()); setCellEditor(new AnTreeEditor(this, renderer)); } // Add one node into the root private void addNode(final AnTextIcon item) { final DefaultMutableTreeNode node; node = new DefaultMutableTreeNode(item, true); node.add(new DefaultMutableTreeNode(null, false)); root.add(node); } // Add the extra node; the first child node public int addExtra(final String extra) { int last; // Remove all nodes when restart getCellEditor().cancelCellEditing(); root.removeAllChildren(); last = 0; if (last == 0) { addNode(new AnTextIcon(extra, null)); model.nodeStructureChanged(root); } else { last--; } return last; } // Add nodes public void addNodes(final AnTextIcon[] list, final int last) { final int size; int iv; final int[] indices; size = list.length; indices = new int[size - last]; iv = 0; for (int i = last; i < size; i++) { indices[iv++] = i + 1; addNode(list[i]); } model.nodesWereInserted(root, indices); // Initially expand the first child node if (last == 0) { expandRow(expand_row); } } // Remove nodes public void removeNodes(final int[] remove_index) { final int nd = remove_index.length; final DefaultMutableTreeNode node; final int[] indices; final Object[] rm_node; getCellEditor().cancelCellEditing(); // If remove all, clean up but keep the extra node if (nd >= root.getChildCount() - 1) { node = (DefaultMutableTreeNode) root.getChildAt(0); addExtra(((AnTextIcon) node.getUserObject()).getText()); return; } indices = new int[nd]; rm_node = new Object[nd]; for (int i = nd - 1; i >= 0; i--) { indices[i] = remove_index[i] + 1; rm_node[i] = root.getChildAt(indices[i]); root.remove(indices[i]); } model.nodesWereRemoved(root, indices, rm_node); } // Remove all nodes public void removeAllNodes() { if (root.getChildCount() != 0) { getCellEditor().cancelCellEditing(); root.removeAllChildren(); model.nodeStructureChanged(root); } } // Set object of the content node public void setContent(final int index, final Object object) { final DefaultMutableTreeNode node, content; node = (DefaultMutableTreeNode) root.getChildAt(index); content = (DefaultMutableTreeNode) node.getChildAt(0); content.setUserObject(object); model.nodeChanged(content); } // Tree cell renderer private static final class AnTreeRenderer extends DefaultTreeCellRenderer { public Component getTreeCellRendererComponent( final JTree tree, Object value, final boolean sel, final boolean expanded, final boolean leaf, final int row, final boolean hasFocus) { final Object object; final AnTextIcon item; Icon icon = null; setLeafIcon(null); setClosedIcon(null); setOpenIcon(null); if (value instanceof DefaultMutableTreeNode) { object = ((DefaultMutableTreeNode) value).getUserObject(); if (object instanceof AnTextIcon) { item = (AnTextIcon) object; value = item.getText(); icon = item.getIcon(); } else if (object instanceof JComponent) { ((JComponent) object) .setBorder(hasFocus ? AnVariable.treeFocusBorder : AnVariable.noFocusBorder); return (Component) object; } } super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus); if (icon != null) { setIcon(icon); } return this; } } // Tree cell editor private final class AnTreeEditor extends DefaultTreeCellEditor { public AnTreeEditor(final JTree tree, final DefaultTreeCellRenderer renderer) { super(tree, renderer); } public Component getTreeCellEditorComponent( final JTree tree, final Object value, final boolean isSelected, final boolean expanded, final boolean leaf, final int row) { editingComponent = this.renderer.getTreeCellRendererComponent( tree, value, isSelected, expanded, leaf, row, true); return editingComponent; } public boolean isCellEditable(final EventObject evt) { if (evt instanceof MouseEvent) { final MouseEvent mEvt = (MouseEvent) evt; if (mEvt.getClickCount() == 1) { final TreePath selPath = tree.getPathForLocation(mEvt.getX(), mEvt.getY()); if (selPath == null) { return false; } final DefaultMutableTreeNode node = (DefaultMutableTreeNode) selPath.getLastPathComponent(); if (node.getUserObject() instanceof ExperimentsView.AnTreePanel) { return true; } } } return super.isCellEditable(evt); } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnFrame.java�������������������������������������������������������0000644�0001750�0001750�00000006171�14517772113�016116� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.guitesting.GUITesting; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnMenuBar; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.Point; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JFrame; import javax.swing.JMenuBar; public final class AnFrame extends JFrame { private AnWindow window; private Analyzer analyzer; // Constructor public AnFrame(final Analyzer analyzer) { super(Analyzer.getAnalyzerReleaseName()); getAccessibleContext().setAccessibleDescription(Analyzer.getAnalyzerReleaseName()); this.analyzer = analyzer; } /** Doesn't require running IPC. Called once. AWT thread */ public void initComponents() { AnUtility.checkIfOnAWTThread(true); // Menu bar JMenuBar menu_bar = new AnMenuBar(); menu_bar.setBorder(null); setJMenuBar(menu_bar); // Register the event handlers addWindowListener(new WindowHandler(this)); // Adjust the window UserPref userPref = UserPref.getInstance(); Dimension size; Point location; size = userPref.getFrameSize(); location = userPref.getFrameLocation(); if (!insideScreen(size, location)) { // Try move window location = new Point(0, 0); } if (!GUITesting.getInstance().isRunningUnderGUITesting()) { if (!insideScreen(size, location)) { // Try to resize location = userPref.getDefaultFrameLocation(); size = userPref.getDefaultFrameSize(); } } setSize(size); setLocation(location); // AnWindow window = new AnWindow(analyzer, this, getContentPane(), menu_bar); if (AnUtility.analyzer_icon != null) { setIconImage(AnUtility.analyzer_icon.getImage()); } } private boolean insideScreen(Dimension size, Point location) { // Note: add 6 pixels beacuse of full screen mode goes a bit outside screen return (location.x + size.width <= AnVariable.SCREEN_SIZE.width + 6 && location.y + size.height <= AnVariable.SCREEN_SIZE.height); } // Get AnWindow public AnWindow getWindow() { return window; } // Window handler private final class WindowHandler extends WindowAdapter { private AnFrame anFrame; public WindowHandler(AnFrame anFrame) { this.anFrame = anFrame; } @Override public void windowClosing(final WindowEvent event) { AnWindow.getInstance().exitAction(); } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/�������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�016374� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/StackState.java����������������������������������������0000644�0001750�0001750�00000005764�14517772113�021224� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; import java.awt.Color; import java.awt.Font; import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.WritableRaster; // State represents each element in the callstack // This class is immutable public class StackState { private static final Font f; static { f = javax.swing.UIManager.getFont("List.font"); } private static final int ICON_WIDTH = f.getSize() < 17 ? 19 : f.getSize() + 2; private static final int ICON_HEIGHT = f.getSize() < 17 ? 19 : f.getSize() + 2; private final String fname; // func name private final long fnumber; // Histable::Function* (NOT Function->id) // Constructor public StackState(String fname, long fnumber) { this.fname = fname; this.fnumber = fnumber; } public String getName() { return fname; } public long getNumber() { return fnumber; } @Override public Object clone() { StackState s = new StackState(fname, fnumber); return s; } public static Image createContigIcon(Color color) { return createIcon(color, ICON_WIDTH, ICON_HEIGHT, false); } public static Image createIcon(Color color) { return createIcon(color, ICON_WIDTH - 2, ICON_HEIGHT - 2, true); } public static Image createIcon(Color color, int width, int height, boolean draw_outline) { BufferedImage image; WritableRaster raster; ColorModel model; int argb, x_last, y_last, i, j; Object data; image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); raster = image.getRaster(); model = image.getColorModel(); argb = color.getRGB(); data = model.getDataElements(argb, null); x_last = width - 1; y_last = height - 1; for (i = 1; i < x_last; i++) { for (j = 1; j < y_last; j++) { raster.setDataElements(i, j, data); } } if (draw_outline) { color = Color.black; argb = color.getRGB(); data = model.getDataElements(argb, null); for (i = 0; i < width; i++) { raster.setDataElements(i, 0, data); raster.setDataElements(i, y_last, data); } for (j = 0; j < height; j++) { raster.setDataElements(0, j, data); raster.setDataElements(x_last, j, data); } } return image; } @Override public String toString() { return fname; } } ������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/ChooserStateView.java����������������������������������0000644�0001750�0001750�00000014756�14517772113�022415� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; import static java.util.concurrent.TimeUnit.*; import org.gprofng.mpmt.AnEvent; import org.gprofng.mpmt.AnListener; import java.awt.Color; import java.awt.Component; import java.util.*; import java.util.concurrent.*; import javax.swing.DefaultListCellRenderer; import javax.swing.ImageIcon; import javax.swing.JList; import javax.swing.ListModel; import javax.swing.SwingUtilities; // Display alphabetically sorted StackStates as Colored boxes labeled with function names public class ChooserStateView extends JList<StackState> implements AnListener { protected final StateColorMap color_map; private StateColorMap.ColorMapSnapshot stateColorSnapshot; private boolean show_duplicates; // one line for each func even if name is same private HashMap<Long, Integer> funcMap; // Maps Func #s to line in list private ArrayList<StackState> sortedData; // copy of original data private final Object updateLock = new Object(); private boolean ignoreUpdates = false; private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); private List<Long> selectedFuncs; // Constructor public ChooserStateView(final StateColorMap color_map) { this.color_map = color_map; stateColorSnapshot = null; ListRenderer lrend; lrend = new ListRenderer(); setCellRenderer(lrend); setBackground(lrend.getBackground()); resetVals(); color_map.addAnListener(this); } private void resetVals() { show_duplicates = false; funcMap = null; sortedData = null; selectedFuncs = new ArrayList<Long>(); } // Set components (MUST BE CALLED ON AWT THREAD) private void setStackStates(Collection<StackState> states) { ArrayList<StackState> data = (states != null) ? new ArrayList(states) : new ArrayList(); Collections.sort( data, new Comparator() { public int compare(Object a, Object b) { StackState aa, bb; aa = (StackState) a; bb = (StackState) b; return aa.getName().compareTo(bb.getName()); } }); sortedData = new ArrayList(data); Vector dataList = new Vector(); funcMap = new HashMap(); // map func #s to dataList String recentName = null; // most recently seen name for (StackState state : sortedData) { if (show_duplicates || !state.getName().equals(recentName)) { dataList.add(state); recentName = state.getName(); } funcMap.put(new Long(state.getNumber()), new Integer(dataList.size() - 1)); } if (!isSelectionEmpty()) { List<StackState> list = getSelectedValuesList(); selectedFuncs = new ArrayList(); for (StackState state : list) { Long val = state.getNumber(); selectedFuncs.add(val); } } setListData(dataList); if (selectedFuncs != null && !selectedFuncs.isEmpty()) { setSelectedFunctions(selectedFuncs); } } private void updateColors() { // only access stateColorSnapshot and setStackStates on AWT thread SwingUtilities.invokeLater( new Runnable() { @Override public void run() { StateColorMap.ColorMapSnapshot latest = color_map.checkForAllUpdates(stateColorSnapshot); if (stateColorSnapshot != latest) { stateColorSnapshot = latest; Collection<StackState> states = stateColorSnapshot.getStackStates(); setStackStates(states); repaint(); } } }); } // color change(s); may be called extremely frequently @Override public void valueChanged(AnEvent ee) { synchronized (updateLock) { if (ignoreUpdates) { return; } // do an immediate update then ignore updates for a while ignoreUpdates = true; updateColors(); } scheduler.schedule( new Runnable() { public void run() { synchronized (updateLock) { // after delay, do an update and reenable future updates ignoreUpdates = false; updateColors(); } } }, 1000, MILLISECONDS); // max rate of refreshing is set here } // Set selected function (MUST BE CALLED ON AWT THREAD) public StackState getState(int ii) { return (StackState) this.getModel().getElementAt(ii); } // Set selected function (MUST BE CALLED ON AWT THREAD) public void setSelectedFunctions(List<Long> funcs) { selectedFuncs = funcs; if (funcMap == null) { return; } ListModel data = getModel(); if (data == null) { return; } if (funcs.isEmpty()) { clearSelection(); return; } int idxs[] = new int[funcs.size()]; int ii = 0; for (Long func : funcs) { Integer idx = funcMap.get(func); if (idx == null) { continue; } idxs[ii++] = idx; } setSelectedIndices(idxs); if (idxs.length == 1) { ensureIndexIsVisible(idxs[0]); } } public void setSelectedFunction(long lfunc) { Long func = lfunc; List<Long> funcs = new ArrayList(); funcs.add(func); setSelectedFunctions(funcs); } // Set selected functions (MUST BE CALLED ON AWT THREAD) public void setSelectionFunctions(HashSet<Long> funcList) { for (Long func : funcList) { setSelectedFunction(func); } } // List renderer protected class ListRenderer extends DefaultListCellRenderer { public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); StackState state = (StackState) value; setText(state.getName()); Color color = color_map.getFuncColor(state.getNumber()); setIcon(new ImageIcon(StackState.createIcon(color))); return this; } } } ������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/StackViewState.java������������������������������������0000644�0001750�0001750�00000002652�14517772113�022050� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; // This class is immutable // State represents each element in the callstack public class StackViewState extends StackState { private final String pcname; private final long pcid; // Histable::DbeInstr* (NOT DbeInstr->id) // Constructor public StackViewState(String fname, String pcname, long fnumber, long pcid) { super(fname, fnumber); this.pcname = pcname; this.pcid = pcid; } // Gets pcname of function as shown in callstack public String getPCName() { return pcname; } public long getPC() { return pcid; } public Object clone() { StackViewState s = new StackViewState(super.getName(), pcname, super.getNumber(), pcid); return s; } public String toString() { return pcname; } } ��������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/StackStateList.java������������������������������������0000644�0001750�0001750�00000005060�14517772113�022045� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; import org.gprofng.mpmt.AnWindow; import java.util.ArrayList; import java.util.HashMap; import java.util.Set; /** * Maintains a list of StackState. Given function id as input, performs IPC to look up function * names. This class can be used to cache function id names. */ public class StackStateList { private final AnWindow anWindow; private final HashMap<Long, StackState> function_htable; // unique StackStates; key=function_id public StackStateList(AnWindow _anWindow) { anWindow = _anWindow; function_htable = new HashMap(); } public void clear() { synchronized (function_htable) { function_htable.clear(); } } public StackState get(long fid) { synchronized (function_htable) { return function_htable.get(fid); } } public ArrayList<StackState> ipcAdd(Set<Long> newFids) { // IPC! ArrayList<Long> missing_fids = new ArrayList(); synchronized (function_htable) { for (Long fid : newFids) { if (!function_htable.containsKey(fid)) { missing_fids.add(fid); } } } if (!missing_fids.isEmpty()) { // now go fetch the missing strings int size = missing_fids.size(); final long[] fidArray = new long[size]; int i = 0; for (Long iter : missing_fids) { fidArray[i] = iter.longValue(); i++; } // get function names final String[] names = anWindow.getFuncNames(fidArray); // IPC!! ArrayList<StackState> missing = new ArrayList(); i = 0; synchronized (function_htable) { for (Long iter : missing_fids) { long fid = iter.longValue(); String name = names[i]; StackState stackState = new StackState(name, fid); function_htable.put(fid, stackState); missing.add(stackState); i++; } } return missing; } return null; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/ColorMap.java������������������������������������������0000644�0001750�0001750�00000026754�14517772113�020674� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; import org.gprofng.mpmt.AnEvent; import org.gprofng.mpmt.AnListener; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import javax.swing.event.EventListenerList; public abstract class ColorMap { public class ColorMapSnapshot { private final long versionNum; private final HashMap<Long, Color> colorMap; private final Collection<StackState> stackStates; ColorMapSnapshot( long _version, HashMap<Long, Color> _colorMap, HashMap<Long, StackState> _stackStateMap) { versionNum = _version; colorMap = (_colorMap != null) ? (HashMap<Long, Color>) _colorMap.clone() : null; stackStates = (_stackStateMap != null) ? new ArrayList(_stackStateMap.values()) : null; } protected long getVersion() { return versionNum; } public HashMap<Long, Color> getColorMap() { return colorMap; } public Collection<StackState> getStackStates() { return stackStates; } } private final ArrayList<ColorRule> activeRules; private final ArrayList<ColorRule> defaultRules; private final HashMap<Long, Color> colorMap; // Maps Func #s to Colors private final HashMap<Long, StackState> stackStateMap; // Maps Func #s to StackState (Names + ID) private long versionNumber; // tracks all changes // Constructor public ColorMap() { versionNumber = 0; colorMap = new HashMap(); stackStateMap = new HashMap(); activeRules = new ArrayList(); defaultRules = new ArrayList(); } public synchronized void reset() { updateVersion(); colorMap.clear(); stackStateMap.clear(); activeRules.clear(); defaultRules.clear(); } protected abstract Color getBaseColor(String name); private Color computeColor(StackState state) { Color c = checkRules(state, activeRules); if (c == null) { c = checkRules(state, defaultRules); } if (c == null) { c = getBaseColor(state.getName()); } return c; } private int addState(StackState state) { String name = state.getName(); long number = state.getNumber(); StackState tmp = stackStateMap.put(number, state); if (tmp != null) { if (tmp.getName().equals(name)) { return 0; // already seen this number/name combination; done! } else { ; // weird! Someone used an alternate name for the function? } } Color c = computeColor(state); setFuncColor(state, c); return 1; } private Color checkRules(StackState state, List<ColorRule> rules) { for (int ii = rules.size() - 1; ii >= 0; ii--) { final ColorRule rule = rules.get(ii); final Pattern reg_exp = rule.reg_exp; final String str_class = rule.getText(); final String name = state.getName(); Color c = null; switch (rule.getType()) { case ColorRule.SETC_START: if (name.startsWith(str_class)) { c = rule.getColor(); } break; case ColorRule.SETC_END: if (name.endsWith(str_class)) { c = rule.getColor(); } break; case ColorRule.SETC_CONTAIN: if (name.indexOf(str_class) != -1) { c = rule.getColor(); } break; case ColorRule.SETC_MATCHES: if (name.equals(str_class)) { c = rule.getColor(); } break; case ColorRule.SETC_REGEXP: if (reg_exp != null && reg_exp.matcher(name).matches()) { c = rule.getColor(); } break; case ColorRule.SETC_ALL: c = rule.getColor(); break; default: return null; // weird! } if (c != null) { return c; } } return null; } // Set class to color: handles changes done through color chooser private void internalSetRule(ColorRule rule) { boolean clears_all = false; ColorRule newRule = rule; switch (rule.getType()) { case ColorRule.SETC_ALL: clears_all = true; break; case ColorRule.SETC_REGEXP: try { Pattern reg_exp = Pattern.compile(rule.getText()); newRule = new ColorRule( rule.getColor(), rule.getType(), rule.getText(), rule.getIsDefault(), reg_exp); } catch (PatternSyntaxException ex) { // YXXX warn user here return; } break; default: break; } ArrayList<ColorRule> selectedRules = rule.getIsDefault() ? defaultRules : activeRules; if (clears_all) { selectedRules.clear(); } selectedRules.add(newRule); } // Set selected func to color private void setFuncColor(final StackState state, final Color color) { Color c = colorMap.put(state.getNumber(), color); if (c == null || !c.equals(color)) { ; // colors changed } } private void updateColors() { Collection<StackState> stackStates = stackStateMap.values(); for (StackState state : stackStates) { Color color = computeColor(state); setFuncColor(state, color); } } private void updateVersion() { // may be called from any thread. versionNumber++; AnUtility.invokeLaterOnSwingThread( new Runnable() { @Override public void run() { fireAnEvent(new AnEvent(this, AnEvent.EVT_UPDATE, 0, null)); } }); } // =============== public functions, must be synchronized =============== public synchronized int addStates(Collection<StackState> states) { int numAdded = 0; for (StackState state : states) { numAdded += addState(state); } if (numAdded == 0) { return numAdded; } updateVersion(); return numAdded; } public synchronized Color getFuncColor(long number) { Color c = colorMap.get(number); if (c == null) { c = Color.black; // weird, caller didn't add this function } return c; } public synchronized ColorMapSnapshot checkForColorUpdates(ColorMapSnapshot snapshot) { if (snapshot == null || snapshot.versionNum != versionNumber) { return new ColorMapSnapshot(versionNumber, colorMap, null); } return snapshot; // no changes } public synchronized ColorMapSnapshot checkForAllUpdates(ColorMapSnapshot snapshot) { if (snapshot == null || snapshot.versionNum != versionNumber) { return new ColorMapSnapshot(versionNumber, colorMap, stackStateMap); } return snapshot; // no changes } public synchronized List<ColorRule> getActiveRules() { return activeRules; } public synchronized void setRule( final Color color, final int type, String text, boolean is_default) { ColorRule rule = new ColorRule(color, type, text, is_default); internalSetRule(rule); updateColors(); updateVersion(); } /** * initialize color rules (no events) * * @param rules */ public synchronized void initRules(final List<ColorRule> rules, boolean sendEvent) { activeRules.clear(); for (ColorRule rule : rules) { internalSetRule(rule); } updateColors(); if (sendEvent) { updateVersion(); } } /** * set color rules and send events * * @param rules */ public synchronized void setRules(final List<ColorRule> rules) { for (ColorRule rule : rules) { internalSetRule(rule); } updateColors(); updateVersion(); } // Set all to color public synchronized void setRuleAllFunctions(final Color color) { ColorRule rule = new ColorRule(color, ColorRule.SETC_ALL, null, false); internalSetRule(rule); updateColors(); updateVersion(); } // Reset all function color to default public synchronized void restoreToDefault() { activeRules.clear(); updateColors(); updateVersion(); } // Listener to the event changed private final EventListenerList listenerList = new EventListenerList(); // Add a listener to the list public void addAnListener(final AnListener listener) { listenerList.add(AnListener.class, listener); } // Fire AnEvent to the listener private void fireAnEvent(AnEvent event) { AnUtility.checkIfOnAWTThread(true); // System.out.println("ColorMap fireAnEvent: " + event); Object[] listeners; listeners = listenerList.getListenerList(); for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == AnListener.class) { ((AnListener) listeners[i + 1]).valueChanged(event); } } } // public void asyncUpdateFullColorMap() { // AnUtility.dispatchOnAWorkerThread(new Runnable() { // @Override // public void run() { // updateFullColorMapIPC(); // } // }, "ColorMapUpdateFullColorMap"); // } public int updateFullColorMapIPC() { Object[] res = getCallTreeFuncsIPC(); if (res == null) { return 0; } long[] funcs = (long[]) res[0]; String[] names = (String[]) res[1]; long[] functions = (long[]) res[2]; List<StackState> states = new ArrayList(); for (int ii = 0; ii < funcs.length; ii++) { if (names[ii] == null) { continue; } StackState state = new StackState(names[ii], functions[ii]); // name, Histable::Function* states.add(state); } int num_added = addStates(states); return num_added; } private Object[] getCallTreeFuncsIPC() { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getCallTreeFuncs"); anWindow.IPC().send(0); Object[] res = (Object[]) anWindow.IPC().recvObject(); return res; } } // <newFunctions> is Histable::Function* public List<StackState> addFunctionsIPC(Set<Long> newFunctions) { // IPC! Set<Long> missing_fids = new HashSet<>(); synchronized (this) { for (Long fid : newFunctions) { if (!stackStateMap.containsKey(fid)) { missing_fids.add(fid); } } } if (missing_fids.isEmpty()) { return null; } // now go fetch the missing strings int size = missing_fids.size(); final long[] funcs = new long[size]; int i = 0; for (Long iter : missing_fids) { funcs[i++] = iter.longValue(); } // get function names AnWindow anWindow = AnWindow.getInstance(); final String[] names = anWindow.getFuncNames(funcs); // IPC!! ArrayList<StackState> missing = new ArrayList(); for (int ii = 0; ii < funcs.length; ii++) { long func = funcs[ii]; String name = names[ii]; StackState stackState = new StackState(name, func); missing.add(stackState); } addStates(missing); // internally synchronized return missing; } } ��������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/AnColorChooser.java������������������������������������0000644�0001750�0001750�00000031744�14517772113�022033� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; import org.gprofng.mpmt.AnDialog; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer.HelpAction; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Frame; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.EventObject; import javax.accessibility.AccessibleContext; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.ButtonGroup; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JColorChooser; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JTabbedPane; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; // YXXX some kind of synchronization needs to be added to color classes; they // are sometimes accessed from non-awt threads public final class AnColorChooser extends AnDialog implements ChangeListener, ListSelectionListener, MouseListener { private JColorChooser chooser; private JButton set_sel, set_all, reset, set_class; private JComboBox combo_class; private JTextField str_class; private JRadioButton idle_normal, idle_inv, idle_color; private JLabel idle_label; private ChooserStateView function_list; private final StateColorMap color_map; // Constructor public AnColorChooser(final AnWindow awindow, final Frame frame) { super(awindow, frame, AnLocale.getString("Function Colors"), false, null, null, null); color_map = new StateColorMap(); initComponents(); ok.setVisible(false); apply.setVisible(false); } // Initialize GUI components private void initComponents() { final JComponent preview; JPanel panel; final JPanel set_panel; final JPanel legend_panel; final ImageIcon icon; final ButtonGroup group; JButton closeButton = getDefaultButtons()[2]; // closeButton.setMnemonic(AnLocale.getString('e', "ColorChooserCloseButtonMN")); getRootPane().setDefaultButton(closeButton); // Color chooser panel chooser = new JColorChooser(); AnUtility.setAccessibleContext( chooser.getAccessibleContext(), AnLocale.getString("Color chooser")); chooser.setPreviewPanel(new JPanel()); chooser.getSelectionModel().addChangeListener(this); preview = (JComponent) chooser.getPreviewPanel().getParent(); if (preview != null) { preview.setBorder(null); } icon = new ImageIcon(StackState.createIcon(chooser.getColor(), 12, 12, true)); set_panel = new JPanel(); set_panel.setLayout(new BoxLayout(set_panel, BoxLayout.Y_AXIS)); // Set-all & Reset buttons set_sel = new JButton(AnLocale.getString("Set Selected Functions"), icon); AnUtility.setAccessibleContext(set_sel.getAccessibleContext(), set_sel.getText()); set_sel.setIconTextGap(8); set_sel.setMnemonic(AnLocale.getString('u', "MNEM_COLOR_CHOOSER_SET_SELECTED_FUNCTIONS")); set_sel.addActionListener(this); set_all = new JButton(AnLocale.getString("Set All Functions"), icon); AnUtility.setAccessibleContext(set_all.getAccessibleContext(), set_all.getText()); set_all.setIconTextGap(8); set_all.setMnemonic(AnLocale.getString('A', "MNEM_COLOR_CHOOSER_SET_ALL_FUNCTIONS")); set_all.addActionListener(this); reset = new JButton(AnLocale.getString("Reset Default Colors")); AnUtility.setAccessibleContext(reset.getAccessibleContext(), reset.getText()); reset.setMnemonic(AnLocale.getString('R', "MNEM_COLOR_CHOOSER_RESET_DEFAULT_COLORS")); reset.addActionListener(this); panel = new JPanel(new GridLayout(1, 0, 4, 0)); panel.add(set_sel); panel.add(set_all); panel.add(reset); set_panel.add(panel); set_panel.add(Box.createVerticalStrut(4)); // Set class color panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); set_class = new JButton(AnLocale.getString("Set Functions:"), icon); AnUtility.setAccessibleContext(set_class.getAccessibleContext(), set_class.getText()); set_class.setIconTextGap(8); set_class.setMnemonic(AnLocale.getString('F', "MNEM_COLOR_CHOOSER_SET_FUNCTIONS")); set_class.addActionListener(this); panel.add(set_class); combo_class = new JComboBox(ColorRule.SETC_STR); AnUtility.setAccessibleContext( combo_class.getAccessibleContext(), AnLocale.getString("Function filter")); panel.add(combo_class); str_class = new JTextField("", 10); AnUtility.setAccessibleContext( str_class.getAccessibleContext(), AnLocale.getString("Function text")); panel.add(str_class); set_panel.add(panel); set_panel.add(Box.createVerticalStrut(4)); set_panel.add(new JSeparator(SwingConstants.HORIZONTAL)); set_panel.add(Box.createVerticalStrut(4)); // Set CPU idle color idle_normal = new JRadioButton(AnLocale.getString("Normal", "COLOR_CHOOSER_NORMAL"), true); AnUtility.setAccessibleContext(idle_normal.getAccessibleContext(), idle_normal.getText()); idle_normal.setMnemonic(AnLocale.getString('N', "MNEM_COLOR_CHOOSER_NORMAL")); idle_normal.addActionListener(this); idle_inv = new JRadioButton(AnLocale.getString("Invisible"), false); AnUtility.setAccessibleContext(idle_inv.getAccessibleContext(), idle_inv.getText()); idle_inv.setMnemonic(AnLocale.getString('I', "MNEM_COLOR_CHOOSER_INVISIBLE")); idle_inv.addActionListener(this); idle_color = new JRadioButton(AnLocale.getString("Selected Color"), false); AnUtility.setAccessibleContext(idle_color.getAccessibleContext(), idle_color.getText()); idle_color.setMnemonic(AnLocale.getString('o', "MNEM_COLOR_CHOOSER_SELECTED_COLOR")); idle_color.addActionListener(this); idle_label = new JLabel(icon); AnUtility.setAccessibleContext( idle_label.getAccessibleContext(), AnLocale.getString("Selected Color")); group = new ButtonGroup(); group.add(idle_normal); group.add(idle_inv); group.add(idle_color); panel = new JPanel(); panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS)); final JLabel lbl = new JLabel(AnLocale.getString("Set CPU Idle Events Color:")); panel.add(lbl); lbl.getAccessibleContext().setAccessibleName(AnLocale.getString("CPU Idle Events Color")); lbl.getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Set CPU Idle Events Color")); panel.add(idle_normal); panel.add(idle_inv); panel.add(idle_color); panel.add(idle_label); panel.add(Box.createGlue()); set_panel.add(panel); // Function List Pane function_list = new ChooserStateView(color_map); function_list.addListSelectionListener(this); function_list.addMouseListener(this); JScrollPane functionListPane = new AnJScrollPane(function_list); HelpAction helpAction = new HelpAction(AnVariable.HELP_TabsLegend); panel.registerKeyboardAction( helpAction, "help", KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); panel.registerKeyboardAction( helpAction, "help", KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), JComponent.WHEN_FOCUSED); panel.registerKeyboardAction( helpAction, "help", KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), JComponent.WHEN_IN_FOCUSED_WINDOW); AccessibleContext context = functionListPane.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Function List")); context.setAccessibleDescription(AnLocale.getString("Function List")); context = function_list.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Function List")); context.setAccessibleDescription(AnLocale.getString("Function List")); // Legend panel to display functions and related colors legend_panel = new JPanel(); legend_panel.setLayout(new BoxLayout(legend_panel, BoxLayout.Y_AXIS)); JTabbedPane pane = new JTabbedPane(); pane.addTab(AnLocale.getString("Legend"), functionListPane); AnUtility.setAccessibleContext(pane.getAccessibleContext(), AnLocale.getString("Legend")); legend_panel.add(pane); // Set chooser outline panel = new JPanel(new BorderLayout()); panel.add(chooser, BorderLayout.WEST); panel.add(legend_panel, BorderLayout.CENTER); panel.add(set_panel, BorderLayout.SOUTH); setAccessory(panel); } // Action performed @Override public void actionPerformed(final ActionEvent event) { final String cmd = event.getActionCommand(); if (cmd.equals(AnLocale.getString("Set Selected Functions"))) { int indices[] = function_list.getSelectedIndices(); int size = function_list.getModel().getSize(); Color color = chooser.getColor(); if (false /* indices.length == size && size>0 */) { // treat "ctrl-a" as all color_map.setRuleAllFunctions(color); } else { ArrayList<ColorRule> rules = new ArrayList(); for (int jj = 0; jj < indices.length; jj++) { int ii = indices[jj]; StackState state = function_list.getState(ii); if (state != null) { ColorRule rule = new ColorRule(color, ColorRule.SETC_MATCHES, state.getName(), false); rules.add(rule); } } color_map.setRules(rules); } } else if (cmd.equals(AnLocale.getString("Set All Functions"))) { color_map.setRuleAllFunctions(chooser.getColor()); } else if (cmd.equals(AnLocale.getString("Reset Default Colors"))) { color_map.restoreToDefault(); } else if (cmd.equals(AnLocale.getString("Set Functions:"))) { String spec = str_class.getText(); spec = spec.trim(); if (!spec.isEmpty()) { color_map.setRule(chooser.getColor(), combo_class.getSelectedIndex(), spec, false); } } else if (cmd.equals(AnLocale.getString("Normal"))) { window.setCPUIdleColor(false, null); // FIXUP: REARCH } else if (cmd.equals(AnLocale.getString("Invisible"))) { window.setCPUIdleColor(true, null); // FIXUP: REARCH } else if (cmd.equals(AnLocale.getString("Selected Color"))) { window.setCPUIdleColor(true, chooser.getColor()); // FIXUP: REARCH } } // Update color from the color chooser @Override public void stateChanged(final ChangeEvent event) { final ImageIcon icon; icon = new ImageIcon(StackState.createIcon(chooser.getColor(), 12, 12, true)); set_class.setIcon(icon); set_sel.setIcon(icon); set_all.setIcon(icon); idle_label.setIcon(icon); } // (MUST BE CALLED ON AWT THREAD) private void funcSelChanged(EventObject event) { final JList list; final StackState state; if (event.getSource() instanceof StackView) { // ChooserStateView list = (StackView) event.getSource(); state = (StackState) list.getSelectedValue(); } else { // XXXmpview, figure this out... // System.err.println("XXXmpview colorchooser: eventsource unknown"); return; } if (state == null) { return; } setSelectedFunction(state.getNumber()); } @Override public void valueChanged(final ListSelectionEvent event) { funcSelChanged(event); } public final StateColorMap getColorMap() { return color_map; } // (MUST BE CALLED ON AWT THREAD) // <number> should be Histable::Function* (not Function->id) public void setSelectedFunction(long number) { Color c = color_map.getFuncColor(number); function_list.setSelectedFunction(number); chooser.setColor(c); } @Override public void mouseClicked(MouseEvent event) { if (!SwingUtilities.isLeftMouseButton(event)) { return; } funcSelChanged(event); } @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseExited(MouseEvent e) {} } ����������������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/StateColorMap.java�������������������������������������0000644�0001750�0001750�00000003060�14517772113�021656� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; import java.awt.Color; public final class StateColorMap extends ColorMap { private final int rgb_min[] = {110, 120, 200}; private final int rgb_max[] = {195, 195, 255}; private final int max_brightness = 225 * 3; // max possible is 255*3; public StateColorMap() {} @Override protected Color getBaseColor(String name) { Color c; int hc = name.hashCode(); double rgb[] = new double[3]; double brightness = 0; for (int ii = 0; ii < 3; ii++) { rgb[ii] = ((hc >> 8 * ii) & 0xff) / 256.0 * (rgb_max[ii] - rgb_min[ii]) + (double) rgb_min[ii]; brightness += rgb[ii]; } if (brightness > max_brightness) { double dim_factor = max_brightness / brightness; for (int ii = 0; ii < 3; ii++) { rgb[ii] *= dim_factor; } } c = new Color((int) rgb[0], (int) rgb[1], (int) rgb[2]); return c; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/ColorRule.java�����������������������������������������0000644�0001750�0001750�00000004352�14517772113�021054� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; import org.gprofng.mpmt.AnLocale; import java.awt.Color; import java.util.regex.Pattern; // This class is immutable public final class ColorRule { public static final String[] SETC_STR = { // YXXX indices must match SETC_* definitions below AnLocale.getString("Starts with"), AnLocale.getString("Contains"), AnLocale.getString("Ends with"), AnLocale.getString("Regular Exp."), AnLocale.getString("Matches exactly") }; public static final int SETC_ALL = -1; public static final int SETC_START = 0; public static final int SETC_CONTAIN = 1; public static final int SETC_END = 2; public static final int SETC_REGEXP = 3; public static final int SETC_MATCHES = 4; private final int type; // SETC_* definition private final String text; private final Color color; private final boolean isDefault; protected final Pattern reg_exp; // may be null public ColorRule(Color _color, int _type, String _nametext, boolean _isDefault) { type = _type; text = _nametext; color = _color; isDefault = _isDefault; reg_exp = null; } public ColorRule( Color _color, int _type, String _nametext, boolean _isDefault, Pattern _reg_exp) { type = _type; text = _nametext; color = _color; isDefault = _isDefault; reg_exp = _reg_exp; } public int getType() { return type; } public String getText() { return text; } public Color getColor() { return color; } public boolean getIsDefault() { return isDefault; } public Pattern getRegExpr() { return reg_exp; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statecolors/StackView.java�����������������������������������������0000644�0001750�0001750�00000035262�14517772113�021052� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statecolors; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.filter.FilterClause; import org.gprofng.mpmt.settings.ViewModeSetting; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Component; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Vector; import javax.swing.AbstractAction; import javax.swing.DefaultListCellRenderer; import javax.swing.ImageIcon; import javax.swing.JList; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; // Stack displayed as Colored boxes labeled with PC names public class StackView extends JList { protected final StateColorMap color_map; private String addFilterString = AnLocale.getString("Add Filter: "); private String viewName = AnLocale.getString("Call Stack"); protected long stackId = -1; private final String exclude_PC_stack = AnLocale.getString("Include only events not containing the current PC stack"); private final String include_PC_stack = AnLocale.getString("Include only events containing the current PC stack"); private final String filter_exclude_PC_stack = addFilterString + exclude_PC_stack; private final String filter_include_PC_stack = addFilterString + include_PC_stack; private final String exclude_function_stack = AnLocale.getString("Include only events not containing the current function stack"); private final String include_function_stack = AnLocale.getString("Include only events containing the current function stack"); private final String filter_exclude_function_stack = addFilterString + exclude_function_stack; private final String filter_include_function_stack = addFilterString + include_function_stack; // Constructor public StackView(final StateColorMap color_map) { this.color_map = color_map; AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Stack View")); ListRenderer lrend; lrend = new ListRenderer(); setCellRenderer(lrend); // setBackground(lrend.getBackground()); // XXXmpview can this be done later, like in setStates? Font font = new Font("Monospaced", Font.PLAIN, getFont().getSize()); setFont(font); setFixedCellHeight(font.getSize() < 17 ? 17 : font.getSize()); KeyStroke keyStroke = KeyboardShortcuts.contextMenuActionShortcut; getInputMap().put(keyStroke, keyStroke); getActionMap() .put( keyStroke, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { StackViewPopupListener popupListener = new StackViewPopupListener(AnWindow.getInstance()); popupListener.showPopup(StackView.this, 0, 0); } }); addKeyListener( new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { AnWindow.getInstance().setSelectedView(AnDisplay.DSP_Source); } } }); setSelectionMode( ListSelectionModel.SINGLE_SELECTION); // Allow only single line selection for now. } public void setStackId(final long id) { this.stackId = id; } // Set components public void setStates(Vector<StackState> sv_state, int index) { int size = sv_state.size(); setListData(sv_state); if (size == 0) { return; } // Set selected function if (index == -1) { clearSelection(); ensureIndexIsVisible(0); } else { index = Math.max(index, 0); index = Math.min(index, size - 1); setSelectedIndex(index); ensureIndexIsVisible(index); } } // Clear list public void reset() { setListData(new Vector<StackState>()); } // Set selected function public StackState getSelectedState() { return (StackState) getSelectedValue(); } // Set selected function public void setSelectedFunction(long func) { StackState state; ListModel data = getModel(); if (data == null) return; state = (StackState) getSelectedValue(); if ((state != null) && (state.getNumber() == func)) return; clearSelection(); int ii; for (ii = 0; ii < data.getSize(); ii++) { state = (StackState) data.getElementAt(ii); if (state.getNumber() == func) { setSelectedValue(state, true); // could do a hashmap break; } } // repaint(); } // List renderer protected class ListRenderer extends DefaultListCellRenderer { @Override public Component getListCellRendererComponent( JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); setText(value.toString()); StackState svstate = (StackState) value; Color color = color_map.getFuncColor(svstate.getNumber()); setIcon(new ImageIcon(StackState.createContigIcon(color))); setBorder(null); return this; } } public class StackViewPopupListener extends MouseAdapter implements PopupMenuListener { private AnWindow window; public StackViewPopupListener(AnWindow w) { window = w; } @Override public void mousePressed(MouseEvent e) { maybeShowPopup(e); } // public void mouseReleased(MouseEvent e) { // maybeShowPopup(e); // } public void maybeShowPopup(MouseEvent e) { showPopup(e.getComponent(), e.getX(), e.getY()); } public void showPopup(Component component, int x, int y) { JPopupMenu popup = createStackViewPopupMenu(); popup.show(component, x, y); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuCanceled(PopupMenuEvent e) {} class ShowSource extends AbstractAction { public ShowSource() { super(AnLocale.getString("Show Source")); } @Override public void actionPerformed(ActionEvent ev) { window.setSelectedView(AnDisplay.DSP_Source); } } class ShowDisasm extends AbstractAction { public ShowDisasm() { super(AnLocale.getString("Show Disassembly")); } @Override public void actionPerformed(ActionEvent ev) { window.setSelectedView(AnDisplay.DSP_Disassembly); } } class FilterByStackId extends AbstractAction { private boolean isExclude; public FilterByStackId(boolean isE) { super(isE ? filter_exclude_PC_stack : filter_include_PC_stack); isExclude = isE; } @Override public void actionPerformed(ActionEvent ev) { String clause = "("; clause += stackId; clause += ")"; String stack = "STACKID"; clause = "(" + clause + "==" + stack + ")"; if (isExclude) { clause = "(!" + clause + ")"; } String shortName = viewName + ": " + AnLocale.getString("Current PC Stack"); String longName; if (isExclude) { longName = filter_exclude_PC_stack; } else { longName = filter_include_PC_stack; } window .getFilters() .addClause( shortName, longName, clause, FilterClause.Kind.STANDARD); // Put the string in text field } } class FilterByStack extends AbstractAction { private boolean isExclude; public FilterByStack(boolean isE) { super(isE ? filter_exclude_function_stack : filter_include_function_stack); isExclude = isE; } @Override public void actionPerformed(ActionEvent ev) { ListModel model = getModel(); long[] funcs = new long[model.getSize()]; for (int i = 0; i < model.getSize(); i++) { StackState state = (StackState) model.getElementAt(i); funcs[model.getSize() - i - 1] = state.getNumber(); } long[] funcIds = window.getFuncIds(funcs); String clause = "("; for (int i = 0; i < funcIds.length; i++) { clause += funcIds[i]; if (i != funcIds.length - 1) { clause += ","; } } clause += ")"; String stack = "USTACK"; if (window.getSettings().getViewModeSetting().get() == ViewModeSetting.ViewMode.MACHINE) { stack = "MSTACK"; } if (window.getSettings().getViewModeSetting().get() == ViewModeSetting.ViewMode.EXPERT) { stack = "XSTACK"; } clause = "(" + clause + " ORDERED IN " + stack + ")"; if (isExclude) { clause = "(!" + clause + ")"; } String shortName = viewName + ": " + AnLocale.getString("Current Function Stack"); String longName; if (isExclude) { longName = filter_exclude_function_stack; } else { longName = filter_include_function_stack; } window .getFilters() .addClause( shortName, longName, clause, FilterClause.Kind.STANDARD); // Put the string in text field } } class FilterByFunction extends AbstractAction { public FilterByFunction() { super( AnLocale.getString( addFilterString + "Include only stacks containing the selected function")); } @Override public void actionPerformed(ActionEvent ev) { long ID = window.getSelectedObject().getSelObjV2("FUNCTION"); String clause = "(" + ID + ")"; String stack = "USTACK"; if (window.getSettings().getViewModeSetting().get() == ViewModeSetting.ViewMode.MACHINE) { stack = "MSTACK"; } if (window.getSettings().getViewModeSetting().get() == ViewModeSetting.ViewMode.EXPERT) { stack = "XSTACK"; } clause = "(" + clause + " IN " + stack + ")"; String shortName = viewName + ": " + AnLocale.getString("Selected Function"); String longName = AnLocale.getString("Include only stacks containing the selected function"); window .getFilters() .addClause( shortName, longName, clause, FilterClause.Kind.STANDARD); // Put the string in text field } } class FilterByPC extends AbstractAction { public FilterByPC() { super( AnLocale.getString(addFilterString + "Include only stacks containing the selected PC")); } @Override public void actionPerformed(ActionEvent ev) { long LID = window.getSelectedObject().getSelObjV2("INSTRUCTION"); String clause = "(" + LID + ")"; String stack = "USTACK"; if (window.getSettings().getViewModeSetting().get() == ViewModeSetting.ViewMode.MACHINE) { stack = "MSTACK"; } if (window.getSettings().getViewModeSetting().get() == ViewModeSetting.ViewMode.EXPERT) { stack = "XSTACK"; } clause = "(" + clause + " IN " + stack + "I)"; String shortName = viewName + ": " + AnLocale.getString("Selected PC"); String longName = AnLocale.getString("Include only stacks containing the selected PC"); window .getFilters() .addClause( shortName, longName, clause, FilterClause.Kind.STANDARD); // Put the string in text field } } class RemoveLastFilter extends AbstractAction { public RemoveLastFilter() { super(AnLocale.getString("Undo Last Filter")); } @Override public void actionPerformed(ActionEvent ev) { window.getFilters().undoLastFilteraction(); } } class RedoLastFilter extends AbstractAction { public RedoLastFilter() { super(AnLocale.getString("Redo Filter")); } @Override public void actionPerformed(ActionEvent ev) { window.getFilters().redoLastFilteraction(); } } class RemoveAllFilter extends AbstractAction { public RemoveAllFilter() { super(AnLocale.getString("Remove All Filters")); } @Override public void actionPerformed(ActionEvent ev) { window.getFilters().addClause(FilterClause.getNoFiltersClause(), false); } } private JPopupMenu createStackViewPopupMenu() { JMenuItem menuItem; JPopupMenu popup = new JPopupMenu(); menuItem = new JMenuItem(new ShowSource()); popup.add(menuItem); menuItem = new JMenuItem(new ShowDisasm()); popup.add(menuItem); popup.addSeparator(); menuItem = new JMenuItem(new FilterByStack(false)); popup.add(menuItem); menuItem = new JMenuItem(new FilterByStack(true)); popup.add(menuItem); if (stackId != -1) { menuItem = new JMenuItem(new FilterByStackId(false)); popup.add(menuItem); menuItem = new JMenuItem(new FilterByStackId(true)); popup.add(menuItem); } menuItem = new JMenuItem(new FilterByFunction()); popup.add(menuItem); menuItem = new JMenuItem(new FilterByPC()); popup.add(menuItem); menuItem = new JMenuItem(new RemoveLastFilter()); menuItem.setEnabled(window.getFilters().canUndoLastFilter()); popup.add(menuItem); menuItem = new JMenuItem(new RedoLastFilter()); menuItem.setEnabled(window.getFilters().canRedoLastFilter()); popup.add(menuItem); menuItem = new JMenuItem(new RemoveAllFilter()); menuItem.setEnabled(window.getFilters().canRemoveAllFilters()); popup.add(menuItem); return popup; } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/welcome/�����������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�015466� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/welcome/WelcomeInnerPanel.form�������������������������������������0000644�0001750�0001750�00000003742�14517772113�021632� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-67,0,0,2,-63"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Form> ������������������������������gprofng-gui-1.0/org/gprofng/mpmt/welcome/WelcomePanel.java������������������������������������������0000644�0001750�0001750�00000004500�14517772113�020605� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.welcome; import org.gprofng.analyzer.AnEnvironment; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; public class WelcomePanel extends javax.swing.JPanel { private final WelcomeInnerPanel welcomeInnerPanel; public WelcomePanel() { initComponents(); setBackground(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); setLayout(new GridBagLayout()); welcomeInnerPanel = new WelcomeInnerPanel(); welcomeInnerPanel.setMinimumSize(new Dimension(10, 10)); welcomeInnerPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(welcomeInnerPanel, gridBagConstraints); } @Override public void requestFocus() { welcomeInnerPanel.requestFocus(); } protected void doCompute() { welcomeInnerPanel.doCompute(); } protected void enableActions(boolean enable) { welcomeInnerPanel.enableActions(enable); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.GridBagLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/welcome/WelcomeView.java�������������������������������������������0000644�0001750�0001750�00000011065�14517772113�020464� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.welcome; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.util.ArrayList; import java.util.List; public final class WelcomeView extends AnDisplay implements ExportSupport, AnChangeListener { private final WelcomePanel welcomePanel; // Constructor public WelcomeView() { super(AnWindow.getInstance(), AnDisplay.DSP_Welcome, AnVariable.HELP_Welcome); setLayout(new BorderLayout()); welcomePanel = new WelcomePanel(); add(welcomePanel, BorderLayout.CENTER); setAccessibility(AnLocale.getString("Welcome View")); AnEventManager.getInstance().addListener(this); } @Override public void requestFocus() { welcomePanel.requestFocus(); } // Initialize GUI components @Override protected void initComponents() {} public String getShortDescr() { return "Welcome short description..."; } public String getLongDescr() { return "<HTML><b>Welcome View</b><br>Welcome long" + " description......<br>..............................................<br>..............................................</HTML>"; } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("WelcomeDisp stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; welcomePanel.enableActions(false); break; case EXPERIMENTS_LOADED_FAILED: welcomePanel.enableActions(true); break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } welcomePanel.enableActions(true); break; case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case FILTER_CHANGED: case SETTING_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void doCompute() { // System.out.println("WelcomeDisp:doCompute: " + selected + " " + computed); AnUtility.checkIfOnAWTThread(false); if (!selected) { // Not selected return; } if (!computed) { // Not computed welcomePanel.doCompute(); computed = true; } } @Override public List<ExportFormat> getSupportedExportFormats() { List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return false; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/welcome/WelcomeInnerPanel.java�������������������������������������0000644�0001750�0001750�00000045651�14517772113�021615� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.welcome; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnAction; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.ExperimentPickListElement; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Box.Filler; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; public class WelcomeInnerPanel extends javax.swing.JPanel { private final int MOST_RECENT_EXP_LIST_SIZE = 8; private static final Font font12 = new JLabel().getFont().deriveFont(12f); private static final Font bold12Font = font12.deriveFont(Font.BOLD); private static final Font plain12Font = font12.deriveFont(Font.PLAIN); private static final Font bold16Font = bold12Font.deriveFont(16f); private static final Font bold17Font = bold12Font.deriveFont(17f); private static final Font bold18Font = bold12Font.deriveFont(18f); private static final Font bold22Font = bold12Font.deriveFont(22f); private static final Font plain16Font = plain12Font.deriveFont(16f); private static final Font plain17Font = plain12Font.deriveFont(17f); private static final Font plain18Font = plain12Font.deriveFont(18f); private static final Font plain19Font = plain12Font.deriveFont(19f); private static final Font plain22Font = plain12Font.deriveFont(22f); private JPanel leftPanel; private JPanel rightPanel; private ImageIcon backgroundImageIcon; private JLabel createExperimentTitleLabel; private JLabel viewExperimentTitleLabel; private WelcomeButton profileAppButton; private WelcomeButton profileRunningAppButton; private WelcomeButton openExistingExperimentButton; private WelcomeButton openRecentExperimentButton; private List<WelcomeButton> recentExperimentsButtons; private WelcomeButton compareExperimentsButton; private WelcomeButton connectButton; public WelcomeInnerPanel() { backgroundImageIcon = new ImageIcon( getClass().getResource("/org/gprofng/mpmt/icons/welcomeBackgroundShadow.png")); initComponents(); buildForeground(); buildBackground(); } @Override public void requestFocus() { profileAppButton.requestFocus(); // First button } protected void enableActions(boolean enable) { if (!enable) { setConnected(false); connectButton.setEnabled(false); } else { setConnected(Analyzer.getInstance().isConnected()); connectButton.setEnabled(false); } } private void setConnected(boolean connected) { createExperimentTitleLabel.setEnabled(connected); viewExperimentTitleLabel.setEnabled(connected); profileAppButton.setEnabled(connected); profileRunningAppButton.setEnabled(false); // profileKernelButton.setEnabled(connected && // Analyzer.getInstance().isKernelProfilingEnabled()); openExistingExperimentButton.setEnabled(connected); if (openRecentExperimentButton != null) { openRecentExperimentButton.setEnabled(connected); } if (recentExperimentsButtons != null) { for (WelcomeButton welcomeButton : recentExperimentsButtons) { welcomeButton.setEnabled(connected); } } compareExperimentsButton.setEnabled(connected); } private void buildBackground() { GridBagConstraints gridBagConstraints = new GridBagConstraints(); JLabel iconLabel = new JLabel(); AnUtility.setAccessibleContext(iconLabel.getAccessibleContext(), " "); iconLabel.setIcon(backgroundImageIcon); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 1; gridBagConstraints.gridheight = 1; gridBagConstraints.anchor = GridBagConstraints.CENTER; add(iconLabel, gridBagConstraints); } private void buildForeground() { GridBagConstraints gridBagConstraints; JPanel foregroundPanel = new JPanel(); Dimension dim = new Dimension(backgroundImageIcon.getIconWidth(), backgroundImageIcon.getIconHeight()); foregroundPanel.setMinimumSize(dim); foregroundPanel.setPreferredSize(dim); foregroundPanel.setMaximumSize(dim); foregroundPanel.setOpaque(false); foregroundPanel.setLayout(new GridBagLayout()); buildLabelsAndPanels(foregroundPanel); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 2; gridBagConstraints.gridheight = 2; gridBagConstraints.anchor = GridBagConstraints.CENTER; add(foregroundPanel, gridBagConstraints); } private void buildLabelsAndPanels(JPanel foregroundPanel) { GridBagConstraints gridBagConstraints; JPanel topLabelPanel = new JPanel(); topLabelPanel.setLayout(new GridBagLayout()); topLabelPanel.setOpaque(false); JLabel label = new JLabel(" "); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setForeground(AnEnvironment.WELCOME_MAIN_LABEL_COLOR); label.setFont(bold16Font); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(0, 0, 0, 0); topLabelPanel.add(label, gridBagConstraints); JLabel label2 = new JLabel(" "); AnUtility.setAccessibleContext(label2.getAccessibleContext(), label2.getText()); label2.setForeground(AnEnvironment.WELCOME_MAIN_LABEL_COLOR); label2.setFont(plain16Font); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(0, 4, 0, 0); topLabelPanel.add(label2, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.insets = new Insets(60, 200, 0, 0); foregroundPanel.add(topLabelPanel, gridBagConstraints); JLabel label3 = new JLabel(AnLocale.getString("Welcome")); AnUtility.setAccessibleContext(label3.getAccessibleContext(), label3.getText()); label3.setForeground(AnEnvironment.WELCOME_MAIN_LABEL_COLOR); label3.setFont(bold22Font); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(50, 75, 0, 0); foregroundPanel.add(label3, gridBagConstraints); leftPanel = new JPanel(); leftPanel.setLayout(new GridBagLayout()); buildLeftPanel(leftPanel); leftPanel.setOpaque(false); // leftPanel.setBackground(Color.red); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(16, 132, 0, 0); foregroundPanel.add(leftPanel, gridBagConstraints); rightPanel = new JPanel(); rightPanel.setLayout(new GridBagLayout()); buildRightPanel(rightPanel); rightPanel.setOpaque(false); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weighty = 1.0; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(16, 40, 0, 0); foregroundPanel.add(rightPanel, gridBagConstraints); } private void buildLeftPanel(JPanel panel) { AnAction action; panel.removeAll(); int gridy = 0; createExperimentTitleLabel = addSectionTitleLabel(panel, AnLocale.getString("Create Experiments"), gridy++); action = AnWindow.getInstance().getProfileApplicationAction(); profileAppButton = addActionButton(panel, gridy++, action.getTextNoDots(), action.getTooltipText(), action); action = AnWindow.getInstance().getProfileRunningProcessAction(); profileRunningAppButton = addActionButton(panel, gridy++, action.getTextNoDots(), action.getTooltipText(), action); addSpace(panel, 14, gridy++); viewExperimentTitleLabel = addSectionTitleLabel(panel, AnLocale.getString("View Experiments"), gridy++); action = AnWindow.getInstance().getOpenExperimentAction(); openExistingExperimentButton = addActionButton(panel, gridy++, action.getTextNoDots(), action.getTooltipText(), action); List<ExperimentPickListElement> recentExperiments = UserPref.getInstance() .getExperimentsPicklists() .getPicklist() .getRecentExperiments(MOST_RECENT_EXP_LIST_SIZE); if (!recentExperiments.isEmpty()) { String buttonText = AnLocale.getString("Open Recent Experiment"); String buttonTT = AnLocale.getString("Click an experiment name below to reopen it"); openRecentExperimentButton = addActionButton(panel, gridy++, buttonText, buttonTT, null); if (Analyzer.getInstance().isConnected()) { recentExperimentsButtons = new ArrayList<WelcomeButton>(); for (ExperimentPickListElement experimentElement : recentExperiments) { String displayName = AnUtility.basename(experimentElement.getPath()); int length = displayName.length(); if (length > 25) { displayName = displayName.substring(0, 16) + "..." + displayName.substring(length - 7); } recentExperimentsButtons.add( addExperimentButton( panel, gridy++, displayName, experimentElement.getToolTip(), new OpenExistingExperimentAction(experimentElement))); } } } action = AnWindow.getInstance().getCompareExperimentsAction(); compareExperimentsButton = addActionButton(panel, gridy++, action.getTextNoDots(), action.getTooltipText(), action); addButtomFill(panel, gridy++); addRightFill(panel); } private void buildRightPanel(JPanel panel) { AnAction action; int gridy = 0; addSectionTitleLabel(panel, AnLocale.getString("Remote"), gridy++); action = AnWindow.getInstance().getConnectAction(); connectButton = addActionButton(panel, gridy++, action.getTextNoDots(), action.getTooltipText(), action); addSpace(panel, 14, gridy++); addSectionTitleLabel(panel, AnLocale.getString("Learn More"), gridy++); action = AnWindow.getInstance().getHelpAnalyzerAction(); addActionButton(panel, gridy++, action.getTextNoDots(), action.getTooltipText(), action); action = AnWindow.getInstance().getHelpNewFeaturesAction(); addActionButton(panel, gridy++, action.getTextNoDots(), action.getTooltipText(), action); action = AnWindow.getInstance().getHelpInformationMapAction(); addActionButton(panel, gridy++, action.getTextNoDots(), action.getTooltipText(), action); addButtomFill(panel, gridy++); } /* * Picklist changes */ public void doCompute() { // System.out.println("WelcomeInnerPanel doCompute ********************"); AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { buildLeftPanel(leftPanel); setConnected(Analyzer.getInstance().isConnected()); validate(); repaint(); } }); } private void addSpace(JPanel panel, int space, int gridy) { Dimension dim = new Dimension(space, space); Filler filler = new Filler(dim, dim, dim); GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridy; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 0); panel.add(filler, gridBagConstraints); } private JLabel addSectionTitleLabel(JPanel panel, String title, int gridy) { JLabel label = new JLabel(title); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setFont(bold18Font); label.setForeground(AnEnvironment.WELCOME_MAIN_LABEL_COLOR); GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridy; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); panel.add(label, gridBagConstraints); return label; } private WelcomeButton addActionButton( JPanel panel, int gridy, String labelTxt, String labelTT, Action action) { WelcomeButton button = new WelcomeButton( labelTxt, labelTT, action, 5, AnEnvironment.WELCOME_BUTTON_ACTION_COLOR, Font.BOLD); JLabel label = new JLabel(); label.setIcon(new ImageIcon(getClass().getResource("/org/gprofng/mpmt/icons/tab.png"))); GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridy; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 0, 0); panel.add(label, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = gridy; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(4, 4, 0, 0); panel.add(button, gridBagConstraints); return button; } private WelcomeButton addExperimentButton( JPanel panel, int gridy, String labelTxt, String labelTT, Action action) { WelcomeButton button = new WelcomeButton( labelTxt, labelTT, action, 4, AnEnvironment.WELCOME_BUTTON_EXPERIMENT_COLOR, Font.BOLD); JLabel label = new JLabel(); if (labelTxt.endsWith("erg")) { label.setIcon( new ImageIcon(getClass().getResource("/org/gprofng/mpmt/icons/expgroup.png"))); } else { label.setIcon( new ImageIcon(getClass().getResource("/org/gprofng/mpmt/icons/experiment.png"))); } AnUtility.setAccessibleContext(label.getAccessibleContext(), labelTxt); GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = gridy; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 4, 0, 0); panel.add(label, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = gridy; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 4, 0, 0); panel.add(button, gridBagConstraints); return button; } private void addButtomFill(JPanel panel, int gridy) { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = gridy; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; panel.add(new JLabel(), gridBagConstraints); } private void addRightFill(JPanel panel) { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 100; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.insets = new Insets(0, 0, 0, 300); Dimension dim = new Dimension(0, 0); Filler filler = new Filler(dim, dim, dim); panel.add(filler, gridBagConstraints); } class OpenExperimentAction implements ActionListener { // @Override @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().openExperimentAction(); } } class ConnectRemoteHostAction implements ActionListener { // @Override @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().connectAction(); } } class CompareExperimentsAction implements ActionListener { // @Override @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().compareExperimentsAction(); } } class OpenExistingExperimentAction extends AbstractAction { private ExperimentPickListElement experimentElement; public OpenExistingExperimentAction(ExperimentPickListElement experimentElement) { this.experimentElement = experimentElement; } @Override public void actionPerformed(ActionEvent e) { ArrayList<String> list = new ArrayList<String>(); list.add(experimentElement.getPath()); String confPath; boolean always; if (experimentElement.getConfPath() != null) { confPath = experimentElement.getConfPath(); always = true; } else { confPath = UserPref.getAsWhenClosedConfigPath(experimentElement.getPath()); always = false; } AnWindow.getInstance() .loadExperimentList( list, false, experimentElement.getWorkingDirectory(), true, confPath, always); } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.GridBagLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ���������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/welcome/WelcomeButton.java�����������������������������������������0000644�0001750�0001750�00000006407�14517772113�021031� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.welcome; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.Action; import javax.swing.JButton; import javax.swing.UIManager; public class WelcomeButton extends JButton { private final Color foreground; public WelcomeButton( String text, String tooltip, Action action, int txtSize, Color foreground, int style) { super(action); setText(text); setToolTipText(tooltip); setIcon(null); AnUtility.setAccessibleContext(getAccessibleContext(), text); this.foreground = foreground; setBorder(null); setBorderPainted(false); setOpaque(false); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); setForeground(foreground); setFont( getFont() .deriveFont(12f)); // Use font size 12 for now. Doesn't resize with --fontsize option setFont(getFont().deriveFont(style)); setFont(getFont().deriveFont((float) getFont().getSize() + txtSize)); if (action != null) { addMouseListener( new MouseAdapter() { private Cursor oldCursor = null; // @Override @Override public void mouseEntered(MouseEvent e) { oldCursor = getCursor(); setCursor(new Cursor(Cursor.HAND_CURSOR)); setForeground(AnEnvironment.WELCOME_BUTTON_FOCUSED_COLOR); } // @Override @Override public void mouseExited(MouseEvent e) { setCursor(oldCursor); setForeground(WelcomeButton.this.foreground); } }); addKeyListener( new KeyAdapter() { @Override public void keyTyped(KeyEvent e) { if (e.getKeyChar() == KeyEvent.VK_ENTER) { actionListener.actionPerformed(null); } } }); } } @Override public void paint(Graphics g) { if (!isEnabled()) { Color saveColor = (Color) UIManager.getDefaults().get("Button.disabledText"); UIManager.getDefaults() .put("Button.disabledText", AnEnvironment.WELCOME_BUTTON_DISABLED_COLOR); super.paint(g); UIManager.getDefaults().put("Button.disabledText", saveColor); } else { super.paint(g); if (hasFocus()) { g.setColor(new Color(200, 200, 200)); g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); } } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/welcome/WelcomePanel.form������������������������������������������0000644�0001750�0001750�00000003741�14517772113�020635� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,52,0,0,1,-18"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Form> �������������������������������gprofng-gui-1.0/org/gprofng/mpmt/control_panel/�����������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�016671� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/control_panel/CPToolbarHandler.java��������������������������������0000644�0001750�0001750�00000002634�14517772113�022567� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.control_panel; import java.awt.event.ActionEvent; public interface CPToolbarHandler { public void selectLeft(); public void selectRight(); public void selectDown(); public void selectUp(); public void selectFind(); // TBR? public void selectFirst(); public void toggleMouseMode(); public int getZoomLevelMax(); public void genericZoomToLevel(int n); public void genericZoomIn(); public void genericZoomOut(); public void genericVZoomToLevel(int n); public void genericVZoomIn(); public void genericVZoomOut(); public void resetZoom(); public void undoZoom(); public void redoZoom(); public void zoomToCaliper(); public void chooseColors(); public void showContextMenu(ActionEvent ev); } ����������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/control_panel/CPFilterPanelHandler.java����������������������������0000644�0001750�0001750�00000001460�14517772113�023366� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.control_panel; public interface CPFilterPanelHandler { public void applyFilter(); public void revalidateFilteredData(); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/control_panel/CPToolbar.java���������������������������������������0000644�0001750�0001750�00000041342�14517772113�021270� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.control_panel; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnAction; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.toolbar.ToolBarFiller; import org.gprofng.mpmt.toolbar.ToolBarSeparator; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.zoomruler.ZoomRulerComponent; import org.gprofng.mpmt.util.zoomruler.ZoomRulerEvent; import org.gprofng.mpmt.util.zoomruler.ZoomRulerListener; import org.gprofng.mpmt.util.zoomruler.ZoomRulerOverlay; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JToggleButton; import javax.swing.JToolBar; import javax.swing.KeyStroke; public class CPToolbar extends JToolBar { // components private JToggleButton grabButton; private CPToolbarHandler handler; private final boolean showZoomUndo; private final boolean showZoomRedo; private final boolean showZoomControls; private ZoomRulerComponent hZoomRuler; private ZoomRulerComponent vZoomRuler; // Actions // FIXUP: actions should be moved to TimelineView and the action buttons should be added here in // this file. private AnAction zoomAction; private AnAction undoAction; private AnAction redoAction; private AnAction upOneAction; private AnAction downOneAction; private AnAction leftOneAction; private AnAction rightOneAction; /** Creates a new instance of MPIControlPanel */ public CPToolbar( CPToolbarHandler handler, boolean showZoomControls, boolean showZoomUndo, boolean showZoomRedo) { super(); this.handler = handler; this.showZoomUndo = showZoomUndo; this.showZoomRedo = showZoomRedo; this.showZoomControls = showZoomControls; init(); setOpaque(false); setBorder(null); } private void init() { JToolBar tb = this; tb.setFloatable(false); int mnem; String bname; String keytext; String modtext; JComponent tmp; AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Toolbar")); downOneAction = new AnAction( AnLocale.getString("Down One Event"), AnUtility.down_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (downOneAction.isEnabled()) { selectDown(); } } }); downOneAction.setKeyboardShortCut( null, "TIMELINE_DOWN", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false)); leftOneAction = new AnAction( AnLocale.getString("Left One Event"), AnUtility.back_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (leftOneAction.isEnabled()) { selectLeft(); } } }); leftOneAction.setKeyboardShortCut( null, "TIMELINE_LEFT", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false)); rightOneAction = new AnAction( AnLocale.getString("Right One Event"), AnUtility.forw_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (rightOneAction.isEnabled()) { selectRight(); } } }); rightOneAction.setKeyboardShortCut( null, "TIMELINE_RIGHT", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false)); upOneAction = new AnAction( AnLocale.getString("Up One Event"), AnUtility.up_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (upOneAction.isEnabled()) { selectUp(); } } }); upOneAction.setKeyboardShortCut( null, "TIMELINE_UP", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false)); zoomAction = new AnAction( AnLocale.getString("Zoom to Selected Time Range"), AnUtility.mtall_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (zoomAction.isEnabled()) { zoomToCaliper(); } } }); zoomAction.setKeyboardShortCut( null, "TIMELINE_ZOOM", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false)); grabButton = new JToggleButton(); grabButton.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); mnem = KeyEvent.VK_T; // TimelineView.java installs real handler keytext = KeyEvent.getKeyText(mnem); bname = AnLocale.getString("Toggle between Zoom and Pan mode") + " (" + keytext + ")"; grabButton.setName(bname); grabButton.getAccessibleContext().setAccessibleName(bname); grabButton.getAccessibleContext().setAccessibleDescription(bname); grabButton.setToolTipText(bname); // grabButton.setMnemonic(mnem); grabButton.setEnabled(true); grabButton.setIcon(AnUtility.panhand_icon); grabButton.setMargin(AnVariable.buttonMargin); grabButton.setBorderPainted(false); // grabButton.setSelected(true); grabButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent actionEvent) { // toggle between rubberbanding and grabbing mode toggleMouseMode(); } }); undoAction = new AnAction( AnLocale.getString("Undo Zoom Action"), AnUtility.undo_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (undoAction.isEnabled()) { undoZoom(); } } }); undoAction.setKeyboardShortCut( null, "TIMELINE_UNDO", KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0, false)); redoAction = new AnAction( AnLocale.getString("Redo Zoom Action"), AnUtility.redo_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (redoAction.isEnabled()) { redoZoom(); } } }); redoAction.setKeyboardShortCut( null, "TIMELINE_REDO", KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, InputEvent.SHIFT_DOWN_MASK, false)); if (showZoomControls) { vZoomRuler = new ZoomRulerComponent( ZoomRulerOverlay.VERTICAL_ORIENTATION, 2, // ZoomRulerOverlay.RULER_LD_DEFAULT, false, false, true); AnUtility.setAccessibleContext( vZoomRuler.getAccessibleContext(), AnLocale.getString("Vertical Zoom")); vZoomRuler.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); final ZoomRulerListener vzrl = new ZoomRulerListener() { @Override public void zoomChanged(ZoomRulerEvent event) { if (event.isUndo()) { undoZoom(); } else if (event.isRedo()) { redoZoom(); } else if (event.isLevelChange()) { int lev = event.getZoomLevel(); genericVZoomToLevel(lev); } else if (event.isLevelPlus()) { genericVZoomIn(); } else if (event.isLevelMinus()) { genericVZoomOut(); } else if (event.isReset()) { // resetZoom(); } else if (event.isPan()) { // if (event.getDirection() == ZoomRulerEvent.PAN_UP) // panUp(); // else if (event.getDirection() == ZoomRulerEvent.PAN_RIGHT) // panRight(); // else if (event.getDirection() == ZoomRulerEvent.PAN_DOWN) // panDown(); // else // PAN_LEFT // panLeft(); } } }; vZoomRuler.addZoomRulerListener(vzrl); tmp = vZoomRuler; // tmp.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); bname = AnLocale.getString("Adjust the Veritcal Zoom"); keytext = KeyEvent.getKeyText(KeyEvent.VK_PLUS); // TimelineView.java installs real handler modtext = KeyEvent.getKeyModifiersText(InputEvent.CTRL_MASK); bname += " (" + modtext + "-" + keytext; keytext = KeyEvent.getKeyText(KeyEvent.VK_MINUS); // TimelineView.java installs real handler bname += ", " + modtext + "-" + keytext + ")"; // tmp.getAccessibleContext().setAccessibleName(bname); // tmp.getAccessibleContext().setAccessibleDescription(bname); tmp.setToolTipText(bname); // tmp.setMnemonic(mnem); // tmp.setEnabled(true); hZoomRuler = new ZoomRulerComponent( ZoomRulerOverlay.HORIZONTAL_ORIENTATION, ZoomRulerOverlay.RULER_LD_DEFAULT, true, false, false); AnUtility.setAccessibleContext( hZoomRuler.getAccessibleContext(), AnLocale.getString("Horizontal Zoom")); hZoomRuler.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); final ZoomRulerListener hzrl = new ZoomRulerListener() { @Override public void zoomChanged(ZoomRulerEvent event) { if (event.isUndo()) { undoZoom(); } else if (event.isRedo()) { redoZoom(); } else if (event.isLevelChange()) { int lev = event.getZoomLevel(); genericZoomToLevel(lev); } else if (event.isLevelPlus()) { genericZoomIn(); } else if (event.isLevelMinus()) { genericZoomOut(); } else if (event.isReset()) { resetZoom(); } else if (event.isPan()) { // if (event.getDirection() == ZoomRulerEvent.PAN_UP) // panUp(); // else if (event.getDirection() == ZoomRulerEvent.PAN_RIGHT) // panRight(); // else if (event.getDirection() == ZoomRulerEvent.PAN_DOWN) // panDown(); // else // PAN_LEFT // panLeft(); } } }; hZoomRuler.addZoomRulerListener(hzrl); tmp = hZoomRuler; // tmp.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); bname = AnLocale.getString("Adjust the Horizontal Zoom"); keytext = KeyEvent.getKeyText(KeyEvent.VK_PLUS); // TimelineView.java installs real handler bname += " (" + keytext; keytext = KeyEvent.getKeyText(KeyEvent.VK_MINUS); // TimelineView.java installs real handler bname += ", " + keytext + ")"; // tmp.getAccessibleContext().setAccessibleName(bname); // tmp.getAccessibleContext().setAccessibleDescription(bname); tmp.setToolTipText(bname); // tmp.setMnemonic(mnem); // tmp.setEnabled(true); tb.add(vZoomRuler); tb.add(new ToolBarFiller(2)); tb.add(hZoomRuler); tb.add(new ToolBarFiller(2)); tb.add(zoomAction.createActionButton()); } // showZoomControls if (showZoomUndo) { tb.add(undoAction.createActionButton()); } if (showZoomRedo) { tb.add(redoAction.createActionButton()); } if (showZoomControls || showZoomUndo || showZoomRedo) { tb.add(new ToolBarSeparator(7, 6)); } tb.add(upOneAction.createActionButton()); tb.add(downOneAction.createActionButton()); tb.add(leftOneAction.createActionButton()); tb.add(rightOneAction.createActionButton()); // tb.add(grabButton); TBR? add(AnWindow.getInstance().getFunctionColorsAction().createActionButton()); tb.revalidate(); KeyStroke ks = KeyboardShortcuts.contextMenuActionShortcut; this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, ks); this.getActionMap() .put( ks, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != handler) { handler.showContextMenu(ev); } } }); } // --- Public API --- /** Turn on navigation controls */ public void enableNavigationButtons( boolean bleft, boolean bright, boolean bup, boolean bdown, boolean bfind) { // YXXX remove bfind? leftOneAction.setEnabled(bleft); rightOneAction.setEnabled(bright); upOneAction.setEnabled(bup); downOneAction.setEnabled(bdown); // zoomAction.setEnabled(bfind); } public void enableZoomToCaliperButton(boolean bfind) { zoomAction.setEnabled(bfind); } public void setZoomLevel(int level) { if (hZoomRuler == null) { return; // weird, caller thinks CPToolbar showZoomControls is true? } hZoomRuler.setZoomLevel(level); } public void setVZoomLevel(int level) { if (vZoomRuler == null) { return; // weird, caller thinks CPToolbar showZoomControls is true? } vZoomRuler.setZoomLevel(level); } public void setNumberOfLevels(int levels) { if (hZoomRuler == null) { return; // weird, caller thinks CPToolbar showZoomControls is true? } hZoomRuler.setNumberOfLevels(levels); } public void setVNumberOfLevels(int levels) { if (vZoomRuler == null) { return; // weird, caller thinks CPToolbar showZoomControls is true? } vZoomRuler.setNumberOfLevels(levels); } /** Turn on navigation controls */ public void enableGrabButton(boolean grab) { grabButton.setEnabled(grab); } public void addToolBarButton(JButton button) { JToolBar tb = this; tb.add(button); tb.revalidate(); } public void enableZoomUndoButton(boolean bfind) { undoAction.setEnabled(bfind); } public void enableZoomRedoButton(boolean bfind) { redoAction.setEnabled(bfind); } // --- wrappers for handler; allows handler to be dynamically replaced private void selectLeft() { handler.selectLeft(); } private void selectRight() { handler.selectRight(); } private void selectDown() { handler.selectDown(); } private void selectUp() { handler.selectUp(); } private void selectFind() { handler.selectFind(); } private void selectFirst() { // no button for this at this time handler.selectFirst(); } private void toggleMouseMode() { handler.toggleMouseMode(); } private void genericZoomIn() { handler.genericZoomIn(); } private void genericZoomOut() { handler.genericZoomOut(); } private void genericZoomToLevel(int n) { handler.genericZoomToLevel(n); } private void genericVZoomIn() { handler.genericVZoomIn(); } private void genericVZoomOut() { handler.genericVZoomOut(); } private void genericVZoomToLevel(int n) { handler.genericVZoomToLevel(n); } private void resetZoom() { handler.resetZoom(); } private void zoomToCaliper() { handler.zoomToCaliper(); } private void undoZoom() { handler.undoZoom(); } private void redoZoom() { handler.redoZoom(); } private void chooseColors() { handler.chooseColors(); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/control_panel/CPDetailsScrollPane.java�����������������������������0000644�0001750�0001750�00000003125�14517772113�023233� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.control_panel; import org.gprofng.mpmt.util.gui.AnJScrollPane; import java.awt.Dimension; import javax.swing.JComponent; import javax.swing.JScrollBar; import javax.swing.JScrollPane; // the following is an attempt to create a scrollpane that respects // the existing width of the RHT. It's not completely smooth. public class CPDetailsScrollPane extends AnJScrollPane { private JComponent child; public CPDetailsScrollPane(JComponent cc) { super(cc, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); child = cc; } public Dimension getPreferredSize() { Dimension dd = child.getPreferredSize(); JScrollBar hscroll = this.getHorizontalScrollBar(); if (hscroll != null) { // if(true || hscroll.isVisible()){ // isVisible not reliable int s_height = hscroll.getPreferredSize().height; dd.height += s_height; } dd.width = 0; return dd; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/control_panel/CPLayoutPanel.java�����������������������������������0000644�0001750�0001750�00000005337�14517772113�022127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.control_panel; import java.awt.BorderLayout; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JScrollPane; /** * The MPIConrolPanel class provides the features common to both the MPIChartConrolPanel and * TimelineControlPanel. These include providing the visual features such as the toolbar buttons and * filtering buttons. Some of the processing of the control input is handled but much is done in the * extending classes implementation of the abstract methods. */ public class CPLayoutPanel extends JPanel { public CPLayoutPanel( JComponent tb, JComponent filter_panel, JComponent custom, JComponent details) { super(); this.setLayout(new BorderLayout()); // north = toolbar, center = belowToolbar // --- this.center = belowToolbarPanel JPanel belowToolbarPanel = new JPanel(); belowToolbarPanel.setLayout(new BorderLayout()); // north = aboveDetails, center = Details belowToolbarPanel.setBorder(BorderFactory.createEmptyBorder()); JScrollPane scrollPane = new JScrollPane(belowToolbarPanel); scrollPane.setBorder(null); this.add(scrollPane, BorderLayout.CENTER); // ------- belowToolbarPanel.north = aboveDetailsBox JPanel aboveDetailsBox = new JPanel(); aboveDetailsBox.setLayout(new BoxLayout(aboveDetailsBox, BoxLayout.Y_AXIS)); aboveDetailsBox.setBorder(BorderFactory.createEmptyBorder()); belowToolbarPanel.add(aboveDetailsBox, BorderLayout.NORTH); if (tb != null) { this.add(tb, BorderLayout.NORTH); } // ----------- aboveDetails top box: filtering if (filter_panel != null) { aboveDetailsBox.add(filter_panel); } // ------- more boxes between Details and Toolbar if (custom != null) { aboveDetailsBox.add(custom); } // ------- belowToolbarPanel.center = detailsPanel if (details != null) { belowToolbarPanel.add(details, BorderLayout.CENTER); } belowToolbarPanel.revalidate(); aboveDetailsBox.revalidate(); this.revalidate(); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnChooser.java�����������������������������������������������������0000644�0001750�0001750�00000065722�14517772113�016475� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.ipc.IPCLogger; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.accessibility.AccessibleContext; import javax.swing.BorderFactory; import javax.swing.Icon; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.filechooser.FileSystemView; public class AnChooser extends JFileChooser implements PropertyChangeListener { private static final int EXP_NOT = 0; private static final int EXP_NORMAL = 1; private static final int EXP_GROUP = 2; private static final int EXP_BAD = 3; private static final int EXP_OLD = 4; public static final int EXP_CHOOSER = 0; public static final int EXP_GROUP_CHOOSER = 1; public static final int TARGET_CHOOSER = 2; public static final int DIR_CHOOSER = 3; public static final int DIR_FILE_CHOOSER = 4; private static String startDir = Analyzer.getInstance().getWorkingDirectory(); private static final String open_text = AnLocale.getString("Open"); private static final String add_text = AnLocale.getString("Add"); private static final String set_text = AnLocale.getString("Set"); private final int chooser_type; private final AnWindow window; private final Component comp; private JPanel previewPanel; private AnList previewList; private ConfigurationPanel anChooserExtraPanel; private String title_str, approve_button_text; private static AnFileSystemView anFileSystemView = null; private AnFile currentRemoteDirectory = null; private final String SLASH = "/"; /** * Common constructor. Used by all constructors in this class. * * @param comp * @param chooser_type * @param window * @param title * @param st_dir * @param rhost * @param fsv */ public AnChooser( final Component comp, final int chooser_type, final AnWindow window, final String title, final String st_dir, String rhost, FileSystemView fsv) { super(st_dir, fsv); this.chooser_type = chooser_type; this.window = window; this.comp = comp; this.anFileSystemView = (AnFileSystemView) fsv; initAnChooser(chooser_type, title, rhost, fsv); } /** * Common constructor. Used by all constructors in remote mode. * * @param comp * @param chooser_type * @param window * @param restart * @param st_dir * @param rhost * @param fsv */ public AnChooser( final Component comp, final int chooser_type, final AnWindow window, final String title, final AnFile st_dir, String rhost, FileSystemView fsv) { super(st_dir, fsv); this.chooser_type = chooser_type; this.window = window; this.comp = comp; this.anFileSystemView = (AnFileSystemView) fsv; initAnChooser(chooser_type, title, rhost, fsv); if (Analyzer.getInstance().remoteConnection != null) { setCurrentDirectory(st_dir); } } /** * Initialize AnChooser * * @param chooser_type * @param title * @param rhost * @param fsv */ private void initAnChooser( final int chooser_type, final String title, String rhost, FileSystemView fsv) { setFileHidingEnabled(false); setFileView(new ExpView()); if (chooser_type != EXP_CHOOSER) { approve_button_text = set_text; } if (chooser_type == EXP_CHOOSER || chooser_type == EXP_GROUP_CHOOSER) { setFileSelectionMode(FILES_AND_DIRECTORIES); setFileFilter(new ExpFilter()); initComponents(); } else if (chooser_type == TARGET_CHOOSER) { setFileSelectionMode(FILES_ONLY); } else if (chooser_type == DIR_FILE_CHOOSER) { setFileSelectionMode(FILES_AND_DIRECTORIES); } else { // chooser_type == DIR_CHOOSER setFileSelectionMode(DIRECTORIES_ONLY); } if (chooser_type == EXP_CHOOSER) { setMultiSelectionEnabled(true); if (null != title) { String newtitle = title; if (rhost != null) { newtitle = title + " " + rhost + ""; } setDialogTitle(newtitle); if (newtitle.startsWith(AnLocale.getString("Add Experiment"))) { approve_button_text = add_text; } else { approve_button_text = open_text; } setApproveButtonText(approve_button_text); } } addPropertyChangeListener(this); } /** * This constructor is used by CollectPanel * * @param comp * @param chooser_type * @param window * @param restart * @param directory */ public AnChooser( final Component comp, final int chooser_type, final AnWindow window, final String directory) { this(comp, chooser_type, window, null /* title */, directory, null, null); } /** * This constructor is used by AnWindow for local file system * * @param comp * @param awindow * @param title * @param restart */ public AnChooser(final Component comp, final AnWindow awindow, final String title) { this(comp, awindow, title, null, null); } /** * This constructor is used by AnWindow for remote file system * * @param comp * @param awindow * @param title * @param title * @param rhost * @param fsv */ public AnChooser( final Component comp, final AnWindow awindow, final String title, String rhost, FileSystemView fsv) { this(comp, EXP_CHOOSER, awindow, title, startDir, rhost, fsv); } @Override public final void setDialogTitle(final String title) { super.setDialogTitle(title); title_str = title; } // @Override // public int showDialog(Component parent, String approveButtonText) throws HeadlessException { // if (chooser_type == EXP_CHOOSER || chooser_type == EXP_GROUP) { // setControlButtonsAreShown(false); // AnDialog2 anDialog2 = new AnDialog2(parent, getDialogTitle()); // anDialog2.getOKButton().setText(getApproveButtonText()); // JPanel panel = new JPanel(); // panel.setLayout(new BorderLayout()); // panel.add(this, BorderLayout.CENTER); // anDialog2.setCustomPanel(panel); // anDialog2.setVisible(true); // AnDialog2.Status status = anDialog2.getStatus(); // if (status == AnDialog2.Status.OK) { // return AnChooser.APPROVE_OPTION; // } // else { // return AnChooser.CANCEL_OPTION; // } // } // else { // setControlButtonsAreShown(true); // return(super.showDialog(parent, approveButtonText)); //To change body of generated // methods, choose Tools | Templates. // } // } /** * Get AnFileSystemView * * @return anFileSystemView */ public final AnFileSystemView getAnFileSystemView() { return anFileSystemView; } /** * Returns the current directory. * * @return the current directory * @see #setCurrentDirectory */ @Override public File getCurrentDirectory() { if (Analyzer.getInstance().remoteConnection != null) { // NM if (null == currentRemoteDirectory) { AnFile af = new AnFile(SLASH); af.setAttributes(SLASH, true, true); // NM Is it correct?? currentRemoteDirectory = af; } // Temporary fix for Windows String dirname = currentRemoteDirectory.getPath(); if (dirname.length() >= 3) { if ((dirname.charAt(1) == ':') && (dirname.charAt(2) == '\\')) { if (dirname.length() > 3) { dirname = SLASH + dirname.substring(3); } else { dirname = SLASH; } AnFile af = new AnFile(dirname); af.setAttributes(dirname, true, true); // NM Is it correct?? currentRemoteDirectory = af; } } return currentRemoteDirectory; } return super.getCurrentDirectory(); } /** * Sets the current directory. * * @param dir */ public void setCurrentDirectory(File curdir) { if (Analyzer.getInstance().remoteConnection == null) { super.setCurrentDirectory(curdir); return; } // NM Temporary implementation for remote case if (curdir == null) { return; } AnFile oldValue = currentRemoteDirectory; String s = curdir.getPath(); // Temporary code for Windows s = AnFileSystemView.slashifyPath(s); AnFile dir = new AnFile(s); // Update attributes if (anFileSystemView != null) { anFileSystemView.updateFileAttributes(dir); } else { // anFileSystemView can be null only during the first call from super currentRemoteDirectory = dir; // just set currentRemoteDirectory and return return; } if (dir != null && !dir.exists()) { // ??? // dir = currentRemoteDirectory; // why not return? return; } // if (dir == null) { // dir = getFileSystemView().getDefaultDirectory(); // } if (currentRemoteDirectory != null) { /* Verify the toString of object */ if (currentRemoteDirectory.equals(dir)) { return; } } AnFile prev = null; while (!isTraversable(dir) && prev != dir) { prev = new AnFile(dir.getParent()); if (prev == null) { return; } dir = prev; // dir = getFileSystemView().getParentDirectory(dir); } currentRemoteDirectory = dir; if (s.startsWith("//")) { prev = null; // BUG } // System.err.println("AnChooser.setCurrentDirectory:"+currentRemoteDirectory); try { firePropertyChange(DIRECTORY_CHANGED_PROPERTY, oldValue, currentRemoteDirectory); } catch (NullPointerException npe) { // CR 7199013, 7200045 // System.err.println("AnChooser.setCurrentDirectory:274: NPE CR 7200045 File=" + // currentRemoteDirectory.getAbsolutePath()); IPCLogger.logTrace( "\n" + "AnChooser.setCurrentDirectory:274: NPE CR 7200045 File=" + currentRemoteDirectory.getAbsolutePath()); // npe.printStackTrace(); currentRemoteDirectory = oldValue; } } /** Returns a list of selected files if the file chooser is set to allow multiple selection. */ public File[] getSelectedAnFiles() { File[] files = getSelectedFiles(); if (Analyzer.getInstance().remoteConnection == null) { return files; } if (anFileSystemView != null) { for (int i = 0; i < files.length; i++) { if (files[i] instanceof AnFile) { continue; } // Replace File with AnFile String file_name = files[i].getAbsolutePath(); AnFile af = new AnFile(file_name); anFileSystemView.updateFileAttributes(af); files[i] = (File) af; } } return files; } /** * Returns the selected file. This can be set either by the programmer via <code>setFile</code> or * by a user action, such as either typing the filename into the UI or selecting the file from a * list in the UI. * * @see #setSelectedFile * @return the selected file */ public File getSelectedAnFile() { File file = getSelectedFile(); if (Analyzer.getInstance().remoteConnection == null) { return file; } if ((file != null) && (anFileSystemView != null)) { if (file instanceof AnFile) { return file; } String file_name = file.getName(); if (null == file_name) { return null; } if (file_name.startsWith(SLASH)) { AnFile af = new AnFile(file_name); anFileSystemView.updateFileAttributes(af); file = (File) af; } else { AnFile dir = (AnFile) getCurrentDirectory(); AnFile af = new AnFile(dir.getPath(), file_name); anFileSystemView.updateFileAttributes(dir, af); file = (File) af /*.getAbsoluteFile() */; } } return file; } // Initialize GUI components private void initComponents() { final JLabel label; final JScrollPane scrollPane; // Add list for preview previewList = new AnList(true); scrollPane = new AnJScrollPane(previewList); scrollPane.setBorder(BorderFactory.createLineBorder(AnEnvironment.SCROLLBAR_BORDER_COLOR)); // Add label for preview label = new JLabel(AnLocale.getString("Experiment Preview:")); label.setBorder(AnVariable.labelBorder); label.setDisplayedMnemonic(AnLocale.getString('E', "MNEM_EXPERIMENT_PREVIEW")); label.setLabelFor(previewList); AccessibleContext context = previewList.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Experiment Preview")); context.setAccessibleDescription(AnLocale.getString("Experiment Preview")); context = label.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Experiment Preview")); context.setAccessibleDescription(AnLocale.getString("Experiment Preview")); previewPanel = new JPanel(new GridBagLayout()); // no ANJPanel previewPanel.setPreferredSize(new Dimension(AnVariable.FVIEW_SIZE)); GridBagConstraints gridBagConstraints; int gridy = 0; gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(6, 6, 0, 0); gridBagConstraints.gridy = gridy++; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; previewPanel.add(label, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(12, 6, 0, 0); gridBagConstraints.gridy = gridy++; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; previewPanel.add(scrollPane, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(12, 6, 0, 0); gridBagConstraints.gridy = gridy++; gridBagConstraints.anchor = GridBagConstraints.SOUTHWEST; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; previewPanel.add(anChooserExtraPanel = new ConfigurationPanel(true), gridBagConstraints); anChooserExtraPanel.setVisible(false); setAccessory(previewPanel); } // override createDialog() to workaround JDK accessibility bug @Override protected final JDialog createDialog(final Component parent) { final JDialog dialog = super.createDialog(parent); final AccessibleContext context = dialog.getAccessibleContext(); context.setAccessibleName(title_str); context.setAccessibleDescription(title_str); return dialog; } // Listener for file chooser @Override public final void propertyChange(final PropertyChangeEvent evt) { AnUtility.dispatchOnAWorkerThread( () -> { PropertyChangeInternal(evt); }, "PropertyChangeThread"); // Run this on a thread so that the AWT does not hang when fileChooser is waiting for a bad // remote file } private final void PropertyChangeInternal(final PropertyChangeEvent evt) { final File file; final String[] exp_info; String header, value; final int type, size; final Dimension msize; if (!evt.getPropertyName().equals(SELECTED_FILE_CHANGED_PROPERTY)) { return; } file = getSelectedAnFile(); if (file == null) { return; } type = getExperimentType(file); if ((chooser_type != DIR_CHOOSER) && (chooser_type != DIR_FILE_CHOOSER)) { if (type == EXP_NOT && file.isDirectory()) { setApproveButtonText(open_text); } else { setApproveButtonText(approve_button_text); } } if (previewList == null) { return; } previewList.removeAll(); anChooserExtraPanel.setVisible(false); if ((type == EXP_NORMAL) || (type == EXP_GROUP)) { // Get experiment preview exp_info = window.getExpPreview(file.getAbsolutePath()); size = exp_info.length; anChooserExtraPanel.initConfigurationChoices(file); anChooserExtraPanel.setWorkingDirectory(file.getParent()); anChooserExtraPanel.setVisible(true); for (int i = 0; i < size; ) { header = exp_info[i++]; value = exp_info[i++]; previewList.add( AnUtility.getItem(header + ":"), value.indexOf('\n') == -1 ? AnUtility.getText(value, 0) : AnUtility.getTextArea(value)); } // msize = previewList.getMaximumSize(); // msize.height = previewList.getPreferredSize().height; // previewList.setMaximumSize(msize); } previewList.repaint(); previewList.invalidate(); previewPanel.validate(); } public List<String> getExperiments() { final List<String> list = new ArrayList<String>(); String errstr = ""; final File[] files = getSelectedAnFiles(); if (files != null) { // Get file list for (int i = 0; i < files.length; i++) { File file = files[i]; int type = getExperimentType(file); if ((type == EXP_NORMAL) || (type == EXP_GROUP)) { String path = file.getAbsolutePath(); List<String> exp_list = AnUtility.getGroupList(path); if (exp_list.size() > 1) { list.add(path); } else { list.addAll(exp_list); } } else { if (!errstr.equals("")) { errstr += "\n"; } if (type == EXP_OLD) { errstr += AnLocale.getString("Old experiment is not supported:"); } else if (type == EXP_BAD) { errstr += AnLocale.getString("Bad experiment:"); } else { errstr += AnLocale.getString("Not a valid experiment:"); } errstr += " " + file; } } } // Show error mesg if (!errstr.equals("")) { AnUtility.showMessage(comp, errstr, JOptionPane.ERROR_MESSAGE); window.getExperimentsView().appendLog(AnLocale.getString("Error: ") + errstr); } return list; } // Get experiment type public static int getExperimentType(final File file) { final String file_name; if (file == null) { return EXP_NOT; } file_name = file.getName(); if (file_name.endsWith(".er")) { if (file.isDirectory()) { return EXP_NORMAL; } else if (file.isFile()) { return EXP_OLD; } else { return EXP_NOT; } } else if (file_name.endsWith(".erg") && file.isFile()) { return EXP_GROUP; } else { return EXP_NOT; } } public String getWorkingDirectory() { String wd = null; if (anChooserExtraPanel != null) { wd = anChooserExtraPanel.getWorkingDirectory(); } return wd; } public String getConfiguration() { String configuration = null; if (anChooserExtraPanel != null) { configuration = anChooserExtraPanel.getConfiguration(); } return configuration; } public boolean alwaysUseThisConfiguration() { boolean always = false; if (anChooserExtraPanel != null) { always = anChooserExtraPanel.alwaysUseThisConfiguration(); } return always; } // Called by the UI when the user hits the Approve button @Override public final void approveSelection() { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { ApproveSelectionInternal(); } }, "ApproveSelectionThread"); // Run this on a thread so that the AWT does not hang when fileChooser is waiting for a bad // remote file } private final void ApproveSelectionInternal() { File[] files = null; final /*NM final*/ File file; final int type; if (chooser_type == EXP_CHOOSER) { files = getSelectedAnFiles(); if (files.length == 0) { return; } file = files[0]; } else { file = getSelectedAnFile(); if (file == null) { return; } } /*NM if (anFileSystemView != null) { // TEMPORARY! should be in getSelectedAnFiles() for (int i = 0; i < files.length; i++) { String file_name = files[i].getName(); AnFile af = new AnFile(file_name); File dir = this.getCurrentDirectory(); anFileSystemView.getFileAttributes(dir, af); files[i] = (File) af.getAbsoluteFile(); } file = files[0]; } */ type = getExperimentType(file); String fullpath = file.getAbsolutePath(); // Non-experiment directory been selected if ((chooser_type != DIR_CHOOSER) && (chooser_type != DIR_FILE_CHOOSER) && file.isDirectory() && type == EXP_NOT) { if (chooser_type == EXP_CHOOSER) { startDir = fullpath; } if (Analyzer.getInstance().remoteConnection != null) { // NM final AnFile af = new AnFile(fullpath); // setCurrentDirectory(af); // causes NPE AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { try { setCurrentDirectory(af); } catch (IllegalArgumentException ex) { // no exceptions expected here } } }); return; } // NM // setCurrentDirectory(file); AnUtility.dispatchOnSwingThread( () -> { try { setCurrentDirectory(file); } catch (IllegalArgumentException ex) { // no exceptions expected here } } // @Override ); return; } else { if (chooser_type == EXP_CHOOSER) { startDir = getCurrentDirectory().getAbsolutePath(); } } boolean done = true; if (chooser_type == EXP_GROUP_CHOOSER) { if (type != EXP_GROUP) { AnUtility.showMessage( comp, AnLocale.getString("Not a valid experiment group: ") + file, JOptionPane.ERROR_MESSAGE); done = false; } } else if (chooser_type == TARGET_CHOOSER) { if (!Analyzer.getInstance().isRemote()) { if (!file.isFile() /* AnUtility.isTarget(file) */) { AnUtility.showMessage( comp, AnLocale.getString("Not a valid target: ") + file, JOptionPane.ERROR_MESSAGE); done = false; } } else { // no check in remote mode /* NM This code is not ready yet // setCurrentDirectory(file); final AnFile af = new AnFile(fullpath); start_dir = af.getDirectoryName(); window.dispatchOnSwingThread(new Runnable() { // @Override public void run() { try { setCurrentDirectory(file.getParentFile()); //start_dir = getCurrentDirectory().getAbsolutePath(); } catch (Exception ex) { // no exceptions expected here ex.printStackTrace(); } } }); */ } } if (done) { super.approveSelection(); } } public final void cancelChooser() { super.cancelSelection(); } // Called by the UI when the user chooses the Cancel button. @Override public final void cancelSelection() { if (chooser_type == EXP_CHOOSER) { startDir = getCurrentDirectory().getAbsolutePath(); } /* NM This code does not work (see CR 16617347) final CancelContext cancelContext = window.getProgressCancelContext(); if (cancelContext != null) { window.dispatchOnWorkerThread(new Runnable() { public void run() { cancelContext.getCancellable().cancel(); // actual cancel will be called by the thread receiving // the cancel for the getFiles IPC request } }, "CancelTaskThread"); } */ super.cancelSelection(); } // File filter for experiment final class ExpFilter extends javax.swing.filechooser.FileFilter { @Override public boolean accept(final File file) { final boolean accepted; final int type; type = getExperimentType(file); switch (chooser_type) { case EXP_GROUP_CHOOSER: accepted = (type == EXP_GROUP) || (type == EXP_NOT && file.isDirectory()); break; case TARGET_CHOOSER: accepted = (type == EXP_NOT && file.isDirectory()) || AnUtility.isTarget(file); break; default: // EXP_CHOOSER accepted = (type != EXP_NOT) || file.isDirectory(); break; } return (accepted); } @Override public String getDescription() { switch (chooser_type) { case EXP_GROUP_CHOOSER: return AnLocale.getString("Analyzer Experiment Group (*.erg)"); case TARGET_CHOOSER: return AnLocale.getString("Analyzer Target (executable files)"); default: // EXP_CHOOSER return AnLocale.getString("Analyzer Experiment (*.er, *.erg)"); } } } // File view for experiment private final class ExpView extends javax.swing.filechooser.FileView { @Override public Icon getIcon(final File file) { if (chooser_type == TARGET_CHOOSER) { if (!file.isFile()) { return getExperimentIcon(file); } switch (AnUtility.getMimeFormat(file)) { case AnUtility.MIME_ELF_EXECUTABLE: return AnUtility.elf_icon; case AnUtility.MIME_JAVA_CLASS_FILE: return AnUtility.cls_icon; case AnUtility.MIME_JAR_FILE: return AnUtility.jar_icon; default: return getExperimentIcon(file); } } else { return getExperimentIcon(file); } } private Icon getExperimentIcon(final File file) { switch (getExperimentType(file)) { case EXP_NORMAL: return AnUtility.expt_icon; case EXP_GROUP: return AnUtility.egrp_icon; case EXP_OLD: return AnUtility.eold_icon; case EXP_BAD: return AnUtility.ebad_icon; default: return null; } } @Override public final Boolean isTraversable(final File file) { return getExperimentType(file) == EXP_NOT && file.isDirectory(); } // Compatible with old JDK @Override public String getName(final File f) { return null; } @Override public String getDescription(final File f) { return null; } @Override public String getTypeDescription(final File f) { return null; } } } ����������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/IOView.java��������������������������������������������������������0000644�0001750�0001750�00000151706�14517772113�015754� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.AnDisplay.DSP_IO; import static org.gprofng.mpmt.AnDisplay.DSP_IOCallStacks; import static org.gprofng.mpmt.AnDisplay.DSP_IOFileDescriptors; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.statecolors.StackView; import org.gprofng.mpmt.statecolors.StackViewState; import org.gprofng.mpmt.statecolors.StateColorMap; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnSplitPaneInternal; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.EventObject; import java.util.List; import java.util.Vector; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JRadioButton; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JViewport; import javax.swing.SwingUtilities; import javax.swing.border.LineBorder; import javax.swing.border.TitledBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; public final class IOView extends FuncListDisp implements AnListener, MouseListener, AdjustmentListener, ListSelectionListener, AnChangeListener { private boolean inCompute = false; private ButtonControlPanel buttonPanel; private JScrollPane errorPane = null; private Object[][] tableDataFile; private Object[][] tableDataVfd; private Object[][] tableDataCalStk; private long[] dataFileIds = null; private long[] dataVfdIds = null; private long[] dataCalStkIds = null; private JRadioButton actButton; private JRadioButton detButton; private JRadioButton calStkButton; private JPanel statPanel; private AnJScrollPane statScrollPane; private String[][] statisticsData; private final int WRITE = 0; private final int READ = 1; private final int OTHER = 2; private final int ERROR = 3; private JComponent eventPane; private JComponent stackViewPane; private StackView stack_view; // Right-hand Tab's Event Stack Display private final StateColorMap clmap; private int fileRowId; private int vfdRowId; private int stackRowId; private boolean updateIfNotSort; private StackView.StackViewPopupListener stackViewPopupListener; /** Keeps last warning to avoid showing the same warning message many times */ // Constructor public IOView() { super(AnWindow.getInstance(), AnDisplay.DSP_IO, 0, AnVariable.HELP_TabsIOActivity); clmap = window.getColorChooser().getColorMap(); clmap.addAnListener(this); initTab(); stackViewPopupListener = stack_view.new StackViewPopupListener(window); setAccessibility(AnLocale.getString("IO")); AnEventManager.getInstance().addListener(this); updateIfNotSort = true; } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("IOView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public JPanel getToolbarPanel() { return null; } private void initTab() { // Event Pane eventPane = new FocusPanel(); eventPane.setLayout(new BorderLayout()); TitledBorder titledBorder = new TitledBorder(AnLocale.getString("I/O Activity")); titledBorder.setBorder(new LineBorder(eventPane.getBackground())); // Event Pane: Call Stack stack_view = new StackView(clmap); stack_view.addMouseListener(this); stack_view.addListSelectionListener(this); stackViewPane = new JPanel(); stackViewPane.setBackground(Color.WHITE); stackViewPane.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(2, 2, 2, 2); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weighty = 1.0; gridBagConstraints.weightx = 1.0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; stackViewPane.add(stack_view, gridBagConstraints); stackViewPane.setVisible(false); stackViewPane.revalidate(); stackViewPane.repaint(); eventPane.add(stackViewPane, BorderLayout.CENTER); eventPane.revalidate(); } class FocusPanel extends JPanel { @Override public void requestFocus() { if (stack_view != null) { stack_view.requestFocus(); } } } @Override public JPopupMenu getFilterPopup() { return table.initPopup(true); } // tab to populate right-side info area public JComponent getStackInfoTabComp() { return eventPane; } // name for tab in right-side info area public String getStackInfoTabName() { return AnLocale.getString("Call Stack - I/O"); } public JComponent getStackViewPane() { return stackViewPane; } @Override public void setSelected(final boolean set) { super.setSelected(set); // Show right pane if we get selected // if (set) { // window.showRightPane(); // } } // Initialize GUI components @Override protected void initComponents() { setLayout(new BorderLayout()); String acName = null; String acDesc = null; JLabel acLabel = null; acName = AnLocale.getString("IOActivity"); acDesc = AnLocale.getString("Show I/O activity for selected application"); if (acName != null) { acLabel = new JLabel(acName, JLabel.RIGHT); AnUtility.setAccessibleContext(acLabel); } table = new AnTable(type, true, true, can_sort, false, true, true, true, acName, acDesc, acLabel); table.setParent(this); if (acLabel != null) { acLabel.setVisible(false); // acLabel.setDisplayedMnemonic(acName.charAt(0)); table.add(acLabel); } table.addAnListener(new TableHandler()); statPanel = new JPanel(); statPanel.setLayout(new GridBagLayout()); statPanel.setBackground(Color.white); statScrollPane = new AnJScrollPane(statPanel); JSplitPane sp = new AnSplitPaneInternal(JSplitPane.VERTICAL_SPLIT, table, statScrollPane); sp.setResizeWeight(.75); add(sp, BorderLayout.CENTER); buttonPanel = new ButtonControlPanel(); add(buttonPanel, BorderLayout.NORTH); } class ButtonControlPanel extends JPanel { int sort_ind; MetricLabel[] label; public ButtonControlPanel() { JPanel displayPanel; String acName; String acDesc; fileRowId = 0; vfdRowId = 0; stackRowId = 0; setLayout(new FlowLayout(FlowLayout.LEFT)); setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); displayPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); displayPanel.setMinimumSize(new Dimension(20, 20)); // So window can resize properly displayPanel.setBorder(null); ButtonGroup group = new ButtonGroup(); JLabel aggrlabel = new JLabel(AnLocale.getString("Aggregate I/O Data By:")); AnUtility.setAccessibleContext(aggrlabel); displayPanel.add(aggrlabel); // Accessibility acName = AnLocale.getString("Aggregate I/O Data By"); acDesc = AnLocale.getString("Select Aggregate I/O Data By"); aggrlabel.getAccessibleContext().setAccessibleName(acName); aggrlabel.getAccessibleContext().setAccessibleDescription(acDesc); actButton = new JRadioButton(AnLocale.getString("File Name")); actButton.setMnemonic(AnLocale.getString('A', "IOViewFileNameMN")); actButton.setSelected(true); group.add(actButton); displayPanel.add(actButton); // Accessibility acName = AnLocale.getString("Aggregate I/O Data By: File Name"); acDesc = AnLocale.getString("Set Aggregate I/O Data BY: File Name"); actButton.getAccessibleContext().setAccessibleName(acName); actButton.getAccessibleContext().setAccessibleDescription(acDesc); detButton = new JRadioButton(AnLocale.getString("File Descriptor")); detButton.setMnemonic(AnLocale.getString('l', "IOViewFileDescriptorMN")); detButton.setSelected(false); group.add(detButton); displayPanel.add(detButton); // Accessibility acName = AnLocale.getString("Aggregate I/O Data By: File Descriptor"); acDesc = AnLocale.getString("Set Aggregate I/O Data BY: File Descriptor"); detButton.getAccessibleContext().setAccessibleName(acName); detButton.getAccessibleContext().setAccessibleDescription(acDesc); calStkButton = new JRadioButton(AnLocale.getString("Call Stack")); calStkButton.setMnemonic(AnLocale.getString('s', "IOViewCallStackMN")); calStkButton.setSelected(false); group.add(calStkButton); displayPanel.add(calStkButton); // Accessibility acName = AnLocale.getString("Aggregate I/O Data By: Call Stack"); acDesc = AnLocale.getString("Set Aggregate I/O Data BY: Call Stack"); calStkButton.getAccessibleContext().setAccessibleName(acName); calStkButton.getAccessibleContext().setAccessibleDescription(acDesc); add(displayPanel); actButton.addItemListener( new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (actButton.isSelected()) { Object[] gtm = getTotalMax(); label = getSettings().getMetricsSetting().getLabel(tableDataFile, gtm, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); AnUtility.checkIPCOnWrongThread(false); names = getNames(type, 0); // IPC - FIXUP: don't do this on AWT AnUtility.checkIPCOnWrongThread(true); sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); table.setData(label, tableDataFile, names, null, 0, name_col, sort_ind); table.setSelectedRow(fileRowId); table.showSelectedRow(); int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IO); window.getSelectionManager().updateSelection(ids, DSP_IO, subtype, 1); } } window.showSubview(window.getIoCallStackSubview(), false); } }); detButton.addItemListener( new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (detButton.isSelected()) { Object[] gtm = getTotalMax(); label = getSettings().getMetricsSetting().getLabel(tableDataVfd, gtm, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); AnUtility.checkIPCOnWrongThread(false); names = getNames(type, 0); // IPC - FIXUP: don't do this on AWT AnUtility.checkIPCOnWrongThread(true); sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); table.setData(label, tableDataVfd, names, null, 0, name_col, sort_ind); table.setSelectedRow(vfdRowId); table.showSelectedRow(); int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IOFileDescriptors); window .getSelectionManager() .updateSelection(ids, DSP_IOFileDescriptors, subtype, 1); } } window.showSubview(window.getIoCallStackSubview(), false); } }); calStkButton.addItemListener( new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { if (calStkButton.isSelected()) { Object[] gtm = getTotalMax(); label = getSettings().getMetricsSetting().getLabel(tableDataCalStk, gtm, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); AnUtility.checkIPCOnWrongThread(false); names = getNames(type, 0); // IPC - FIXUP: don't do this on AWT AnUtility.checkIPCOnWrongThread(true); sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); table.setData(label, tableDataCalStk, names, null, 0, name_col, sort_ind); table.setSelectedRow(stackRowId); table.showSelectedRow(); if (stackRowId >= dataCalStkIds.length) { stackRowId = dataCalStkIds.length - 1; } long id = dataCalStkIds[stackRowId]; int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IOCallStacks); window.getSelectionManager().updateSelection(ids, DSP_IOCallStacks, subtype, 1); } updateStackView(id); } window.showSubview(window.getIoCallStackSubview(), true); } }); } } // Compute & update function list table @Override public void doCompute() { AnUtility.checkIfOnAWTThread(false); MetricLabel[] label; final String pwarnstr; // Not selected if (!selected) { return; } // XXXX show error when compare is on, needs simplified, // but the situation is different for different views if (window.getSettings().getCompareModeSetting().comparingExperiments()) { JLabel error_label = new JLabel(); error_label.setHorizontalAlignment(JLabel.CENTER); error_label.getAccessibleContext().setAccessibleName(AnLocale.getString("Error message")); error_label .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Error message")); JViewport error_view = new JViewport(); error_view.setView(error_label); String msg = AnLocale.getString("Not available when comparing experiments"); error_label.setText(msg); AnUtility.setAccessibleContext(error_label); if (errorPane == null) { errorPane = new AnJScrollPane(); add(errorPane, BorderLayout.CENTER); } errorPane.setViewportView(error_view); errorPane.setVisible(true); buttonPanel.setVisible(false); statScrollPane.setVisible(false); return; } if (errorPane != null) { errorPane.setVisible(false); } buttonPanel.setVisible(true); statScrollPane.setVisible(true); if (inCompute) { return; } else { inCompute = true; } // int typeForPresentation = type; if (!computed) { // need re-compute reset(); tableDataFile = null; dataFileIds = null; tableDataVfd = null; dataVfdIds = null; tableDataCalStk = null; dataCalStkIds = null; stack_view.reset(); table.setViewport(); final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(type); Object[] raw_data_with_ids = window.getTableDataV2("MET_IO", "ALL", "IOACTFILE", "" + subtype, null); tableDataFile = localProcessData(mlist, raw_data_with_ids); dataFileIds = current_ids; if (updateIfNotSort) { statisticsData = getIOStatistics(); AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { statPanel.removeAll(); displayStatisticsData(statisticsData); } }); } updateIfNotSort = true; raw_data_with_ids = window.getTableDataV2("MET_IO", "ALL", "IOACTVFD", "" + subtype, null); tableDataVfd = localProcessData(mlist, raw_data_with_ids); dataVfdIds = current_ids; raw_data_with_ids = window.getTableDataV2("MET_IO", "ALL", "IOCALLSTACK", "" + subtype, null); tableDataCalStk = localProcessData(mlist, raw_data_with_ids); dataCalStkIds = current_ids; names = getNames(type, 0); // IPC call, don't do on AWT AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { if (actButton.isSelected()) { MetricLabel[] label = getSettings().getMetricsSetting().getLabel(tableDataFile, null, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); int sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); table.setData(label, tableDataFile, names, null, 0, name_col, sort_ind); table.setSelectedRow(fileRowId); table.showSelectedRow(); } else if (detButton.isSelected()) { MetricLabel[] label = getSettings().getMetricsSetting().getLabel(tableDataVfd, null, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); int sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); table.setData(label, tableDataVfd, names, null, 0, name_col, sort_ind); table.setSelectedRow(vfdRowId); table.showSelectedRow(); } else if (calStkButton.isSelected()) { MetricLabel[] label = getSettings().getMetricsSetting().getLabel(tableDataCalStk, null, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); int sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); table.setData(label, tableDataCalStk, names, null, 0, name_col, sort_ind); table.setSelectedRow(stackRowId); table.showSelectedRow(); } if (table.getTable().getColumnCount() == 1) { table.showMessage(new NoMetricsSelectedPanel(type)); inCompute = false; return; } } }); } // else if (!isUpdated()) { // Object[] gtm = getTotalMax(); // label = getSettings().getMetricsSetting().getLabel(table.getTableData(), // gtm, typeForPresentation, table); // // if (label != null) { // table.setLabel(label); // } // } AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { if (actButton.isSelected()) { int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IO); window.getSelectionManager().updateSelection(ids, DSP_IO, subtype, 1); } } else if (detButton.isSelected()) { int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IOFileDescriptors); window .getSelectionManager() .updateSelection(ids, DSP_IOFileDescriptors, subtype, 1); } } else if (calStkButton.isSelected()) { if (stackRowId >= dataCalStkIds.length) { stackRowId = dataCalStkIds.length - 1; } long id = dataCalStkIds[stackRowId]; int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IOCallStacks); window.getSelectionManager().updateSelection(ids, DSP_IOCallStacks, subtype, 1); } updateStackView(id); } } }); computed = true; // setUpdated(true); // pstatstr = window.getMsg(AnUtility.PSTAT_MSG); pwarnstr = window.getMsg(AnUtility.PWARN_MSG); // if (pstatstr != null) { // window.appendLog(pstatstr); // } if (pwarnstr != null) { window.showProcessorWarning(pwarnstr); } inCompute = false; } public int getDisplayMode() { int displayMode = DSP_IO; if (detButton.isSelected()) { displayMode = DSP_IOFileDescriptors; } else if (calStkButton.isSelected()) { displayMode = DSP_IOCallStacks; } return displayMode; } public long[] getSelectedIds(int selectedIndices[], int displayMode) { // FIXUP: REARCH long[] ids = null; if (selectedIndices.length >= 1) { ids = new long[selectedIndices.length]; for (int i = 0; i < selectedIndices.length; i++) { if (displayMode == DSP_IO) { ids[i] = dataFileIds[selectedIndices[i]]; } else if (displayMode == DSP_IOFileDescriptors) { ids[i] = dataVfdIds[selectedIndices[i]]; } else { ids[i] = dataCalStkIds[selectedIndices[i]]; } } } return ids; } private String exportStatisticsData(final String[][] raw_data) { if (raw_data == null) { return null; } StringBuilder strBuild = new StringBuilder(); strBuild.append("\n"); if (!AnWindow.getInstance().getFilters().anyFilters()) { strBuild.append(AnLocale.getString("I/O Data Statistics For <Total>")); strBuild.append("\n\n"); } else { strBuild.append(AnLocale.getString("I/O Data Statistics For <Total> (filters on)")); strBuild.append("\n\n"); } if (raw_data[WRITE].length > 1) { strBuild.append(raw_data[WRITE][0]); strBuild.append("\n"); strBuild.append(AnLocale.getString("I/O Size Range")); strBuild.append("\t\t\t"); strBuild.append(AnLocale.getString("Write Calls")); strBuild.append("\n"); for (int i = 1; i < raw_data[WRITE].length; i++) { if (raw_data[WRITE][i].trim().indexOf('-') > 0) { strBuild.append(" "); } strBuild.append(raw_data[WRITE][i]); if (raw_data[WRITE][i].trim().indexOf('-') > 0) { strBuild.append("\t\t\t"); } else { strBuild.append("\t\t"); } i++; strBuild.append(raw_data[WRITE][i]); strBuild.append("\n"); } strBuild.append("\n"); } if (raw_data[READ].length > 1) { strBuild.append(raw_data[READ][0]); strBuild.append("\n"); strBuild.append(AnLocale.getString("I/O Size Range")); strBuild.append("\t\t\t"); strBuild.append(AnLocale.getString("Read Calls")); strBuild.append("\n"); for (int i = 1; i < raw_data[READ].length; i++) { if (raw_data[READ][i].trim().indexOf('-') > 0) { strBuild.append(" "); } strBuild.append(raw_data[READ][i]); if (raw_data[READ][i].trim().indexOf('-') > 0) { strBuild.append("\t\t\t"); } else { strBuild.append("\t\t"); } i++; strBuild.append(raw_data[READ][i]); strBuild.append("\n"); } strBuild.append("\n"); } if (raw_data[OTHER].length > 1) { strBuild.append(raw_data[OTHER][0]); strBuild.append("\n"); for (int i = 1; i < raw_data[OTHER].length; i++) { strBuild.append(raw_data[OTHER][i]); strBuild.append("\t\t"); i++; strBuild.append(raw_data[OTHER][i]); strBuild.append("\n"); } strBuild.append("\n"); } if (raw_data[ERROR].length > 1) { strBuild.append(raw_data[ERROR][0]); strBuild.append("\n"); for (int i = 1; i < raw_data[ERROR].length; i++) { strBuild.append(raw_data[ERROR][i]); strBuild.append("\t\t"); i++; strBuild.append(raw_data[ERROR][i]); strBuild.append("\n"); } strBuild.append("\n"); } return strBuild.toString(); } private void displayStatisticsData(final String[][] raw_data) { if (raw_data == null) { return; } GridBagConstraints gridBagConstraints = new GridBagConstraints(); Color color = new Color(240, 240, 240); if (!AnWindow.getInstance().getFilters().anyFilters()) { JLabel label = new JLabel(AnLocale.getString("I/O Data Statistics For <Total>")); AnUtility.setAccessibleContext(label); label.setFont(table.getFont().deriveFont(Font.BOLD)); label.setOpaque(true); label.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets.left = 0; gridBagConstraints.insets.bottom = 10; statPanel.add(label, gridBagConstraints); } else { JLabel label = new JLabel(AnLocale.getString("I/O Data Statistics For <Total> (filters on)")); AnUtility.setAccessibleContext(label); label.setFont(table.getFont().deriveFont(Font.BOLD)); label.setOpaque(true); label.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets.left = 0; gridBagConstraints.insets.bottom = 10; statPanel.add(label, gridBagConstraints); } gridBagConstraints.insets.bottom = 0; if (raw_data[WRITE].length > 1) { JPanel writePanel = new JPanel(); writePanel.setLayout(new GridBagLayout()); writePanel.setBackground(Color.WHITE); GridBagConstraints gridBagConstraintsWrite = new GridBagConstraints(); JLabel label1 = new JLabel(raw_data[WRITE][0]); AnUtility.setAccessibleContext(label1); label1.setFont(table.getFont().deriveFont(Font.BOLD)); label1.setOpaque(true); label1.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.gridwidth = 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets.bottom = 0; gridBagConstraints.insets.top = 0; gridBagConstraints.insets.left = 0; statPanel.add(label1, gridBagConstraints); gridBagConstraintsWrite.gridwidth = 1; JLabel label2 = new JLabel(AnLocale.getString("I/O Size Range")); AnUtility.setAccessibleContext(label2); label2.setFont(table.getFont().deriveFont(Font.BOLD)); gridBagConstraintsWrite.weightx = 1; gridBagConstraintsWrite.weighty = 0; gridBagConstraintsWrite.gridx = 0; gridBagConstraintsWrite.gridy = 1; gridBagConstraintsWrite.anchor = GridBagConstraints.LINE_START; gridBagConstraintsWrite.fill = GridBagConstraints.NONE; gridBagConstraintsWrite.insets.bottom = 1; gridBagConstraintsWrite.insets.top = 0; gridBagConstraintsWrite.insets.left = 0; writePanel.add(label2, gridBagConstraintsWrite); JLabel label3 = new JLabel(AnLocale.getString("Write Calls")); AnUtility.setAccessibleContext(label3); label3.setFont(table.getFont().deriveFont(Font.BOLD)); gridBagConstraintsWrite.weightx = 1; gridBagConstraintsWrite.weighty = 0; gridBagConstraintsWrite.gridx = gridBagConstraintsWrite.gridx + 1; gridBagConstraintsWrite.gridy = 1; gridBagConstraintsWrite.anchor = GridBagConstraints.LINE_START; gridBagConstraintsWrite.fill = GridBagConstraints.NONE; gridBagConstraintsWrite.insets.bottom = 1; gridBagConstraintsWrite.insets.top = 0; gridBagConstraintsWrite.insets.left = 120; writePanel.add(label3, gridBagConstraintsWrite); for (int i = 1; i < raw_data[WRITE].length; i++) { JLabel label4 = new JLabel(raw_data[WRITE][i]); AnUtility.setAccessibleContext(label4); label4.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsWrite.weightx = 1; gridBagConstraintsWrite.weighty = 0; gridBagConstraintsWrite.gridx = 0; gridBagConstraintsWrite.gridy = gridBagConstraintsWrite.gridy + 1; gridBagConstraintsWrite.anchor = GridBagConstraints.LINE_START; gridBagConstraintsWrite.fill = GridBagConstraints.NONE; gridBagConstraintsWrite.insets.bottom = 0; gridBagConstraintsWrite.insets.top = 0; if (raw_data[WRITE][i].trim().indexOf('-') > 0) { gridBagConstraintsWrite.insets.left = 5; } else { gridBagConstraintsWrite.insets.left = 0; } writePanel.add(label4, gridBagConstraintsWrite); i++; JLabel label5 = new JLabel(raw_data[WRITE][i]); AnUtility.setAccessibleContext(label5); label5.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsWrite.weightx = 1; gridBagConstraintsWrite.weighty = 0; gridBagConstraintsWrite.gridx = gridBagConstraintsWrite.gridx + 1; gridBagConstraintsWrite.anchor = GridBagConstraints.LINE_START; gridBagConstraintsWrite.fill = GridBagConstraints.NONE; gridBagConstraintsWrite.insets.left = 120; gridBagConstraintsWrite.insets.bottom = 0; writePanel.add(label5, gridBagConstraintsWrite); } gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.REMAINDER; gridBagConstraints.insets.bottom = 10; statPanel.add(writePanel, gridBagConstraints); } if (raw_data[READ].length > 1) { JPanel readPanel = new JPanel(); readPanel.setLayout(new GridBagLayout()); readPanel.setBackground(Color.WHITE); GridBagConstraints gridBagConstraintsRead = new GridBagConstraints(); JLabel label1 = new JLabel(raw_data[READ][0]); AnUtility.setAccessibleContext(label1); label1.setFont(table.getFont().deriveFont(Font.BOLD)); label1.setOpaque(true); label1.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.gridwidth = 1; gridBagConstraints.insets.bottom = 0; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; statPanel.add(label1, gridBagConstraints); gridBagConstraintsRead.gridwidth = 1; JLabel label2 = new JLabel(AnLocale.getString("I/O Size Range")); AnUtility.setAccessibleContext(label2); label2.setFont(table.getFont().deriveFont(Font.BOLD)); gridBagConstraintsRead.weightx = 1; gridBagConstraintsRead.weighty = 0; gridBagConstraintsRead.gridx = 0; gridBagConstraintsRead.gridy = 1; gridBagConstraintsRead.anchor = GridBagConstraints.LINE_START; gridBagConstraintsRead.fill = GridBagConstraints.NONE; gridBagConstraintsRead.insets.bottom = 1; readPanel.add(label2, gridBagConstraintsRead); JLabel label3 = new JLabel(AnLocale.getString("Read Calls")); AnUtility.setAccessibleContext(label3); label3.setFont(table.getFont().deriveFont(Font.BOLD)); gridBagConstraintsRead.weightx = 1; gridBagConstraintsRead.weighty = 0; gridBagConstraintsRead.gridx = gridBagConstraintsRead.gridx + 1; gridBagConstraintsRead.gridy = 1; gridBagConstraintsRead.anchor = GridBagConstraints.LINE_START; gridBagConstraintsRead.fill = GridBagConstraints.NONE; gridBagConstraintsRead.insets.bottom = 1; gridBagConstraintsRead.insets.left = 120; readPanel.add(label3, gridBagConstraintsRead); for (int i = 1; i < raw_data[READ].length; i++) { JLabel label4 = new JLabel(raw_data[READ][i]); AnUtility.setAccessibleContext(label4); label4.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsRead.weightx = 1; gridBagConstraintsRead.weighty = 0; gridBagConstraintsRead.gridx = 0; gridBagConstraintsRead.gridy = gridBagConstraintsRead.gridy + 1; gridBagConstraintsRead.anchor = GridBagConstraints.LINE_START; gridBagConstraintsRead.fill = GridBagConstraints.NONE; gridBagConstraintsRead.insets.bottom = 0; gridBagConstraintsRead.insets.top = 0; if (raw_data[READ][i].trim().indexOf('-') > 0) { gridBagConstraintsRead.insets.left = 5; } else { gridBagConstraintsRead.insets.left = 0; } readPanel.add(label4, gridBagConstraintsRead); i++; JLabel label5 = new JLabel(raw_data[READ][i]); AnUtility.setAccessibleContext(label5); label5.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsRead.weightx = 1; gridBagConstraintsRead.weighty = 0; gridBagConstraintsRead.gridx = gridBagConstraintsRead.gridx + 1; gridBagConstraintsRead.anchor = GridBagConstraints.LINE_START; gridBagConstraintsRead.fill = GridBagConstraints.NONE; gridBagConstraintsRead.insets.left = 120; gridBagConstraintsRead.insets.bottom = 0; readPanel.add(label5, gridBagConstraintsRead); } gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.REMAINDER; gridBagConstraints.insets.bottom = 10; statPanel.add(readPanel, gridBagConstraints); } if (raw_data[OTHER].length > 1) { JPanel otherPanel = new JPanel(); otherPanel.setLayout(new GridBagLayout()); otherPanel.setBackground(Color.WHITE); GridBagConstraints gridBagConstraintsOther = new GridBagConstraints(); JLabel label1 = new JLabel(raw_data[OTHER][0]); AnUtility.setAccessibleContext(label1); label1.setFont(table.getFont().deriveFont(Font.BOLD)); label1.setOpaque(true); label1.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.gridwidth = 1; gridBagConstraints.insets.bottom = 0; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; statPanel.add(label1, gridBagConstraints); gridBagConstraintsOther.gridwidth = 1; for (int i = 1; i < raw_data[OTHER].length; i++) { JLabel label2 = new JLabel(raw_data[OTHER][i]); AnUtility.setAccessibleContext(label2); label2.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsOther.weightx = 1; gridBagConstraintsOther.weighty = 0; gridBagConstraintsOther.gridx = 0; gridBagConstraintsOther.gridy = gridBagConstraintsOther.gridy + 1; gridBagConstraintsOther.anchor = GridBagConstraints.LINE_START; gridBagConstraintsOther.fill = GridBagConstraints.NONE; gridBagConstraintsOther.insets.left = 0; otherPanel.add(label2, gridBagConstraintsOther); i++; JLabel label3 = new JLabel(raw_data[OTHER][i]); AnUtility.setAccessibleContext(label3); label3.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsOther.weightx = 1; gridBagConstraintsOther.weighty = 0; gridBagConstraintsOther.gridx = gridBagConstraintsOther.gridx + 1; gridBagConstraintsOther.anchor = GridBagConstraints.LINE_START; gridBagConstraintsOther.fill = GridBagConstraints.NONE; gridBagConstraintsOther.insets.left = 175; otherPanel.add(label3, gridBagConstraintsOther); } gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.REMAINDER; gridBagConstraints.insets.bottom = 10; statPanel.add(otherPanel, gridBagConstraints); } if (raw_data[ERROR].length > 1) { JPanel errorPanel = new JPanel(); errorPanel.setLayout(new GridBagLayout()); errorPanel.setBackground(Color.WHITE); GridBagConstraints gridBagConstraintsError = new GridBagConstraints(); JLabel label1 = new JLabel(raw_data[ERROR][0]); AnUtility.setAccessibleContext(label1); label1.setFont(table.getFont().deriveFont(Font.BOLD)); label1.setOpaque(true); label1.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.gridwidth = 1; gridBagConstraints.insets.bottom = 0; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; statPanel.add(label1, gridBagConstraints); gridBagConstraintsError.gridwidth = 1; for (int i = 1; i < raw_data[ERROR].length; i++) { JLabel label2 = new JLabel(raw_data[ERROR][i]); AnUtility.setAccessibleContext(label2); label2.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsError.weightx = 1; gridBagConstraintsError.weighty = 0; gridBagConstraintsError.gridx = 0; gridBagConstraintsError.gridy = gridBagConstraintsError.gridy + 1; gridBagConstraintsError.anchor = GridBagConstraints.LINE_START; gridBagConstraintsError.fill = GridBagConstraints.NONE; gridBagConstraintsError.insets.left = 0; errorPanel.add(label2, gridBagConstraintsError); i++; JLabel label3 = new JLabel(raw_data[ERROR][i]); AnUtility.setAccessibleContext(label3); label3.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsError.weightx = 1; gridBagConstraintsError.weighty = 0; gridBagConstraintsError.gridx = gridBagConstraintsError.gridx + 1; gridBagConstraintsError.anchor = GridBagConstraints.LINE_START; gridBagConstraintsError.fill = GridBagConstraints.NONE; gridBagConstraintsError.insets.left = 175; errorPanel.add(label3, gridBagConstraintsError); } gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.REMAINDER; gridBagConstraints.insets.bottom = 10; statPanel.add(errorPanel, gridBagConstraints); } // The last component. It will push everything up. JLabel label = new JLabel(""); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 1; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; statPanel.add(label, gridBagConstraints); statPanel.invalidate(); statPanel.validate(); statPanel.repaint(); } public void updateStackView(long stackId) { if (stackId == 0 /*null*/) { stack_view.reset(); // update stack in right-hand tab return; // Request for details about uninstrumented code is not supported yet. } AnUtility.checkIPCOnWrongThread(false); long[] pcs = window.getStackPCs(stackId); // IPC! String[] pcnames = window.getStackNames(stackId); // IPC! long[] funcs = window.getStackFunctions(stackId); // IPC! String[] fnames = window.getFuncNames(funcs); // IPC! AnUtility.checkIPCOnWrongThread(true); Vector<StackState> state_vec = new Vector<StackState>(); int i; for (i = 0; i < funcs.length; i++) { StackViewState svstate = new StackViewState(fnames[i], pcnames[i], funcs[i], pcs[i]); state_vec.add(svstate); } final int selected_frame = funcs.length - 1; clmap.addStates(state_vec); AnUtility.checkIPCOnWrongThread(false); stack_view.setStates( state_vec, selected_frame); // update stack in right-hand tab // FIXUP: don't do this on AWT AnUtility.checkIPCOnWrongThread(true); stack_view.setStackId(stackId); stackViewPane.setVisible(true); stackViewPane.revalidate(); AnWindow.getInstance().setSubviewReadyToShow("ioCallStackSubview", true); } // Listener for updating table private final class TableHandler implements AnListener { @Override public void valueChanged(final AnEvent event) { switch (event.getType()) { case AnEvent.EVT_SELECT: // Selecting if (actButton.isSelected()) { fileRowId = event.getValue(); computed = false; AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IO); window.getSelectionManager().updateSelection(ids, DSP_IO, subtype, 1); } } }); } else if (detButton.isSelected()) { vfdRowId = event.getValue(); ; computed = false; AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IOFileDescriptors); window .getSelectionManager() .updateSelection(ids, DSP_IOFileDescriptors, subtype, 1); } } }); } else if (calStkButton.isSelected()) { stackRowId = event.getValue(); computed = false; AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { long id = dataCalStkIds[stackRowId]; int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_IOCallStacks); window .getSelectionManager() .updateSelection(ids, DSP_IOCallStacks, subtype, 1); } updateStackView(id); } }); } break; case AnEvent.EVT_SORT: // Sorting // save current scroll location updateIfNotSort = false; getSettings() .getMetricsSetting() .setSortMetricByDType(this, ((Integer) event.getAux()).intValue(), type); break; case AnEvent.EVT_COPY_ALL: // Copy all lines copyAll(); break; case AnEvent.EVT_COPY_SEL: // Copy selected lines copySelected(); break; case AnEvent.EVT_SWITCH: // Column switching if (table != null) { table.columnsSaved = false; } int from = event.getValue(); int to = ((Integer) event.getAux()).intValue(); getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, type); break; case AnEvent.EVT_UPDATE: // setUpdated(false); break; case AnEvent.EVT_COMPUTE: computed = false; break; } } } // color change(s) @Override public void valueChanged(AnEvent e) { // setUpdated(false); stack_view.repaint(); } // Set selected function private void updateSummary(final StackState tmpstate) { if (!(tmpstate instanceof StackViewState)) { System.err.println("XXXmpview ioactivitydisp: not StackViewState"); return; } StackViewState state = (StackViewState) tmpstate; final long sel_func; final long sel_pc; sel_func = state.getNumber(); sel_pc = state.getPC(); long sel_obj = window.getSelectedObject().getObject(sel_func, sel_pc); if (sel_obj != 0L) { window.getSelectedObject().setSelObj(sel_obj, AnDisplay.DSP_IO, 0); // lazy computing may be needed for if Summary is not been selected if (window.getViews().getCurrentViewDisplay() == window.getIOView()) { int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, getDisplayMode()); window.getSelectionManager().updateSelection(ids, getDisplayMode(), 0, 1); } } else { AnWindow.getInstance() .getViews() .getCurrentViewDisplay() .computeOnAWorkerThread(); // Update selection. FIXUP: Views that react on selections // should change selction on SELECTION_CHANGED or // SELECTED_OBJECT_CHANGED events if not from own view } } } @Override public void adjustmentValueChanged(final AdjustmentEvent e) { revalidate(); } @Override public void mouseClicked(final MouseEvent event) { if (SwingUtilities.isLeftMouseButton(event)) { funcChanged(event); } if (SwingUtilities.isRightMouseButton(event)) { stackViewPopupListener.maybeShowPopup(event); } } @Override public void mouseEntered(final MouseEvent event) {} @Override public void mouseExited(final MouseEvent event) {} @Override public void mousePressed(final MouseEvent event) {} @Override public void mouseReleased(final MouseEvent event) {} // Will be needed if I want to update summary tab based on selection @Override public void valueChanged(final ListSelectionEvent event) { funcChanged(event); } // (MUST BE CALLED ON AWT THREAD) public void funcChanged(EventObject event) { final JList list; StackState state = null; if (event instanceof MouseEvent) { if (window.getColorChooser().isVisible()) { window.getColorChooser().setVisible(true); } if (((MouseEvent) event).getClickCount() > 1) { window.setSelectedView(AnDisplay.DSP_Source); } } else if (window.getColorChooser().isVisible()) { window.getColorChooser().setVisible(true); } if (event.getSource() instanceof StackView) { list = stack_view; state = (StackState) list.getSelectedValue(); } else { // XXXmpview, figure this out... // System.err.println("XXXmpview ioactivitydisp: eventsource unknown"); return; } if (state == null) { return; } stack_view.setSelectedFunction(state.getNumber()); // is this redundant? window.getColorChooser().setSelectedFunction(state.getNumber()); updateSummary(state); } @Override protected boolean supportsFindText() { return true; } // Find @Override public int find(final String str, final boolean next, boolean caseSensitive) { int find_row; if ((str == null) || (str.length() == 0)) { return -1; } find_row = table.findAfter(str, next, caseSensitive); if (find_row == -1) { find_row = table.findBefore(str, next, caseSensitive); } // Update summary display if (find_row != -1) { goToLine(table, find_row); } return find_row; } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String text = super.exportAsText(limit, format, delimiter); // exports the main table // Export lower panel if format is TEXT if (format == ExportFormat.TEXT && (limit == null || limit >= 0)) { statisticsData = getIOStatistics(); text += exportStatisticsData(statisticsData); } return text; } // Native methods from liber_dbe.so private String[][] getIOStatistics() { synchronized (IPC.lock) { window.IPC().send("getIOStatistics"); window.IPC().send(0); return (String[][]) window.IPC().recvObject(); } } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); if (calStkButton.isSelected()) { list.add(window.getIoCallStackSubview()); } return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); if (calStkButton.isSelected()) { list.add(window.getIoCallStackSubview()); } return list; } @Override public void goToLine(final AnTable tbl, final int row) { tbl.setSelectedRow(row); int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, getDisplayMode()); window.getSelectionManager().updateSelection(ids, getDisplayMode(), subtype, 1); if (calStkButton.isSelected()) { long id = dataCalStkIds[row]; updateStackView(id); } } } } ����������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/CannotFindFilePanel.form�������������������������������������������0000644�0001750�0001750�00000010575�14517772113�020435� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,2,10"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="textLabel"> <Properties> <Property name="text" type="java.lang.String" value="jLabel1"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="pathTextField"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="null"/> </Property> <Property name="opaque" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="resolveButton"> <Properties> <Property name="text" type="java.lang.String" value="jButton1"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="resolveButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> �����������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/����������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�015640� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/���������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�017144� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/IOEvent.java���������������������������������������0000644�0001750�0001750�00000005442�14517772113�021230� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnInteger; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnLong; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.timeline2.TimelineVariable; import java.awt.Color; import java.util.List; import javax.swing.ImageIcon; public class IOEvent extends ExtendedEvent implements DurationEvent, StateEvent { protected final String[] LABELS = { AnLocale.getString("IO Type:"), // NOI18N AnLocale.getString("IO File Descriptor:"), // NOI18N AnLocale.getString("IO Bytes:"), // NOI18N AnLocale.getString("Duration (msec.):") // NOI18N }; public final int type; // IO Type public final int fd; // File Descriptor public final long bytes; // Number of bytes public final long duration; // in nanosec private final String[] eventSpecificInfo; public IOEvent( int lwpid, int thrid, int cpuid, long ts, long stack, long func, List<StackState> stackStates, int type, int fd, long bytes, long duration, long time_adjust) { super(lwpid, thrid, cpuid, ts, stack, func, time_adjust, stackStates); this.type = type; this.fd = fd; this.bytes = bytes; this.duration = duration; this.eventSpecificInfo = initEventSpecificInfo(); } public String[] getEventSpecificInfo() { String[] rc = this.eventSpecificInfo.clone(); return rc; } private String[] initEventSpecificInfo() { String typename; typename = TimelineVariable.iotype_info.getNameByRawIdx(type); return new String[] { typename, new AnInteger(fd).toString(), new AnLong(bytes).toString(), new AnLong(duration).toTime(.000001) }; } public String[] getEventSpecificLabels() { return LABELS; } public long getDuration() { return duration; } public ImageIcon[] getEventSpecificIcons() { Color color = TimelineVariable.iotype_info.getColorByRawIdx(type); ImageIcon icon = new ImageIcon(StackState.createIcon(color)); return new ImageIcon[] { icon, null, null, null, }; } public int getState() { return type; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/ProfileEvent.java����������������������������������0000644�0001750�0001750�00000005171�14517772113�022320� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnLong; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.timeline2.TimelineVariable; import java.awt.Color; import java.util.List; import javax.swing.ImageIcon; public final class ProfileEvent extends ExtendedEvent implements DurationEvent, StateEvent { private final String[] LABELS = { AnLocale.getString("Duration (msec.):"), // NOI18N AnLocale.getString("Thread State:") // NOI18N }; private final int mstate; private final long interval; // in nanosec private final long duration; // visual duration, in nanosec private final int ompstate; private final String[] eventSpecificInfo; public ProfileEvent( int lwpid, int thrid, int cpuid, long ts, long stack, long func, List<StackState> stackStates, int mstate, long interval, int ompstate, long duration, long time_adjust) { super(lwpid, thrid, cpuid, ts, stack, func, time_adjust, stackStates); this.mstate = mstate; this.ompstate = ompstate; // YXXX unused for now this.interval = interval; this.duration = duration; this.eventSpecificInfo = initEventSpecificInfo(); } public String[] getEventSpecificInfo() { String[] rc = this.eventSpecificInfo.clone(); return rc; } private String[] initEventSpecificInfo() { String state = TimelineVariable.mstate_info.getNameByRawIdx(mstate); return new String[] { new AnLong(interval).toTime(0.000001), state, }; } public String[] getEventSpecificLabels() { return LABELS; } public ImageIcon[] getEventSpecificIcons() { Color color = TimelineVariable.mstate_info.getColorByRawIdx(mstate); ImageIcon icon = new ImageIcon(StackState.createIcon(color)); return new ImageIcon[] { null, icon, }; } public long getDuration() { return duration; } public int getState() { return mstate; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/RaceEvent.java�������������������������������������0000644�0001750�0001750�00000005335�14517772113�021574� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnAddress; import org.gprofng.mpmt.AnInteger; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.statecolors.StackState; import java.util.List; public final class RaceEvent extends ExtendedEvent { private static final int WRITE_RACE = 0; private static final int WRITE_RACE_RED = 1; private static final int READ_RACE = 2; private static final int READ_RACE_RED = 3; private static final String[] TYPES = { AnLocale.getString("Write"), // NOI18N AnLocale.getString("Write Red"), // NOI18N AnLocale.getString("Read"), // NOI18N AnLocale.getString("Read Red") // NOI18N }; private static final String TYPE = AnLocale.getString("Type:"); // NOI18N private static final String RACE_ID = AnLocale.getString("Race ID:"); // NOI18N private static final String ADDRESS = AnLocale.getString("Address:"); // NOI18N private static final String[] GENERIC_RACE_LABELS = {TYPE, ADDRESS, RACE_ID}; private final int type; private final int race_id; private final long vaddr; public RaceEvent( final int lwpid, final int thrid, final int cpuid, final long ts, final long stack, final long func, List<StackState> stackStates, final int type, final int race_id, final long vaddr, long time_adjust) { super(lwpid, thrid, cpuid, ts, stack, func, time_adjust, stackStates); this.type = type; this.race_id = race_id; this.vaddr = vaddr; } public String[] getEventSpecificInfo() { // fixme what about redundancy flag bit? switch (type) { case WRITE_RACE: case WRITE_RACE_RED: case READ_RACE: case READ_RACE_RED: return new String[] { TYPES[type], AnAddress.toHexString(vaddr), new AnInteger(race_id).toString() }; } return null; } public String[] getEventSpecificLabels() { switch (type) { case WRITE_RACE: case WRITE_RACE_RED: case READ_RACE: case READ_RACE_RED: return GENERIC_RACE_LABELS; } return null; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/EventDetail.java�����������������������������������0000644�0001750�0001750�00000003745�14517772113�022127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ // @(#)EventDetail.java 1.21 11/06/09 package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.statecolors.StackState; import java.util.List; import javax.swing.ImageIcon; public abstract class EventDetail { public static final int NO_CPU_INFO = -1; private static final String[] DUMMY_STRINGS = {}; // private final static char[] DUMMY_MNEMONICS = { }; private static final ImageIcon[] DUMMY_ICONS = {}; // TODO: adjust should be moved to DBE so filters work as expected for time-adjust experiments protected final long timestamp; // adjusted timestamp, e.g. as viewed in timeline private final long org_time; // original timestamp public EventDetail(final long original_time, final long time_adjust) { timestamp = original_time - time_adjust; org_time = original_time; } public final long getTimestamp() { return timestamp; } public abstract long getStack(); // for none, DetailsIPC.INVALID_STACK_ID public abstract List<StackState> getStackStates(); // for none, returns NULL public String[] getEventSpecificLabels() { return DUMMY_STRINGS; } public String[] getEventSpecificInfo() { return DUMMY_STRINGS; } // public char[] getEventSpecificMnemonics() { // return DUMMY_MNEMONICS; // } public ImageIcon[] getEventSpecificIcons() { return DUMMY_ICONS; } } ���������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/HWCEvent.java��������������������������������������0000644�0001750�0001750�00000014724�14517772113�021345� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnAddress; import org.gprofng.mpmt.AnInteger; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnLong; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.statecolors.StackState; import java.util.List; public final class HWCEvent extends ExtendedEvent { private static final String INTERVAL = AnLocale.getString("Interval:"); // NOI18N private static final String FREQ = AnLocale.getString("Clock Freq (MHz):"); // NOI18N private static final String DATAVADDR = AnLocale.getString("Data Virtual Addr:"); // NOI18N private static final String DATAPADDR = AnLocale.getString("Data Physical Addr:"); // NOI18N private static final String PCVADDR = AnLocale.getString("PC Virtual Addr:"); // NOI18N private static final String PCPADDR = AnLocale.getString("PC Physical Addr:"); // NOI18N private static final String DATADESC = AnLocale.getString("Data Descriptor:"); // NOI18N private static final String[] LABELS = {INTERVAL}; private static final String[] LABELS2 = {INTERVAL, FREQ}; private static final String[] XLABELS = { INTERVAL, DATAVADDR, DATAPADDR, PCVADDR, PCPADDR, DATADESC }; private static final String[] XLABELS2 = { INTERVAL, FREQ, DATAVADDR, DATAPADDR, PCVADDR, PCPADDR, DATADESC }; // ABS encodings must match definitions in ABS.h private static final long ABS_NULL = 0x00L; private static final long ABS_CODE_RANGE = 0xFFL; private static final long ABS_RT_CODEMASK = 0x0FL; private static final long ABS_PP_CODEMASK = 0xF0L; private static final String[] ABS_RT_CODES = { "", // NOI18N AnLocale.getString("(Internal error)"), // NOI18N AnLocale.getString("(Backtracking blocked)"), // NOI18N AnLocale.getString("(Backtracking incomplete)"), // NOI18N AnLocale.getString("(Register lost)"), // NOI18N AnLocale.getString("(Invalid address)"), // NOI18N AnLocale.getString("(UNKNOWN)") // NOI18N }; private static final String[] ABS_PP_CODES = { "", // NOI18N AnLocale.getString("(No Symbolic Information)"), // NOI18N AnLocale.getString("(Backtracking failed)"), // NOI18N AnLocale.getString("(Blocked by branch target)"), // NOI18N AnLocale.getString("(<POST-PROCESSING ERROR>)") // NOI18N }; // passed to constructor private final AnWindow m_window; private final long interval; private final long eventEA, eventPA, eventVPC, eventPPC; private final int cpu_freq; private final String[] eventSpecificInfo; private final String[] eventSpecificLabels; public HWCEvent( final AnWindow awindow, int lwpid, int thrid, int cpuid, // IPC!! long ts, long stack, long func, List<StackState> stackStates, long interval, long eventEA, long eventPA, long eventVPC, long eventPPC, int cpu_freq, long time_adjust) { super(lwpid, thrid, cpuid, ts, stack, func, time_adjust, stackStates); this.m_window = awindow; this.interval = interval; this.eventEA = eventEA; this.eventPA = eventPA; this.eventVPC = eventVPC; this.eventPPC = eventPPC; this.cpu_freq = cpu_freq; this.eventSpecificInfo = ipcInitEventSpecificInfo(); this.eventSpecificLabels = initEventSpecificLabels(); } private String ipcGetDataspaceTypeDesc() { long stack = super.getStack(); return ipcGetDataspaceTypeDesc(stack); } private String getDataAddress() { int rt_code, pp_code; if (0 > eventEA || eventEA > ABS_CODE_RANGE) return AnAddress.toHexString(eventEA); else { rt_code = (int) (eventEA & ABS_RT_CODEMASK); pp_code = (int) (eventEA & ABS_PP_CODEMASK) / 0xF; if (rt_code > ABS_RT_CODES.length) rt_code = ABS_RT_CODES.length - 1; if (pp_code > ABS_PP_CODES.length) pp_code = ABS_PP_CODES.length - 1; return ABS_PP_CODES[pp_code] + ABS_RT_CODES[rt_code]; } } private String getPhysicalAddress() { if (eventPA != ABS_NULL) return AnAddress.toHexString(eventPA); else return ""; } private String getVirtualPC() { if (eventVPC != ABS_NULL) return AnAddress.toHexString(eventVPC); else return ""; } private String getPhysicalPC() { if (eventPPC != ABS_NULL) return AnAddress.toHexString(eventPPC); else return ""; } public String[] getEventSpecificInfo() { String[] rc = eventSpecificInfo.clone(); return rc; } // eventEA is only defined for XHWC records private String[] ipcInitEventSpecificInfo() { if ((cpu_freq == 0) && (eventEA == ABS_NULL)) return new String[] {new AnLong(interval).toString()}; else if (eventEA == ABS_NULL) return new String[] {new AnLong(interval).toString(), new AnInteger(cpu_freq).toString()}; else if (cpu_freq == 0) return new String[] { new AnLong(interval).toString(), getDataAddress(), getPhysicalAddress(), getVirtualPC(), getPhysicalPC(), ipcGetDataspaceTypeDesc() }; else return new String[] { new AnLong(interval).toString(), new AnInteger(cpu_freq).toString(), getDataAddress(), getPhysicalAddress(), getVirtualPC(), getPhysicalPC(), ipcGetDataspaceTypeDesc() }; } public String[] getEventSpecificLabels() { String[] rc = this.eventSpecificLabels.clone(); return rc; } private String[] initEventSpecificLabels() { if ((cpu_freq == 0) && (eventEA == ABS_NULL)) return LABELS; else if (eventEA == ABS_NULL) return LABELS2; else if (cpu_freq == 0) return XLABELS; else return XLABELS2; } // Native methods from liber_dbe.so private String ipcGetDataspaceTypeDesc(long stack) { synchronized (IPC.lock) { m_window.IPC().send("getDataspaceTypeDesc"); // NOI18N m_window.IPC().send(stack); return m_window.IPC().recvString(); } } } ��������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/SyncEvent.java�������������������������������������0000644�0001750�0001750�00000003775�14517772113�021644� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnAddress; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnLong; import org.gprofng.mpmt.statecolors.StackState; import java.util.List; public class SyncEvent extends ExtendedEvent implements DurationEvent { protected final String[] LABELS = { AnLocale.getString("Duration (msec.):"), // NOI18N AnLocale.getString("Lock Address:") // NOI18N }; public final long duration; // in nanosec public final long sobj; // synchronization object (f.e. mutex) private final String[] eventSpecificInfo; public SyncEvent( int lwpid, int thrid, int cpuid, long ts, long stack, long func, List<StackState> stackStates, long duration, long sobj, long time_adjust) { super(lwpid, thrid, cpuid, ts, stack, func, time_adjust, stackStates); this.duration = duration; this.sobj = sobj; this.eventSpecificInfo = initEventSpecificInfo(); } public String[] getEventSpecificInfo() { String[] rc = this.eventSpecificInfo.clone(); return rc; } private String[] initEventSpecificInfo() { return new String[] {new AnLong(duration).toTime(.000001), AnAddress.toHexString(sobj)}; } public String[] getEventSpecificLabels() { return LABELS; } public long getDuration() { return duration; } } ���gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/MPIEvent.java��������������������������������������0000644�0001750�0001750�00000005046�14517772113�021346� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnInteger; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnLong; import org.gprofng.mpmt.statecolors.StackState; import java.util.List; public final class MPIEvent extends ExtendedEvent implements DurationEvent { private final String[] LABELS = { AnLocale.getString("Duration (msec.):"), // NOI18N AnLocale.getString("Sub-Type:"), // NOI18N AnLocale.getString("Message Count:"), // NOI18N AnLocale.getString("Bytes:") // NOI18N }; // This order has to match what's in data_pckts.h for MPI stuff private static final String[] MPITYPES = { "mpisend", // NOI18N "mpireceive", // NOI18N "mpisendrecv", // NOI18N "mpiother" // NOI18N }; // passed to constructor private final long duration; // in nanosec private final int sub_type, msg_cnt; private final long msg_bytes; private final String[] eventSpecificInfo; public MPIEvent( int lwpid, int thrid, int cpuid, long ts, long stack, long func, List<StackState> stackStates, long duration, int msg_cnt, int sub_type, long msg_bytes, long time_adjust) { super(lwpid, thrid, cpuid, ts, stack, func, time_adjust, stackStates); this.duration = duration; this.sub_type = sub_type; this.msg_cnt = msg_cnt; this.msg_bytes = msg_bytes; this.eventSpecificInfo = initEventSpecificInfo(); } public String[] getEventSpecificInfo() { String[] rc = this.eventSpecificInfo.clone(); return rc; } private String[] initEventSpecificInfo() { return new String[] { new AnLong(duration).toTime(.000001), MPITYPES[sub_type], new AnInteger(msg_cnt).toString(), new AnLong(msg_bytes).toString() }; } public String[] getEventSpecificLabels() { return LABELS; } public long getDuration() { return duration; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/DeadlockEvent.java���������������������������������0000644�0001750�0001750�00000005365�14517772113�022433� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnAddress; import org.gprofng.mpmt.AnInteger; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.statecolors.StackState; import java.util.List; public final class DeadlockEvent extends ExtendedEvent { private static final String[] TYPES = { AnLocale.getString("Lock Held"), // NOI18N AnLocale.getString("Lock Requested"), // NOI18N AnLocale.getString("<Unknown>"), // NOI18N }; private static final String[] DLTYPES = { AnLocale.getString("Potential Deadlock"), // NOI18N AnLocale.getString("Actual Deadlock"), // NOI18N AnLocale.getString("<Unknown>"), // NOI18N }; private static final String TYPE = AnLocale.getString("Lock Event:"); // NOI18N private static final String DLTYPE = AnLocale.getString("Deadlock Type:"); // NOI18N private static final String DEADLOCK_ID = AnLocale.getString("Deadlock ID:"); // NOI18N private static final String ADDRESS = AnLocale.getString("Address:"); // NOI18N private static final String[] GENERIC_RACE_LABELS = {TYPE, DLTYPE, ADDRESS, DEADLOCK_ID}; private final int type; private final int dltype; private final int deadlock_id; private final long vaddr; public DeadlockEvent( final int lwpid, final int thrid, final int cpuid, final long ts, final long stack, final long func, List<StackState> stackStates, final int type, final int dltype, final int deadlock_id, final long vaddr, long time_adjust) { super(lwpid, thrid, cpuid, ts, stack, func, time_adjust, stackStates); this.type = (type >= 0 && type < TYPES.length) ? type : TYPES.length - 1; this.dltype = (dltype >= 0 && dltype < DLTYPES.length) ? dltype : DLTYPES.length - 1; this.deadlock_id = deadlock_id; this.vaddr = vaddr; } public String[] getEventSpecificInfo() { return new String[] { TYPES[type], DLTYPES[dltype], AnAddress.toHexString(vaddr), new AnInteger(deadlock_id).toString() }; } public String[] getEventSpecificLabels() { return GENERIC_RACE_LABELS; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/Sample.java����������������������������������������0000644�0001750�0001750�00000014210�14517772113�021131� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnDouble; import org.gprofng.mpmt.AnInteger; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.timeline2.TimelineVariable; import java.awt.Color; import java.util.List; import javax.swing.*; public class Sample extends EventDetail implements DurationEvent { private static final double DIV = 1000000000.0; private static ImageIcon[] allIcons; private static Object allIconsLock = new Object(); private static String[] allLabels; private static Object allLabelsLock = new Object(); private static final String[] LABELS = { AnLocale.getString("Process:"), // NOI18N AnLocale.getString("Sample Number:"), // NOI18N AnLocale.getString("Sample Start Label:"), // NOI18N AnLocale.getString("Sample End Label:"), // NOI18N AnLocale.getString("Start Time (sec.):"), // NOI18N AnLocale.getString("End Time (sec.):"), // NOI18N AnLocale.getString("Duration (sec.):"), // NOI18N }; // private final static char[] MNEMONICS = { // AnLocale.getString('E', "MNEM_SAMPLE_EXPERIMENT_NAME"), // NOI18N // AnLocale.getString('m', "MNEM_SAMPLE_SAMPLE_NUMBER"), // NOI18N // AnLocale.getString('L', "MNEM_SAMPLE_SAMPLE_START_LABEL"), // NOI18N // AnLocale.getString('b', "MNEM_SAMPLE_SAMPLE_END_LABEL"), // NOI18N // AnLocale.getString('a', "MNEM_SAMPLE_START_TIME"), // NOI18N // AnLocale.getString('n', "MNEM_SAMPLE_END_TIME"), // NOI18N // AnLocale.getString('D', "MNEM_SAMPLE_DURATION"), // NOI18N // }; // passed to constructor private final int number; private final String start_label, end_label; private final long duration; // in nanosec private final long total; // resource usage in nanosec private final long[] mstates; // resource usage in nanosec private final String expname; private final String[] eventSpecificInfo; private final String[] eventSpecificLabels; // Constructor public Sample( int number, String start_label, String end_label, long start_time, long end_time, long total, long[] mstates, String expname, long time_adjust) { super(end_time, time_adjust); // event timestamps are end times, not start times this.number = number; this.start_label = start_label; this.end_label = end_label; this.duration = end_time - start_time; this.total = total; this.mstates = mstates; this.expname = expname; this.eventSpecificInfo = initEventSpecificInfo(); this.eventSpecificLabels = initEventSpecificLabels(); } public long getStack() { return DetailsIPC.INVALID_STACK_ID; } public final List<StackState> getStackStates() { return null; } public String getStartLabel() { return start_label; } public String getEndLabel() { return end_label; } public long getTotalTime() { return total; } public long getDuration() { return duration; } public Object getData() { return mstates; } public long[] getMStates() { return mstates; } public String[] getEventSpecificLabels() { String[] rc = this.eventSpecificLabels.clone(); return rc; } private String[] initEventSpecificLabels() { synchronized (allLabelsLock) { if (allLabels == null) { int idx = 0; allLabels = new String[LABELS.length + TimelineVariable.NUM_SOLARIS_MSTATES]; for (int ii = 0; ii < LABELS.length; ii++) { allLabels[idx++] = LABELS[ii]; } for (int ii = 0; ii < TimelineVariable.NUM_SOLARIS_MSTATES; ii++) { allLabels[idx++] = TimelineVariable.mstate_info.getNameByDisplayIdx(ii); } } return allLabels; } } public String[] getEventSpecificInfo() { String[] rc = eventSpecificInfo.clone(); return rc; } private String[] initEventSpecificInfo() { String[] strings; strings = new String[LABELS.length + TimelineVariable.NUM_SOLARIS_MSTATES]; strings[0] = expname; strings[1] = new AnInteger(number).toString(); strings[2] = start_label; strings[3] = end_label; strings[4] = TimelineVariable.strTimestamp(super.getTimestamp() - duration); strings[5] = TimelineVariable.strTimestamp(super.getTimestamp()); strings[6] = TimelineVariable.strTimestamp(duration); // int numLabels = LABELS.length + TimelineVariable.NUM_SOLARIS_MSTATES; for (int ii = 0; ii < mstates.length; ii++) { int idx = TimelineVariable.mstate_info.getDisplayIdx(ii); if (idx >= 0 && idx < TimelineVariable.NUM_SOLARIS_MSTATES) { double time = mstates[ii]; double percent = total == 0 ? total : (time / total) * 100; int labelIdx = LABELS.length + idx; // numLabels-1-idx; strings[labelIdx] = new AnDouble(time / DIV).toPercentQuote(percent); } else { ; // unexpected } } return strings; } public ImageIcon[] getEventSpecificIcons() { synchronized (allIconsLock) { if (allIcons == null) { allIcons = new ImageIcon[LABELS.length + TimelineVariable.NUM_SOLARIS_MSTATES]; int idx = LABELS.length; for (int ii = 0; ii < TimelineVariable.NUM_SOLARIS_MSTATES; ii++) { Color c = TimelineVariable.mstate_info.getColorByDisplayIdx(ii); allIcons[idx++] = new ImageIcon(StackState.createIcon(c)); } } return allIcons; } } // public char[] getEventSpecificMnemonics() { // return MNEMONICS; // } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/DurationEvent.java���������������������������������0000644�0001750�0001750�00000001402�14517772113�022476� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; public interface DurationEvent { public long getDuration(); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/ExtendedEvent.java���������������������������������0000644�0001750�0001750�00000003530�14517772113�022455� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.statecolors.StackState; import java.util.Collections; import java.util.List; public abstract class ExtendedEvent extends EventDetail { private final int lwpid; private final int thrid; private final int cpuid; private final Long stack; private final List<StackState> stackStates; private final long func; // leaf function public ExtendedEvent( final int lwpid, final int thrid, final int cpuid, final long ts, final long stack, final long func, long time_adjust, final List<StackState> stackStates) { super(ts, time_adjust); this.lwpid = lwpid; this.thrid = thrid; this.cpuid = cpuid; if (stack != 0) this.stack = new Long(stack); else this.stack = null; this.stackStates = Collections.unmodifiableList(stackStates); this.func = func; } public final int getLWP() { return lwpid; } public final int getThread() { return thrid; } public final int getCPU() { return cpuid; } public final long getStack() { return stack.longValue(); } public final List<StackState> getStackStates() { return stackStates; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/HeapEvent.java�������������������������������������0000644�0001750�0001750�00000013455�14517772113�021601� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnAddress; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnLong; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.timeline2.TimelineVariable; import java.awt.Color; import java.util.List; import javax.swing.ImageIcon; public final class HeapEvent extends ExtendedEvent implements StateEvent { private static final int MALLOC = 0; private static final int FREE = 1; private static final int REALLOC = 2; private static final int MMAP = 3; private static final int MUNMAP = 4; private static final String TYPE = AnLocale.getString("Type:"); // NOI18N private static final String ALLOCATED = AnLocale.getString("Event Bytes Allocated:"); // NOI18N private static final String ADDRESS = AnLocale.getString("Address:"); // NOI18N private static final String OADDRESS = AnLocale.getString("Old Address:"); // NOI18N private static final String LEAKED = AnLocale.getString("Event Bytes Leaked:"); // NOI18N private static final String FREED = AnLocale.getString("Event Bytes Freed:"); // NOI18N private static final String HEAPSZ = AnLocale.getString("Net Bytes Allocated:"); // NOI18N private static final String LEAKSZ = AnLocale.getString("Net Bytes Leaked:"); // NOI18N private static final String[] MALLOC_LABELS = { TYPE, ALLOCATED, LEAKED, ADDRESS, HEAPSZ, LEAKSZ, }; private static final String[] FREE_LABELS = { TYPE, FREED, ADDRESS, HEAPSZ, LEAKSZ, }; private static final String[] REALLOC_LABELS = { TYPE, ALLOCATED, FREED, LEAKED, ADDRESS, OADDRESS, HEAPSZ, LEAKSZ, }; private static final String[] MMAP_LABELS = { TYPE, ALLOCATED, FREED, LEAKED, ADDRESS, HEAPSZ, LEAKSZ, }; private static final String[] MUNMAP_LABELS = { TYPE, ALLOCATED, FREED, ADDRESS, HEAPSZ, LEAKSZ, }; private final int type; private final long allocated; private final long vaddr; private final long ovaddr; private final long leaked; private final long freed; private final long heapsz; private final long leaksz; private final String[] eventSpecificInfo; public HeapEvent( final int lwpid, final int thrid, final int cpuid, final long ts, final long stack, final long func, List<StackState> stackStates, final int type, final long allocated, final long vaddr, final long ovaddr, long leaked, long freed, long heapsz, long leaksz, long time_adjust) { super(lwpid, thrid, cpuid, ts, stack, func, time_adjust, stackStates); this.type = type; this.allocated = allocated; this.vaddr = vaddr; this.ovaddr = ovaddr; this.leaked = leaked; this.freed = freed; this.heapsz = heapsz; this.leaksz = leaksz; this.eventSpecificInfo = initEventSpecificInfo(); } public String[] getEventSpecificInfo() { String[] rc = this.eventSpecificInfo.clone(); return rc; } private String[] initEventSpecificInfo() { final String name = TimelineVariable.htype_info.getNameByRawIdx(type); switch (type) { case MALLOC: return new String[] { name, new AnLong(allocated).toString(), new AnLong(leaked).toString(), AnAddress.toHexString(vaddr), new AnLong(heapsz).toString(), new AnLong(leaksz).toString(), }; case MMAP: return new String[] { name, new AnLong(allocated).toString(), new AnLong(freed).toString(), new AnLong(leaked).toString(), AnAddress.toHexString(vaddr), new AnLong(heapsz).toString(), new AnLong(leaksz).toString(), }; case MUNMAP: return new String[] { name, new AnLong(allocated).toString(), new AnLong(freed).toString(), AnAddress.toHexString(vaddr), new AnLong(heapsz).toString(), new AnLong(leaksz).toString(), }; case FREE: return new String[] { name, new AnLong(freed).toString(), AnAddress.toHexString(vaddr), new AnLong(heapsz).toString(), new AnLong(leaksz).toString(), }; case REALLOC: return new String[] { name, new AnLong(allocated).toString(), new AnLong(freed).toString(), new AnLong(leaked).toString(), AnAddress.toHexString(vaddr), AnAddress.toHexString(ovaddr), new AnLong(heapsz).toString(), new AnLong(leaksz).toString(), }; } return null; } public String[] getEventSpecificLabels() { switch (type) { case MALLOC: return MALLOC_LABELS; case FREE: return FREE_LABELS; case REALLOC: return REALLOC_LABELS; case MMAP: return MMAP_LABELS; case MUNMAP: return MUNMAP_LABELS; } return null; } public ImageIcon[] getEventSpecificIcons() { Color color = TimelineVariable.htype_info.getColorByRawIdx(type); ImageIcon icon = new ImageIcon(StackState.createIcon(color)); return new ImageIcon[] { icon, null, null, null, }; } public int getState() { return type; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/StateEvent.java������������������������������������0000644�0001750�0001750�00000001373�14517772113�022000� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; public interface StateEvent { public int getState(); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline/events/DetailsIPC.java������������������������������������0000644�0001750�0001750�00000027063�14517772113�021643� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline.events; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.statecolors.StackViewState; import java.util.ArrayList; import java.util.List; // contents moved here from timeline.Experiment.java // Ideally, IPC related to TL details should be updated to use properties... public class DetailsIPC { public static final long INVALID_STACK_ID = -1; public static EventDetail ipcGetTLDetails( AnWindow m_window, int exp_id, String exp_name, int data_id, Settings.TLData_type tl_type, int entity_prop_id, long event_id, int cpu_freq, long time_adjust) { final EventDetail[] events; if (tl_type.equals(Settings.TLData_type.TL_SAMPLE)) { // YXXX samples has separate processing. Fix when old TL removed events = ipcGetSampleObjs(m_window, exp_id, event_id, event_id, exp_name, time_adjust); } else if (tl_type.equals(Settings.TLData_type.TL_GCEVENT)) { // CXXX Bug 20801848 events = ipcGetGCEventObjs(m_window, exp_id, event_id, event_id, exp_name, time_adjust); } else { final Object[] detailVals; detailVals = ipcGetTLDetails(m_window, exp_id, data_id, entity_prop_id, event_id); if (detailVals == null) { return null; } final long[] values = (long[]) detailVals[0]; final long[] funcs = (long[]) detailVals[1]; final String[] funcNames = (String[]) detailVals[2]; final long[] pcs = (long[]) detailVals[3]; final String[] pcNames = (String[]) detailVals[4]; List<StackState> stackStates = new ArrayList<StackState>(); for (int i = 0; i < funcs.length; i++) { StackViewState svstate = new StackViewState(funcNames[i], pcNames[i], funcs[i], pcs[i]); stackStates.add(svstate); } // To avoid changing legacy code in ipcFinish_getTLDetailsEvents(), set up arrays of details // here: final long[][] list = new long[1][]; list[0] = values; final List<List<StackState>> stackStatesList = new ArrayList<>(); stackStatesList.add(stackStates); events = ipcFinish_getTLDetailsEvents( m_window, list, stackStatesList, tl_type, cpu_freq, time_adjust); } if (events == null || events.length == 0) { return null; } return events[0]; } // TLData_type is defined in Presentation.java. Make sure // to update TLData_type if there is a new TL_?? type. Also, // The new TL_?? type has to match with the type that is // returned by getTLDetailValues(). This method is defined // in Dbe.cc. private static EventDetail[] ipcFinish_getTLDetailsEvents( AnWindow m_window, final long[][] list, List<List<StackState>> stackStatesList, final Settings.TLData_type tl_type, final int cpu_freq, final long time_adjust) { long[] value; final int size = list.length; final EventDetail events[] = new EventDetail[size]; switch (tl_type) { case TL_CLOCK: for (int i = 0; i < size; i++) { value = list[i]; events[i] = new ProfileEvent( (int) value[0], (int) value[1], (int) value[2], value[3], value[4], value[5], stackStatesList.get(i), (int) value[6], value[7], (int) value[8], value[9], time_adjust); } break; case TL_SYNC: for (int i = 0; i < size; i++) { value = list[i]; events[i] = new SyncEvent( (int) value[0], (int) value[1], (int) value[2], value[3], value[4], value[5], stackStatesList.get(i), value[6], value[7], time_adjust); } break; case TL_HWC: for (int i = 0; i < size; i++) { value = list[i]; events[i] = new HWCEvent( m_window, (int) value[0], (int) value[1], (int) value[2], value[3], value[4], value[5], stackStatesList.get(i), value[6], value[7], value[8], value[9], value[10], cpu_freq, time_adjust); } break; case TL_HEAP: case TL_HEAPSZ: for (int i = 0; i < size; i++) { value = list[i]; events[i] = new HeapEvent( (int) value[0], (int) value[1], (int) value[2], value[3], value[4], value[5], stackStatesList.get(i), (int) value[6], value[7], value[8], value[9], value[10], value[11], value[12], value[13], time_adjust); } break; case TL_IOTRACE: for (int i = 0; i < size; i++) { value = list[i]; events[i] = new IOEvent( (int) value[0], (int) value[1], (int) value[2], value[3], value[4], value[5], stackStatesList.get(i), (int) value[6], (int) value[7], value[8], value[9], time_adjust); } break; case TL_RACES: for (int i = 0; i < size; i++) { value = list[i]; events[i] = new RaceEvent( (int) value[0], (int) value[1], (int) value[2], value[3], value[4], value[5], stackStatesList.get(i), (int) value[6], (int) value[7], value[8], time_adjust); } break; case TL_DLCK: for (int i = 0; i < size; i++) { value = list[i]; events[i] = new DeadlockEvent( (int) value[0], (int) value[1], (int) value[2], value[3], value[4], value[5], stackStatesList.get(i), (int) value[6], (int) value[7], (int) value[8], value[9], time_adjust); } break; case TL_MPI: for (int i = 0; i < size; i++) { value = list[i]; events[i] = new MPIEvent( (int) value[0], (int) value[1], (int) value[2], value[3], value[4], value[5], stackStatesList.get(i), value[6], (int) value[7], (int) value[8], value[9], time_adjust); } break; default: break; // weird } return events; } private static Sample[] ipcGetSampleObjs( AnWindow m_window, int exp_id, long lo_idx, long hi_idx, String exp_name, long time_adjust) { Sample[] event; final Object[] objs = ipcGetSamples(m_window, exp_id, lo_idx, hi_idx); if (objs != null) { final long[][] array = (long[][]) objs[0]; final long[] starts = (long[]) objs[1]; final long[] ends = (long[]) objs[2]; final long[] rtimes = (long[]) objs[3]; final String[] start_label = (String[]) objs[4]; final String[] end_label = (String[]) objs[5]; final int[] samp_id = (int[]) objs[6]; int nsmp = array.length; event = new Sample[nsmp]; for (int i = 0; i < nsmp; i++) { long[] list = array[i]; long[] mstates = list.clone(); Sample samp = new Sample( samp_id[i], start_label[i], end_label[i], starts[i], ends[i], rtimes[i], mstates, exp_name, time_adjust); event[i] = samp; } } else { event = new Sample[0]; } return event; } // CXXX Bug 20801848 - return type may not be Sample[] private static Sample[] ipcGetGCEventObjs( AnWindow m_window, int exp_id, long lo_idx, long hi_idx, String exp_name, long time_adjust) { Sample[] event; final Object[] objs = ipcGetGCEvents(m_window, exp_id, lo_idx, hi_idx); if (objs != null) { final long[] starts = (long[]) objs[0]; final long[] ends = (long[]) objs[1]; final int[] gcevent_id = (int[]) objs[2]; int nsmp = gcevent_id.length; event = new Sample[nsmp]; long[] mstates = new long[0]; for (int i = 0; i < nsmp; i++) { Sample gcevent = new Sample( gcevent_id[i], null, null, starts[i], ends[i], ends[i] - starts[i], mstates, exp_name, time_adjust); event[i] = gcevent; } } else { event = new Sample[0]; } return event; } private static Object[] ipcGetTLDetails( AnWindow m_window, final int exp_id, final int data_id, final int entity_prop_id, final long event_id) { synchronized (IPC.lock) { m_window.IPC().send("getTLDetails"); // NOI18N m_window.IPC().send(0); m_window.IPC().send(exp_id); m_window.IPC().send(data_id); m_window.IPC().send(entity_prop_id); m_window.IPC().send(event_id); return (Object[]) m_window.IPC().recvObject(); } } private static Object[] ipcGetSamples( AnWindow m_window, final int exp_id, long hi_idx, long lo_idx) { synchronized (IPC.lock) { m_window.IPC().send("getSamples"); // NOI18N m_window.IPC().send(0); m_window.IPC().send(exp_id); m_window.IPC().send(hi_idx); m_window.IPC().send(lo_idx); return (Object[]) m_window.IPC().recvObject(); } } private static Object[] ipcGetGCEvents( AnWindow m_window, final int exp_id, long hi_idx, long lo_idx) { synchronized (IPC.lock) { m_window.IPC().send("getGCEvents"); // NOI18N m_window.IPC().send(0); m_window.IPC().send(exp_id); m_window.IPC().send(hi_idx); m_window.IPC().send(lo_idx); return (Object[]) m_window.IPC().recvObject(); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/event/�������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�015153� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/event/AnChangeListener.java����������������������������������������0000644�0001750�0001750�00000001441�14517772113�021073� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.event; /** * @author tpreisle */ public interface AnChangeListener { void stateChanged(AnChangeEvent e); } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/event/AnSelectionEvent.java����������������������������������������0000644�0001750�0001750�00000002646�14517772113�021137� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.event; import java.util.EventObject; public class AnSelectionEvent extends EventObject { private long[] selObj; private int type; private int subtype; private int version; public AnSelectionEvent(Object source, long[] selObj, int type, int subtype, int version) { super(source); this.selObj = selObj; this.type = type; this.subtype = subtype; this.version = version; } /** * @return the selObj */ public long[] getSelObj() { return selObj; } /** * @return the type */ public int getType() { return type; } /** * @return the subtype */ public int getSubtype() { return subtype; } /** * @return the version */ public int getVersion() { return version; } } ������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/event/AnEventManager.java������������������������������������������0000644�0001750�0001750�00000006746�14517772113�020571� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.event; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.util.gui.AnUtility; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @author tpreisle */ public class AnEventManager { private boolean logEvents = false; private static AnEventManager instance = null; private List<AnChangeListener> listenerList = null; private AnEventManager() { listenerList = new ArrayList<AnChangeListener>(); } /** * @return */ public static AnEventManager getInstance() { if (instance == null) { instance = new AnEventManager(); } return instance; } /** * @param listener */ public synchronized void addListener(AnChangeListener listener) { listenerList.add(listener); } /** * @param listener */ public synchronized void removeListener(AnChangeListener listener) { listenerList.remove(listener); } /** * Fire an AnChangeEvent. Events are always dispatched on AWT thread. Requirements to the event * handler: o When it done handling the event and returns, all the views states need to be * *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param changeEvent the event */ public void fireAnChangeEvent(final AnChangeEvent changeEvent) { long start = 0; if (logEvents) { start = new Date().getTime(); String type = changeEvent.getType().toString(); if (changeEvent.getType() == AnChangeEvent.Type.SETTING_CHANGED || changeEvent.getType() == AnChangeEvent.Type.SETTING_CHANGING) { AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) changeEvent.getSource(); type += " " + anSettingChangeEvent.getType(); } System.out.println("AnEventManager.fireChangeEventInternal begin: " + type); } AnUtility.dispatchOnSwingThread( new Runnable() { // REFACTOR: should this be non-blocking? // AnUtility.invokeLaterOnSwingThread(new Runnable() {// REFACTOR: should // this be non-blocking? @Override public void run() { fireAnChangeEventInternal(changeEvent); } }); if (logEvents) { String type = changeEvent.getType().toString(); System.out.println( "AnEventManager.fireChangeEventInternal end: " + type + " ms=" + (new Date().getTime() - start)); } } private synchronized void fireAnChangeEventInternal(final AnChangeEvent changeEvent) { for (AnChangeListener listener : listenerList) { listener.stateChanged(changeEvent); } } } ��������������������������gprofng-gui-1.0/org/gprofng/mpmt/event/AnChangeEvent.java�������������������������������������������0000644�0001750�0001750�00000005642�14517772113�020376� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.event; import java.util.EventObject; /** * @author tpreisle */ public class AnChangeEvent extends EventObject { public enum Type { MOST_RECENT_EXPERIMENT_LIST_CHANGED, // fired when there is a change to the most recent // experiments list REMOTE_CONNECTION_CHANGING, // fired when remote connection is about to change REMOTE_CONNECTION_CANCELLED_OR_FAILED, // fired if remove connection cancelled or failed REMOTE_CONNECTION_CHANGED, // fired when remote connection successfully connected FILTER_CHANGING, // fired when filters are about to change FILTER_CHANGED, // fired when filters have changed SOURCE_FINDING_CHANGING, // fired when find source are changing (archive, gp-display-text pathmap, ...) SOURCE_FINDING_CHANGED, // fired when find source are changing (archive, gp-display-text pathmap, ...) EXPERIMENTS_LOADING_NEW, // fired when new experiment(s) are about to be loaded from scratch EXPERIMENTS_LOADING_ADDED_OR_REMOVED, // fired when new experiment(s) are about to be added or // removed (compare, aggregate, ...) EXPERIMENTS_LOADED_FAILED, // fired when new experiment(s) failed to load EXPERIMENTS_LOADED, // fired when new experiment(s) loaded successfully SETTING_CHANGING, // fired when a setting is abot to change. SETTING_CHANGED, // fired when a setting is changed. SELECTED_OBJECT_CHANGED, // fired when selected object has changed from outside a main view // (CalledByCalls) SELECTION_UPDATE, // fired when selection should be changed. Handler of this event will fire a // SELECTION_CHANGING/SELECTION_CHANGED event SELECTION_CHANGING, // fired when selection is about to be changed. SELECTION_CHANGED, // fired when selection has changed. One handler of this event (Summary view) // will update Selection Details panel DEBUG, // for debugging TEST1, // for testing TEST2, // for testing } private final Type type; public AnChangeEvent(Object source, Type type) { super(source); this.type = type; } /** * @return the event type */ public Type getType() { return type; } } ����������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/SelectedObject.java������������������������������������������������0000644�0001750�0001750�00000017266�14517772113�017473� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.util.gui.AnUtility; public final class SelectedObject implements AnChangeListener { private long selObjectSelectionTime = 0; private boolean selObjWasSet = false; private long selIndex; private int selType; private int selSubType; public SelectedObject() { AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("RacesView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_NEW: resetSelectedObject(); break; case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADED_FAILED: case EXPERIMENTS_LOADED: // Nothing break; case FILTER_CHANGING: resetSelectedObject(); break; case FILTER_CHANGED: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SETTING_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } private void debug() { System.out.println(this.getClass().getSimpleName()); } public void setSelObjWithEvent(long index, int type, int subtype) { setSelObj(index, type, subtype); AnEventManager.getInstance() .fireAnChangeEvent(new AnChangeEvent(this, AnChangeEvent.Type.SELECTED_OBJECT_CHANGED)); } public void setSelObj(long index, int type, int subtype) { // System.out.println("setSelObj: " + index + " " + type + " " + subtype); synchronized (IPC.lock) { AnUtility.checkIPCOnWrongThread(false); getWindow().IPC().send("setSelObj"); getWindow().IPC().send(0); getWindow().IPC().send(index); getWindow().IPC().send(type); getWindow().IPC().send(subtype); getWindow().IPC().recvString(); // synchronize // store the selection selObjectSelectionTime = System.currentTimeMillis(); selObjWasSet = true; selIndex = index; selType = type; selSubType = subtype; AnUtility.checkIPCOnWrongThread(true); } } public boolean wasASelDone() { return selObjWasSet; } private void resetSelectedObject() { selObjWasSet = false; } public long getSelIndex() { return selIndex; } public int getSelType() { return selType; } public int getSelSubType() { return selSubType; } public long getSelObj(int type, int subtype) { synchronized (IPC.lock) { getWindow().IPC().send("getSelObj"); getWindow().IPC().send(0); getWindow().IPC().send(type); getWindow().IPC().send(subtype); long l = getWindow().IPC().recvLong(); // System.out.println("getSelObj: " + l); return l; } } public int getSelIndex(long sel_obj, int type, int subtype) { synchronized (IPC.lock) { getWindow().IPC().send("getSelIndex"); getWindow().IPC().send(0); getWindow().IPC().send(sel_obj); getWindow().IPC().send(type); getWindow().IPC().send(subtype); return getWindow().IPC().recvInt(); } } /** * @return the selObjectSelectionTime */ public long getSelObjectSelectionTime() { return selObjectSelectionTime; } /** * Get Selected Object. New API "V2" (version 2). Based on unique id. * * @param ConvertTo String "FUNCTION" * @return ID */ public long getSelObjV2(String ConvertTo) { synchronized (IPC.lock) { AnUtility.checkIPCOnWrongThread(false); getWindow().IPC().send("getSelObjV2"); getWindow().IPC().send(0); getWindow().IPC().send(ConvertTo); long res = getWindow().IPC().recvLong(); AnUtility.checkIPCOnWrongThread(true); return res; } } public void setSelObjV2WithEvent(long id) { setSelObjV2(id); AnEventManager.getInstance() .fireAnChangeEvent(new AnChangeEvent(this, AnChangeEvent.Type.SELECTED_OBJECT_CHANGED)); } public void setSelObjV2(long id) { // System.out.println("setSelObjV2: " + id); AnUtility.checkIPCOnWrongThread(false); synchronized (IPC.lock) { getWindow().IPC().send("setSelObjV2"); getWindow().IPC().send(0); getWindow().IPC().send(id); getWindow().IPC().recvString(); // synchronize // store the selection selObjectSelectionTime = System.currentTimeMillis(); selObjWasSet = true; } AnUtility.checkIPCOnWrongThread(true); } public long[] getSelObjIO(long id, int type) { synchronized (IPC.lock) { final IPC ipc = getWindow().IPC(); ipc.send("getSelObjIO"); ipc.send(0); ipc.send(id); ipc.send(type); return (long[]) ipc.recvObject(); } } public long[] getSelObjsIO(final long[] ids, int type) { synchronized (IPC.lock) { AnUtility.checkIPCOnWrongThread(false); final IPC ipc = getWindow().IPC(); ipc.send("getSelObjsIO"); ipc.send(0); ipc.send(ids); ipc.send(type); long[] ll = (long[]) ipc.recvObject(); AnUtility.checkIPCOnWrongThread(true); return ll; } } public long getSelObjHeapTimestamp(long id) { synchronized (IPC.lock) { final IPC ipc = getWindow().IPC(); ipc.send("getSelObjHeapTimestamp"); ipc.send(0); ipc.send(id); return (long) ipc.recvLong(); } } public int getSelObjHeapUserExpId(long id) { synchronized (IPC.lock) { final IPC ipc = getWindow().IPC(); ipc.send("getSelObjHeapUserExpId"); ipc.send(0); ipc.send(id); return (int) ipc.recvInt(); } } public long getObject(final long sel_func, final long sel_pc) { synchronized (IPC.lock) { AnUtility.checkIPCOnWrongThread(false); getWindow().IPC().send("getObject"); getWindow().IPC().send(0); getWindow().IPC().send(sel_func); getWindow().IPC().send(sel_pc); long l = getWindow().IPC().recvLong(); AnUtility.checkIPCOnWrongThread(true); return l; } } private AnWindow getWindow() { return AnWindow.getInstance(); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ConfigurationPanel.form��������������������������������������������0000644�0001750�0001750�00000020011�14517772113�020403� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-31"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JCheckBox" name="useConfCheckBox"> <Properties> <Property name="text" type="java.lang.String" value="NOI18N"/> <Property name="opaque" type="boolean" value="false"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useConfCheckBoxActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="confComboBox"> <Properties> <Property name="editable" type="boolean" value="true"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="21" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="confBrowseButton"> <Properties> <Property name="text" type="java.lang.String" value="..."/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="confBrowseButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JCheckBox" name="alwaysCheckBox"> <Properties> <Property name="opaque" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="18" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JCheckBox" name="workingDirCheckBox"> <Properties> <Property name="text" type="java.lang.String" value="NOI18N"/> <Property name="opaque" type="boolean" value="false"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="workingDirCheckBoxActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="4" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="workingDirLabel"> <Properties> <Property name="text" type="java.lang.String" value="NOI18N"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="21" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="workingDirTextField"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="5" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="wdBrowseButton"> <Properties> <Property name="text" type="java.lang.String" value="..."/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="wdBrowseButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnFileSystemView.java����������������������������������������������0000644�0001750�0001750�00000074077�14517772113�020015� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.IPC.AnIPCException; import org.gprofng.mpmt.ipc.IPCContext; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCLogger; import org.gprofng.mpmt.ipc.IPCResult; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Vector; import javax.swing.UIManager; import javax.swing.filechooser.FileSystemView; /** AnFileSystemView - File System View for remote experiments */ public class AnFileSystemView extends FileSystemView { private AnWindow anWindow = null; private AnChooser anChooser = null; // private int TIMEOUT = 2000; // default timeout 2 seconds // private int SLEEPTIME = 10; // default sleep time 10 milliseconds private String lastRequest = null; private String lastResponse = null; private boolean firstEntry = false; // true; private static final String SLASH = "/"; private static final String DOUBLE_SLASH = "//"; private static final char SLASH_CHAR = '/'; private static final char BACKSLASH_CHAR = '\\'; private static final char COLUMN_CHAR = ':'; private static int ThreadID = 0; private File[] roots = null; static AnFileSystemView remoteFileSystemView = null; static boolean useSystemExtensionsHiding = false; private boolean DONT_USE_LS = true; // false; public static AnFileSystemView getFileSystemView() { useSystemExtensionsHiding = UIManager.getDefaults().getBoolean("FileChooser.useSystemExtensionHiding"); UIManager.addPropertyChangeListener( new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { if (e.getPropertyName().equals("lookAndFeel")) { useSystemExtensionsHiding = UIManager.getDefaults().getBoolean("FileChooser.useSystemExtensionHiding"); } } }); if (remoteFileSystemView == null) { remoteFileSystemView = new RemoteFileSystemView(); } return remoteFileSystemView; } /** * Returns all root partitions on this system. For example, on Windows, this would be the * "Desktop" folder, while on DOS this would be the A: through Z: drives. */ public File[] getRoots() { if (null != roots) { return roots; } roots = new AnFile[1]; AnFile root = new AnFile(SLASH); roots[0] = root; // createFileSystemRoot(root); return roots; } /** * Is dir the root of a tree in the file system, such as a drive or partition. Example: Returns * true for "C:\" on Windows 98. * * @param dir a <code>File</code> object representing a directory * @return <code>true</code> if <code>f</code> is a root of a filesystem * @see #isRoot * @since 1.4 */ public boolean isFileSystemRoot(File dir) { if (dir != null) { String p = dir.getAbsolutePath(); if (SLASH.equals(p)) { return true; } } return false; } private File[] filterHiddenFiles(File[] files, boolean isFileHidingEnabled) { File[] filesOut = files; if (isFileHidingEnabled) { List list = new ArrayList(); for (File file : files) { if (!file.getName().startsWith(".")) { list.add(file); } } filesOut = (File[]) list.toArray(new File[list.size()]); } return filesOut; } /** * Gets the list of shown (i.e. not hidden) files. Use '/bin/ls' or * 'gp-display-text' to get the list of remote files */ @Override public synchronized File[] getFiles(File directory, boolean isFileHidingEnabled) { long start, end; start = System.currentTimeMillis(); // Temporary fix for Windows String path = slashifyPath(directory.getPath()); AnFile dir = new AnFile(path); ThreadID++; // System.err.println("AnFileSystemView.getFiles: Thread ID="+ThreadID); if (firstEntry) { // First time run some useless command String s = getRemoteHostInfo(); end = System.currentTimeMillis(); // System.out.println("getRemoteHostInfo() [Duration: " + (end - start) + " ms.] returned: " + // s); firstEntry = false; } File[] files = new AnFile[0]; try { String cmd = "/bin/ls -a"; String dirname = dir.getAbsolutePath(); // dir.getCanonicalPath(); // Try to get directory contents if (firstEntry) { // First time try to use /bin/ls // firstEntry = false; } else { // Try to get directory contents from gp-display-text try { String filenames = lastResponse; // Debug optimization // Debug optimization if ((null == lastRequest) || (!lastRequest.equals(dirname))) { // filenames = anWindow.getFiles(dirname, cmd); // System.err.println("AnFileSystemView.getFiles: call IPC_getFiles() Thread // ID="+ThreadID+" File:"+dirname); filenames = IPC_getFiles(dirname, cmd); } Vector<AnFile> v = new Vector(); if (null != filenames) { String fn = filenames; while (fn.length() > 0) { int j = fn.indexOf("\n"); if (j <= 0) { break; } String fname = fn.substring(0, j); fn = fn.substring(j + 1); AnFile af = new AnFile(dirname, fname); v.add(af); } if (v.size() > 0) { files = new AnFile[v.size()]; for (int i = 0; i < v.size(); i++) { AnFile af = v.elementAt(i); // updateFileAttributes(dir, af); // too slow files[i] = af; } updateFileAttributes(dir, (AnFile[]) files); lastRequest = dirname; // Debug optimization lastResponse = filenames; // Debug optimization end = System.currentTimeMillis(); return filterHiddenFiles(files, isFileHidingEnabled); } } } catch (AnIPCException e) { // e.printStackTrace(); // System.err.println("AnFileSystemView.getFiles: AnIPCException CR 7199013 Thread // ID="+ThreadID); IPCLogger.logTrace( "\nAnFileSystemView.getFiles: AnIPCException CR 7199013 Thread ID=" + ThreadID); } catch (Exception e) { e.printStackTrace(); // continue using /bin/ls } } if (DONT_USE_LS) { return filterHiddenFiles(files, isFileHidingEnabled); } // Try to get directory contents from /bin/ls AnShellCommand sc = new AnShellCommand(); sc.setRemoteConnection(anWindow.getAnalyzer().remoteConnection); try { sc.run(dirname, cmd); Vector<AnFile> v = new Vector(); String fn; while (sc.isRunning()) { // Parse /bin/ls output try { fn = sc.readOutput(true); if (fn == null) { break; } if (fn.length() <= 0) { continue; } int j = fn.indexOf("\n"); if (j > 0) { fn = fn.substring(0, j); } AnFile af = new AnFile(dirname, fn); v.add(af); } catch (Exception e) { // done? } } fn = sc.readOutput(false); while (fn != null) { // Parse /bin/ls output if (fn.length() <= 0) { fn = sc.readOutput(false); continue; } int j = fn.indexOf("\n"); if (j > 0) { fn = fn.substring(0, j); } AnFile af = new AnFile(dirname, fn); v.add(af); fn = sc.readOutput(false); } if (v.size() < 1) { return filterHiddenFiles(files, isFileHidingEnabled); } files = new AnFile[v.size()]; for (int i = 0; i < v.size(); i++) { AnFile af = v.elementAt(i); // updateFileAttributes(dir, af); // too slow files[i] = af; } updateFileAttributes(dir, (AnFile[]) files); end = System.currentTimeMillis(); // System.out.println("getFiles(" + dirname + ") using /bin/ls: " + (end - start) + " ms."); } catch (Exception e) { return filterHiddenFiles(files, isFileHidingEnabled); } } catch (Exception e) { return filterHiddenFiles(files, isFileHidingEnabled); } /* // add all files in dir if (!(dir instanceof ShellFolder)) { try { dir = getShellFolder(dir); } catch (FileNotFoundException e) { return new File[0]; } } File[] names = ((ShellFolder) dir).listFiles(!useFileHiding); if (names == null) { return new File[0]; } for (File f : names) { if (Thread.currentThread().isInterrupted()) { break; } if (!(f instanceof ShellFolder)) { if (isFileSystemRoot(f)) { f = createFileSystemRoot(f); } try { f = ShellFolder.getShellFolder(f); } catch (FileNotFoundException e) { // Not a valid file (wouldn't show in native file chooser) // Example: C:\pagefile.sys continue; } catch (InternalError e) { // Not a valid file (wouldn't show in native file chooser) // Example C:\Winnt\Profiles\joe\history\History.IE5 continue; } } if (!useFileHiding || !isHiddenFile(f)) { files.add(f); } } */ // firstEntry = false; return filterHiddenFiles(files, isFileHidingEnabled); } /** * Process File Attributes * * @param dir * @param file * @param filename * @param fattr * @return */ private boolean processFileAttributes( String /*AnFile*/ dir, AnFile file, String filename, String fattr) { int j = fattr.indexOf("\n"); if (j > 0) { fattr = fattr.substring(0, j); } if (fattr.endsWith(filename)) { boolean isDir = false; boolean exists = false; if (fattr.startsWith("d")) { isDir = true; exists = true; file.setAttributes(dir, isDir, exists); } if (fattr.startsWith("-")) { isDir = false; exists = true; file.setAttributes(dir, isDir, exists); } file.attributesReady = true; return true; } return false; } /** * Get file attributes and saves it in AnFile * * @param file * @return true if no exceptions happened */ public boolean updateFileAttributes(AnFile file) { return updateFileAttributes(null, file); } /** * Get file attributes and saves it in AnFile * * @param dir * @param file * @return true if no exceptions happened */ public boolean updateFileAttributes(AnFile dir, AnFile file) { if (file.getAttributesReady()) { return true; } String LS_CMD = "/bin/ls -dl "; try { String dirname = null; if (dir != null) { dirname = dir.getCanonicalPath(); } String filename = file.getPath(); // Try to get this info from gp-display-text String fullfilename = filename; if (!fullfilename.startsWith(SLASH)) { if (null != dirname) { if (!dirname.endsWith(SLASH)) { dirname += SLASH; } // Temporary fix for Windows dirname = slashifyPath(dirname); fullfilename = dirname + filename; } else { fullfilename = SLASH + filename; // BUG! } } // String fattr = anWindow.getFileAttributes(fullfilename, LS_CMD); String fattr = IPC_getFileAttributes(fullfilename, LS_CMD); if (null != fattr) { if (fattr.length() > 0) { if (processFileAttributes(dirname, file, fullfilename, fattr)) { return true; } } fattr = null; } if (null == fattr) { file.existsFlag = false; file.isDirectoryFlag = false; file.attributesReady = true; } if (DONT_USE_LS) { // TEMPORARY: don't use /bin/ls return false; } AnShellCommand sc = new AnShellCommand(); sc.setRemoteConnection(anWindow.getAnalyzer().remoteConnection); String cmd = LS_CMD + filename; sc.run(dirname, cmd); while (sc.isRunning()) { try { fattr = sc.readOutput(true); if (fattr == null) { break; } if (fattr.length() > 0) { // Parse /bin/ls output if (processFileAttributes(/*dir*/ dirname, file, filename, fattr)) { return true; } } } catch (Exception e) { // done? break; } } fattr = sc.readOutput(false); while (fattr != null) { if (fattr.length() > 0) { // Parse /bin/ls output if (processFileAttributes(/*dir*/ dirname, file, filename, fattr)) { return true; } } fattr = sc.readOutput(false); } } catch (Exception e) { // e.printStackTrace(); } return false; } /** * Update File Attributes if the name matches * * @param files * @param filename * @param index * @param dir * @return true if updated */ private boolean updateFile(AnFile[] files, String filename, int index, /*AnFile*/ String dir) { boolean isDir = false; boolean exists = true; if (index >= files.length) { return false; } String s = files[index].getName(); // NM was files[index].getPath(); if (filename.endsWith(SLASH)) { isDir = true; filename = filename.substring(0, filename.length() - 1); if (filename.compareTo(s) == 0) { files[index].setAttributes(dir, isDir, exists); return true; } return false; } if (filename.compareTo(s) == 0) { // Regular file files[index].setAttributes(dir, isDir, exists); return true; } else if (filename.endsWith("@")) { // Link String fs = filename.substring(0, filename.length() - 1); if (fs.compareTo(s) == 0) { isDir = true; files[index].setAttributes(dir, isDir, exists); return true; } } else if (filename.endsWith("*")) { String fs = filename.substring(0, filename.length() - 1); if (fs.compareTo(s) == 0) { isDir = false; files[index].setAttributes(dir, isDir, exists); return true; } } return false; } /** * Internal function to process 'ls -aF' output and update file attributes * * @param files * @param filenames * @return */ private boolean processFileAttributes(/*AnFile*/ String dir, AnFile[] files, String filenames) { int index = 0; String fn = filenames; while (filenames.length() > 0) { int j = filenames.indexOf("\n"); if (j > 0) { fn = filenames.substring(0, j); filenames = filenames.substring(j + 1); } else { break; } if (updateFile(files, fn, index, dir)) { if (index < files.length - 1) { index++; } continue; } // Search through all files int i; for (i = 0; i < files.length; i++) { if (updateFile(files, fn, i, dir)) { break; } } if (i < files.length - 1) { index = i + 1; } else { // skip this file i = 0; // for breakpoint } } return true; } /** * Update file attributes for the whole directory * * @param File dir * @param AnFile[] files * @return */ public boolean updateFileAttributes(AnFile dir, AnFile[] files) { if (files.length <= 0) { return false; } String filenames = ""; String dirname = null; try { if (dir == null) { return false; } dirname = dir.getAbsolutePath(); // Temporary fix for Windows dirname = slashifyPath(dirname); String cmd = "/bin/ls -aF"; // Try to get this info from gp-display-text // filenames = anWindow.getFiles(dirname, cmd); filenames = IPC_getFiles(dirname, cmd); if (filenames.length() > 0) { return (processFileAttributes(dirname, files, filenames)); } if (DONT_USE_LS) { return false; // NM don't use /bin/ls } // Try to get this info from /bin/ls AnShellCommand sc = new AnShellCommand(); sc.setRemoteConnection(anWindow.getAnalyzer().remoteConnection); sc.run(dirname, cmd); String fattr = null; while (sc.isRunning()) { // Read output try { fattr = sc.readOutput(true); if (fattr == null) { break; } if (fattr.length() <= 0) { continue; } filenames += fattr; } catch (Exception e) { // done? } } fattr = sc.readOutput(false); while (fattr != null) { // Read output if (fattr.length() <= 0) { fattr = sc.readOutput(false); continue; } filenames += fattr; fattr = sc.readOutput(false); } } catch (Exception e) { } if (filenames.indexOf("\n") > 0) { if (null != dirname) { return (processFileAttributes(dirname, files, filenames)); } else { return false; // for debug } } return false; } /** * Name of a file, directory, or folder as it would be displayed in a system file browser. Example * from Windows: the "M:\" directory displays as "CD-ROM (M:)" * * <p>The default implementation gets information from the ShellFolder class. * * @param f a <code>File</code> object * @return the file name as it would be displayed by a native file chooser * @see JFileChooser#getName * @since 1.4 */ public String getSystemDisplayName(File f) { if (f == null) { return null; } String name = f.getName(); /* NM Temporary if (!name.equals("..") && !name.equals(".") && (useSystemExtensionsHiding || !isFileSystem(f) || isFileSystemRoot(f)) && (f instanceof ShellFolder || f.exists())) { try { name = getShellFolder(f).getDisplayName(); } catch (FileNotFoundException e) { return null; } if (name == null || name.length() == 0) { name = f.getPath(); // e.g. "/" } } NM */ return name; } /** Creates a new folder with a default folder name. */ @Override public File createNewFolder(File containingDir) throws IOException { // anWindow.createDirectory(dirname); throw new UnsupportedOperationException("Not supported yet."); } /** Sets AnWindows. */ public void setAnWindow(AnWindow a) { anWindow = a; } /** Gets AnWindows. */ public AnWindow getAnWindow() { return (anWindow); } public void setAnChooser(AnChooser c) { anChooser = c; } /** * Run "/bin/uname -a" command * * @return output */ String getRemoteHostInfo() { String hostInfo = ""; AnShellCommand sc = new AnShellCommand(); sc.setRemoteConnection(anWindow.getAnalyzer().remoteConnection); String cmd = "/bin/uname -a"; try { sc.run(cmd); String str = null; while (sc.isRunning()) { // Read output try { str = sc.readOutput(true); if (str == null) { break; } if (str.length() <= 0) { continue; } hostInfo += str; } catch (Exception e) { break; } } str = sc.readOutput(false); while (str != null) { // Read output if (str.length() <= 0) { str = sc.readOutput(false); continue; } hostInfo += str; str = sc.readOutput(false); } } catch (Exception e) { } return hostInfo; } /** * Get File Attributes via IPC call * * @param filename * @param format * @return String */ public String IPC_getFileAttributes(final String filename, final String format) { IPCContext fsvContext = IPCContext.newCurrentContext( AnLocale.getString("File Chooser"), IPCContext.Scope.SYSTEM, false, anWindow); fsvContext.setCancellable(true); IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE, fsvContext); ipcHandle.append("getFileAttributes"); ipcHandle.append(filename); ipcHandle.append(format); IPCResult ipcResult = ipcHandle.sendRequest(); if (ipcResult.getCC() != IPCResult.CC.SUCCESS) { anChooser.cancelChooser(); } String result = ipcResult.getString(); // blocking if (result == null) { System.err.println("Error: ipcHandle: " + ipcHandle); } anWindow.getSystemProgressPanel().setProgressCancelContext(null); return result; } /** * Get Files via IPC call * * @param dirname * @param format * @return String */ private synchronized String IPC_getFiles(final String dirname, final String format) { IPCContext fsvContext = IPCContext.newCurrentContext( AnLocale.getString("File Chooser"), IPCContext.Scope.SYSTEM, false, anWindow); fsvContext.setCancellable(true); IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE, fsvContext); ipcHandle.append("getFiles"); ipcHandle.append(dirname); ipcHandle.append(format); IPCResult ipcResult = ipcHandle.sendRequest(); if (ipcResult.getCC() != IPCResult.CC.SUCCESS) { anChooser.cancelChooser(); } String result = ipcResult.getString(); // blocking anWindow.getSystemProgressPanel().setProgressCancelContext(null); // System.out.println("--------------------------- \'" + dirname + "\' \'" + format + // "\'"); // System.out.println("IPC_getFiles: \n" + result); return result; } public static String slashifyPath(String path) { String s = path; if (null == s) { return null; } // Temporary code for Windows if (s.length() >= 3) { if ((s.charAt(1) == COLUMN_CHAR) && (s.charAt(2) == BACKSLASH_CHAR)) { // Special case if (s.length() > 3) { s = SLASH + s.substring(3); } else { s = SLASH; } } } // Replace all \ characters with / characters s = s.replace(BACKSLASH_CHAR, SLASH_CHAR); // Replace double slashes with single slash int n = s.indexOf(DOUBLE_SLASH); while (n >= 0) { s = s.substring(0, n) + s.substring(n + 1); n = s.indexOf(DOUBLE_SLASH); } return s; } } // End of AnFileSystemView /** Remote FileSystemView */ class RemoteFileSystemView extends AnFileSystemView { private static final String SLASH = "/"; private static final char SLASH_CHAR = '/'; private AnFile root = null; private AnFile home = null; /** Returns a File object constructed from the given path string. */ public File createFileObject(String path) { AnFile f = new AnFile(path); // if (isFileSystemRoot(f)) { // f = createFileSystemRoot(f); // } // Update file attributes updateFileAttributes(f); return f; } /** Returns a File object constructed from the given path string. */ public File createFileObject(File parent, String fileName) { String path = parent.getPath(); if (path.endsWith(SLASH)) { path = path + fileName; } else { path = path + SLASH + fileName; } return createFileObject(path); } /** Creates a new folder with a default folder name. */ public File createNewFolder(File containingDir) throws IOException { if (containingDir == null) { throw new IOException("Containing directory is null:"); } String res = null; AnFile newFolder = null; if (containingDir instanceof AnFile) { String defaultFolderName = UIManager.getString("FileChooser.other.newFolder"); newFolder = (AnFile) containingDir; String folderName = newFolder.getAbsolutePath() + SLASH + defaultFolderName; newFolder = new AnFile(folderName); // System.out.println("Create New Folder: " + newFolder.getAbsolutePath()); res = getAnWindow().createDirectories(newFolder.getAbsolutePath()); } if (null == newFolder) { throw new IOException("Create New Folder is not implemented yet."); } if (null != res && res.length() > 0) { throw new IOException("Create New Folder failed: " + res); } return newFolder; } /** * @param parent a <code>File</code> object representing a directory or special folder * @param fileName a name of a file or folder which exists in <code>parent</code> * @return a File object. This is normally constructed with <code>new * File(parent, fileName)</code> except when parent and child are both special folders, in which * case the <code>File</code> is a wrapper containing a <code>ShellFolder</code> object. * @since 1.4 */ public File getChild(File parent, String fileName) { return createFileObject(parent, fileName); } public File getHomeDirectory() { if (null == home) { String HomeDir = AnWindow.getInstance().getHomeDir(); if (HomeDir != null) { home = new AnFile(HomeDir); return home; } } else { return home; } if (null == root) { root = new AnFile(SLASH); } return (root); } /** * Return the user's default starting directory for the file chooser. * * @return a <code>File</code> object representing the default starting folder * @since 1.4 */ public File getDefaultDirectory() { if (null == root) { root = new AnFile(SLASH); } return (root); } /** * Returns the parent directory of <code>dir</code>. * * @param dir the <code>File</code> being queried * @return the parent directory of <code>dir</code>, or <code>null</code> if <code>dir</code> is * <code>null</code> */ public File getParentDirectory(File dir) { if (dir == null || !dir.exists()) { return null; } String psf = dir.getParent(); if (psf == null) { return null; } AnFile pdir = new AnFile(dir.getParent()); return pdir; } /** * On Windows, a file can appear in multiple folders, other than its parent directory in the * filesystem. Folder could for example be the "Desktop" folder which is not the same as * file.getParentFile(). * * @param folder a <code>File</code> object repesenting a directory or special folder * @param file a <code>File</code> object * @return <code>true</code> if <code>folder</code> is a directory or special folder and contains * <code>file</code>. * @since 1.4 */ public boolean isParent(File folder, File file) { if (folder == null || file == null) { return false; } // NM else if (folder instanceof ShellFolder) { File parent = file.getParentFile(); if (parent != null && parent.equals(folder)) { return true; } File[] children = getFiles(folder, false); for (int i = 0; i < children.length; i++) { if (file.equals(children[i])) { return true; } } return false; // NM } else { // NM return folder.equals(file.getParentFile()); // NM } } /** * Used by UI classes to decide whether to display a special icon for a computer node, e.g. "My * Computer" or a network server. * * <p>The default implementation has no way of knowing, so always returns false. * * @param dir a directory * @return <code>false</code> always * @since 1.4 */ public boolean isComputerNode(File dir) { // return ShellFolder.isComputerNode(dir); return false; } /** * Checks if <code>f</code> represents a real directory or file as opposed to a special folder * such as <code>"Desktop"</code>. Used by UI classes to decide if a folder is selectable when * doing directory choosing. * * @param f a <code>File</code> object * @return <code>true</code> if <code>f</code> is a real file or directory. * @since 1.4 */ public boolean isFileSystem(File f) { // NM if (f instanceof ShellFolder) { // NM ShellFolder sf = (ShellFolder)f; // Shortcuts to directories are treated as not being file system objects, // so that they are never returned by JFileChooser. // NM return sf.isFileSystem() && !(sf.isLink() && sf.isDirectory()); // NM } else { // NM return true; // NM } // NM TEMPORARY: return true if (f.isDirectory()) { return true; } return false; } /* Normalize the given pathname, whose length is len, starting at the given offset; everything before this offset is already normal. */ private String normalize(String pathname, int len, int off) { if (len == 0) return pathname; int n = len; while ((n > 0) && (pathname.charAt(n - 1) == SLASH_CHAR)) n--; if (n == 0) return SLASH; StringBuffer sb = new StringBuffer(pathname.length()); if (off > 0) sb.append(pathname.substring(0, off)); char prevChar = 0; for (int i = off; i < n; i++) { char c = pathname.charAt(i); if ((prevChar == SLASH_CHAR) && (c == SLASH_CHAR)) continue; sb.append(c); prevChar = c; } return sb.toString(); } /* Check that the given pathname is normal. If not, invoke the real normalizer on the part of the pathname that requires normalization. This way we iterate through the whole pathname string only once. */ public String normalize(String pathname) { int n = pathname.length(); char prevChar = 0; for (int i = 0; i < n; i++) { char c = pathname.charAt(i); if ((prevChar == SLASH_CHAR) && (c == SLASH_CHAR)) return normalize(pathname, n, i - 1); prevChar = c; } if (prevChar == SLASH_CHAR) return normalize(pathname, n, n - 1); return pathname; } public int prefixLength(String pathname) { if (pathname.length() == 0) return 0; return (pathname.charAt(0) == SLASH_CHAR) ? 1 : 0; } } // End of RemoteFileSystemView �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/experiment_props/��������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�017435� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/experiment_props/ExperimentProperties.java�������������������������0000644�0001750�0001750�00000010554�14517772113�024405� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.experiment_props; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; // This class is intended to be immutable // // Mirrors back-end Experiment DataDescriptor and PropDescr information public class ExperimentProperties { public static class BasicInfo { private final int exp_id; // dbe Experiment handle private final int founder_exp_id; // dbe handle of founder experiment (same as exp_id if standalone) private final int user_exp_id; // filter experiment id private final int exp_group_id; // dbe experiment group id private final String exp_name; private final long offset_time, start_time, end_time; private final long start_wall_secs; // wall time-of-day seconds at start_time private final String hostname; private final int cpu_freq; public BasicInfo( final int exp_id, final int founder_exp_id, final int user_exp_id, final String exp_name, final int group_id, final long offset_time, final long start_time, final long end_time, final long start_wall_secs, final String hostname, final int cpu_freq) { this.exp_id = exp_id; this.founder_exp_id = founder_exp_id; this.user_exp_id = user_exp_id; this.exp_name = exp_name; this.exp_group_id = group_id; this.offset_time = offset_time; this.start_time = start_time; this.end_time = end_time; this.start_wall_secs = start_wall_secs; this.hostname = hostname; this.cpu_freq = cpu_freq; } } private final BasicInfo basic_info; private final List<DataDescriptor> data_desc; private final List<DataDescriptor> time_data_desc; private final Map<String, DataDescriptor> desc_map; public ExperimentProperties(final BasicInfo basic_info, List<DataDescriptor> data_desc) { this.basic_info = basic_info; this.data_desc = data_desc; this.time_data_desc = timeDataDescriptions(data_desc); this.desc_map = new HashMap(); } public final int getID() { return basic_info.exp_id; } public final int getFounderID() { return basic_info.founder_exp_id; } public final int getUserID() { return basic_info.user_exp_id; } public final long getTimeOffset() { return basic_info.offset_time; } public final long getStartTime() { return basic_info.start_time; } public final long getEndTime() { return basic_info.end_time; } public final long getStartWallSeconds() { return basic_info.start_wall_secs; } public final String getHostname() { return basic_info.hostname; } public final int getCpuFreq() { return basic_info.cpu_freq; } public List<DataDescriptor> getDataDescriptors() { return data_desc; } public List<DataDescriptor> getTstampDataDescriptors() { return time_data_desc; } public DataDescriptor findDataDescriptor(final String name) { if (desc_map.isEmpty()) { if (data_desc == null) { return null; } for (DataDescriptor desc : data_desc) { desc_map.put(desc.getName(), desc); } } return desc_map.get(name); } public String getName() { return basic_info.exp_name; } public int getGroupId() { return basic_info.exp_group_id; } private List<DataDescriptor> timeDataDescriptions(List<DataDescriptor> dataDescriptors) { ArrayList<DataDescriptor> tlDataDescriptors = new ArrayList(); if (dataDescriptors == null) { // experiment dropped? return tlDataDescriptors; } for (DataDescriptor ddscr : dataDescriptors) { if (ddscr.findProp("TSTAMP") != null) { tlDataDescriptors.add(ddscr); } } return tlDataDescriptors; } } ����������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/experiment_props/PropDescriptor.java�������������������������������0000644�0001750�0001750�00000003446�14517772113�023171� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.experiment_props; // This class is intended to be immutable. // // PropDescriptor is a container to hold the DBE description of a metric // to be d[isplayed. (e.g. CPU Cycles) public final class PropDescriptor { private final String name; // identifier name private final String uname; // printable name private final int prop_id; // Dbe PROP_* value private final String stateNames[]; private final String stateUNames[]; public PropDescriptor( final String name, final String uname, int prop_id, final String stateNames[], final String stateUNames[]) { // used for HWC data, where aux is needed to specify counter this.name = name; this.uname = uname; this.prop_id = prop_id; this.stateNames = stateNames; this.stateUNames = stateUNames; } public String getName() { return name; } public String getDescription() { return uname; } public int getPropId() { return prop_id; } public String[] getStateNames() { // may return null return stateNames; } public String[] getStateUNames() { // may return null return stateUNames; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/experiment_props/Experiments.java����������������������������������0000644�0001750�0001750�00000032146�14517772113�022514� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.experiment_props; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import java.util.ArrayList; import java.util.Collections; import java.util.List; // ExperimentProperties sync'd with back-end experiments. // NOTE: Synchronization on all public interfaces is required because calls may come from // more than one thread. public final class Experiments { private final AnWindow w_IPC; private final ArrayList<ExperimentProperties> experiments; // Constructor public Experiments(final AnWindow awindow) { this.w_IPC = awindow; experiments = new ArrayList(); } // --- public experiment interface ---- public synchronized ExperimentProperties getExperimentProperties(int expId) { if (expId < 0 || expId >= experiments.size()) { return null; } return experiments.get(expId); } public synchronized List<ExperimentProperties> getAllExperimentProperties() { return Collections.unmodifiableList(experiments); } // Drop all experiments public synchronized void resetAll() { dropAllExps(); } public synchronized void ipcUpdateExps() { // IPC! dropAllExps(); // YXXX might much better to check for changes boolean[] enable = w_IPC.getExpEnable(); // IPC!! if (enable == null) { return; } final int size = enable.length; final int experimentIds[] = new int[size]; for (int i = 0; i < size; i++) { experimentIds[i] = i; } // Use "async" IPC calls to minimize the "high latency" effect IPCResult ipcr_founderExpIds = getFounderExpIdIPCRequest(experimentIds); // ASYNC IPC IPCResult ipcr_userExpIds = getUserExpIdIPCRequest(experimentIds); // ASYNC IPC IPCResult ipcr_names = getExpVerboseNameIPCRequest(experimentIds); // ASYNC IPC IPCResult ipcr_groupIds = getExpGroupIdIPCRequest(experimentIds); // ASYNC IPC IPCResult ipcr_timeObject = getExperimentTimeInfoIPCRequest(experimentIds); // ASYNC IPC IPCResult ipcr_ddscrObject = getExperimentDataDescriptorsIPCRequest(experimentIds); // ASYNC IPC // Get the results fron those "async" IPC calls // Old code used "sync" IPC calls int[] founderExpIds = ipcr_founderExpIds.getInts(); // w_IPC.getFounderExpId(experimentIds); // SYNC IPC int[] userExpIds = ipcr_userExpIds.getInts(); // w_IPC.getUserExpId(experimentIds); // SYNC IPC String[] names = ipcr_names.getStrings(); // w_IPC.getExpVerboseName(experimentIds); // SYNC IPC int[] groupIds = ipcr_groupIds.getInts(); // w_IPC.getExpGroupId(experimentIds); // SYNC IPC Object[] timeObject = ipcr_timeObject.getObjects(); // ipcGetExperimentTimeInfo(experimentIds); // SYNC IPC List<ExperimentProperties.BasicInfo> basicInfoList = processGetExperimentBasicInfo( experimentIds, founderExpIds, userExpIds, names, groupIds, timeObject); final Object[] ddscrObject = ipcr_ddscrObject.getObjects(); // ipcGetExperimentDataDescriptors(experimentIds); // SYNC IPC List<List<DataDescriptor>> dataDescriptorsList = processGetExperimentDataDescriptors(ddscrObject); if (basicInfoList == null || dataDescriptorsList == null) { return; // weird } for (int i = 0; i < size; i++) { ExperimentProperties.BasicInfo metaData = basicInfoList.get(i); List<DataDescriptor> dataDescriptors = dataDescriptorsList.get(i); ExperimentProperties expProps = new ExperimentProperties(metaData, dataDescriptors); experiments.add(expProps); } } // --- internal stuff private void dropAllExps() { experiments.clear(); } // ---IPC--- (Native methods from liber_dbe.so) private List<ExperimentProperties.BasicInfo> processGetExperimentBasicInfo( final int[] expIds, final int[] founderExpIds, final int[] userExpIds, final String[] names, final int[] groupIds, final Object[] timeObject) { if (timeObject == null || expIds == null || founderExpIds == null || userExpIds == null || groupIds == null) { return null; } final List<ExperimentProperties.BasicInfo> basicInfoList = new ArrayList(); final long[] offset_time = (long[]) timeObject[0]; // ipcGetRelativeStartTime(exp_id); final long[] start_time = (long[]) timeObject[1]; // ipcGetStartTime(exp_id); final long[] end_time = (long[]) timeObject[2]; // ipcGetEndTime (exp_id); final long[] start_wall_sec = (long[]) timeObject[3]; // ipcGetWallStartSec(exp_id); final String[] hostname = (String[]) timeObject[4]; // final int[] cpu_freq = (int[]) timeObject[5]; // ipcGetClock (exp_id); final int size = expIds.length; if (size != founderExpIds.length || size != userExpIds.length || size != names.length || size != groupIds.length || size != start_time.length || size != offset_time.length || size != end_time.length || size != start_wall_sec.length || size != hostname.length || size != cpu_freq.length) { return null; // weird } for (int i = 0; i < size; i++) { // loop for each experiment ExperimentProperties.BasicInfo metaData = new ExperimentProperties.BasicInfo( expIds[i], founderExpIds[i], userExpIds[i], names[i], groupIds[i], offset_time[i], start_time[i], end_time[i], start_wall_sec[i], hostname[i], cpu_freq[i]); basicInfoList.add(metaData); } return basicInfoList; } private List<List<DataDescriptor>> processGetExperimentDataDescriptors(final Object[] list) { if (list == null) { return null; } final List<List<DataDescriptor>> dataDescriptorList = new ArrayList(); final Object[] dataDescrsInfo = (Object[]) (list[0]); final Object[] dataDescrsProps = (Object[]) (list[1]); // array of dbeGetDataPropertiesV2() final int size = dataDescrsInfo.length; for (int i = 0; i < size; i++) { // loop for each experiment final List<DataDescriptor> exp_descrs = processGetExperimentDataDescriptors_experiment( (Object[]) dataDescrsInfo[i], (Object[]) dataDescrsProps[i]); dataDescriptorList.add(exp_descrs); } return dataDescriptorList; } private List<DataDescriptor> processGetExperimentDataDescriptors_experiment( final Object[] dataDescrsInfo, // ipcGetDataDescriptorsV2(exp_id); final Object[] dataDescrsProps) { final ArrayList<DataDescriptor> dataDescriptors = new ArrayList(); if (dataDescrsProps == null || dataDescrsInfo == null) { return dataDescriptors; } final Object[] list = dataDescrsInfo; if (list.length == 0) { return dataDescriptors; } final int[] data_id = (int[]) list[0]; final String[] name = (String[]) list[1]; final String[] uname = (String[]) list[2]; final int[] aux_prop_id = (int[]) list[3]; int size = data_id.length; if (size != dataDescrsProps.length) { return dataDescriptors; // weird } for (int i = 0; i < size; i++) { final ArrayList<PropDescriptor> props = processDataPropertiesV2((Object[]) dataDescrsProps[i]); DataDescriptor ddscr = new DataDescriptor(name[i], uname[i], data_id[i], props, aux_prop_id[i]); dataDescriptors.add(ddscr); } return dataDescriptors; } private ArrayList<PropDescriptor> processDataPropertiesV2(final Object[] list) { final ArrayList<PropDescriptor> propDescriptors = new ArrayList(); if (list == null || list.length == 0) { return propDescriptors; } final int[] propId = (int[]) list[0]; final String[] propUName = (String[]) list[1]; final int[] propTypeId = (int[]) list[2]; final String[] propTypeName = (String[]) list[3]; // YXXX add this final int[] propFlags = (int[]) list[4]; final String[] propName = (String[]) list[5]; final Object[] propStates = (Object[]) list[6]; final Object[] propUStates = (Object[]) list[7]; int size = propId.length; for (int i = 0; i < size; i++) { String[] states = (String[]) propStates[i]; String[] ustates = (String[]) propUStates[i]; String name = propName[i]; String uname = propUName[i]; int id = propId[i]; PropDescriptor propDscr = new PropDescriptor(name, uname, id, states, ustates); propDescriptors.add(propDscr); } return propDescriptors; } // private Object[] ipcGetExperimentTimeInfo(final int experimentIds[]){ // synchronized( IPC.lock ) { // w_IPC.IPC().send("getExperimentTimeInfo"); // // w_IPC.IPC().send(w_IPC.getWindowID()); // w_IPC.IPC().send(experimentIds); // return (Object[])w_IPC.IPC().recvObject(); // } // } // // private Object[] ipcGetExperimentDataDescriptors(final int experimentIds[]){ // synchronized( IPC.lock ) { // w_IPC.IPC().send("getExperimentDataDescriptors"); // // w_IPC.IPC().send(w_IPC.getWindowID()); // w_IPC.IPC().send(experimentIds); // return (Object[])w_IPC.IPC().recvObject(); // } // } /** * Send request to get corresponding Exp Verbose Names. Non-blocking IPC call. Caller should call * ipcResult.getObject() to get the result @Parameters: expIds - experimentsDisp indexes * * @return IPCResult */ public IPCResult getExpVerboseNameIPCRequest(final int[] expIds) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getExpVerboseName"); ipcHandle.append(expIds); IPCResult ipcResult = ipcHandle.sendRequest(); // String[] result = ipcResult.getObject() // blocking return ipcResult; } /** * Send request to get corresponding Exp Group IDs. Non-blocking IPC call. Caller should call * ipcResult.getObject() to get the result @Parameters: expIds - experimentsDisp indexes * * @return IPCResult */ public IPCResult getExpGroupIdIPCRequest(final int[] expIds) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getExpGroupId"); ipcHandle.append(expIds); IPCResult ipcResult = ipcHandle.sendRequest(); // int[] result = ipcResult.getObject() // blocking return ipcResult; } /** * Send request to get corresponding founderExpIds. Non-blocking IPC call. Caller should call * ipcResult.getObject() to get the result @Parameters: expIds - experimentsDisp indexes * * @return IPCResult */ public IPCResult getFounderExpIdIPCRequest(final int[] expIds) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getFounderExpId"); ipcHandle.append(expIds); IPCResult ipcResult = ipcHandle.sendRequest(); // int[] result = ipcResult.getObject() // blocking return ipcResult; } /** * Send request to get corresponding userExpIds. Non-blocking IPC call. Caller should call * ipcResult.getObject() to get the result @Parameters: expIds - experimentsDisp indexes * * @return IPCResult */ public IPCResult getUserExpIdIPCRequest(final int[] expIds) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getUserExpId"); ipcHandle.append(expIds); IPCResult ipcResult = ipcHandle.sendRequest(); // int[] result = ipcResult.getObject() // blocking return ipcResult; } /** * Send request to get corresponding Experiment Time Info. Non-blocking IPC call. Caller should * call ipcResult.getObject() to get the result @Parameters: expIds - experimentsDisp indexes * * @return IPCResult */ public IPCResult getExperimentTimeInfoIPCRequest(final int[] expIds) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getExperimentTimeInfo"); ipcHandle.append(expIds); IPCResult ipcResult = ipcHandle.sendRequest(); // int[] result = ipcResult.getObject() // blocking return ipcResult; } /** * Send request to get corresponding Experiment Data Descriptors. Non-blocking IPC call. Caller * should call ipcResult.getObject() to get the result @Parameters: expIds - experimentsDisp * indexes * * @return IPCResult */ public IPCResult getExperimentDataDescriptorsIPCRequest(final int[] expIds) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getExperimentDataDescriptors"); ipcHandle.append(expIds); IPCResult ipcResult = ipcHandle.sendRequest(); // int[] result = ipcResult.getObject() // blocking return ipcResult; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/experiment_props/DataDescriptor.java�������������������������������0000644�0001750�0001750�00000007716�14517772113�023126� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.experiment_props; import org.gprofng.mpmt.settings.Settings; import java.util.ArrayList; // This class is intended to be immutable. // // DataDescriptor is a container to hold the DBE description of a metric // to be displayed. (e.g. CPU Cycles) public final class DataDescriptor { private final String name; private final String uname; private final Settings.TLData_type tldata_type; // enum/bitmask TBR? private final int data_id; // Dbe DATA_* value private final ArrayList<PropDescriptor> props; private final int aux_prop_id; // e.g. PROP_HWCTAG private final int aux_count; // number of values for aux_prop_id private final boolean has_callstacks; public DataDescriptor( final String name, final String uname, final int data_id, final ArrayList<PropDescriptor> props, final int aux_prop_id) { this.name = name; this.uname = uname; this.tldata_type = Settings.TLData_type.find(name); this.data_id = data_id; this.props = props; this.aux_prop_id = aux_prop_id; PropDescriptor prop = findProp(aux_prop_id); if (prop != null && prop.getStateNames() != null) { aux_count = prop.getStateNames().length; } else { aux_count = 0; } if (findProp("FRINFO") != null) { has_callstacks = true; } else { has_callstacks = false; } } public String getName() { return name; } public String getAuxName(int aux) { // gp-display-text metrics command for HWCs if (aux_count == 0) { return null; } PropDescriptor prop = findProp(aux_prop_id); if (aux < 0 || aux >= aux_count || prop == null) { return null; // unexpected } String auxName = prop.getStateNames()[aux]; return auxName; } public String getAuxUName(int aux) { // gp-display-text metrics command for HWCs' description if (aux_count == 0) { return null; } PropDescriptor prop = findProp(aux_prop_id); if (aux < 0 || aux >= aux_count || prop == null) { return null; // unexpected } String auxName = prop.getStateUNames()[aux]; return auxName; } public String getErRcTLDataCmdName(int aux) { // tldata .gprofng.rc command String cmd = Settings.getErRcTLDataCmdName(tldata_type, getAuxName(aux)); return cmd; } public String getLongUName(int aux) { // long user-visible name String longUName = Settings.getErRcTLDataLongUName(uname, getAuxUName(aux)); return longUName; } public Settings.TLData_type getTLDataType() { // TBR? return tldata_type; } public int getDataId() { return data_id; } public final ArrayList<PropDescriptor> getProps() { return props; } public final PropDescriptor findProp(int prop_id) { if (props == null) { return null; } for (PropDescriptor prop : props) { if (prop_id == prop.getPropId()) { return prop; } } return null; } public final PropDescriptor findProp(String propName) { if (props == null) { return null; } for (PropDescriptor prop : props) { if (propName.equals(prop.getName())) { return prop; } } return null; } public int getAuxPropId() { return aux_prop_id; } public int getAuxCount() { return aux_count; } public boolean hasCallstacks() { return has_callstacks; } } ��������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/LibraryVisibilityDialog.java���������������������������������������0000644�0001750�0001750�00000004074�14517772113�021401� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.picklist.StringPickList; import org.gprofng.mpmt.util.gui.AnDialog2; import java.awt.Frame; import java.util.List; public class LibraryVisibilityDialog extends AnDialog2 { private final LibraryVisibilityPanel libraryVisibilityPanel; public LibraryVisibilityDialog(Frame owner) { super(owner, owner, AnLocale.getString("Library and Class Visibility")); libraryVisibilityPanel = new LibraryVisibilityPanel(this); setHelpTag(AnVariable.HELP_ShowHideFunctions); setCustomPanel(libraryVisibilityPanel); getHelpButton().setVisible(true); } @Override public void setVisible(boolean b) { if (b) { libraryVisibilityPanel.reset(); } super.setVisible(b); } @Override protected void setStatus(Status status) { super.setStatus(status); if (status == Status.OK) { libraryVisibilityPanel.save(); } } public void initStates( boolean java, List<String> initStates, StringPickList hideFuncsIncludePickList, String currentIncludeFilter, StringPickList hideFuncsExcludePickList, String currentExcludeFilter) { libraryVisibilityPanel.initStates( java, hideFuncsIncludePickList, currentIncludeFilter, hideFuncsExcludePickList, currentExcludeFilter); } // For persistance public boolean isJava() { return libraryVisibilityPanel.isJava(); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/�����������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�015461� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareSimplePanel.form������������������������������������0000644�0001750�0001750�00000004027�14517772113�021773� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> </AuxValues> <Layout> <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="400" max="32767" attributes="0"/> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="300" max="32767" attributes="0"/> </Group> </DimensionLayout> </Layout> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareGroupsPanel.form������������������������������������0000644�0001750�0001750�00000004027�14517772113�022021� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> </AuxValues> <Layout> <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="400" max="32767" attributes="0"/> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="300" max="32767" attributes="0"/> </Group> </DimensionLayout> </Layout> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareNavigationPanel.java��������������������������������0000644�0001750�0001750�00000003344�14517772113�022620� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.compare; import org.gprofng.analyzer.AnEnvironment; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.BorderFactory; import javax.swing.JPanel; public class CompareNavigationPanel extends JPanel { private CompareStatusPanel compareStatusPanel; public CompareNavigationPanel() { setBorder( BorderFactory.createMatteBorder(1, 0, 0, 1, AnEnvironment.NAVIGATION_PANEL_BORDER_COLOR)); setBackground(AnEnvironment.NAVIGATION_PANEL_SECTION_BACKGROUND_COLOR); compareStatusPanel = new CompareStatusPanel(); setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new Insets(2, 4, 6, 4); add(compareStatusPanel, gridBagConstraints); compareStatusPanel.repaint(); } public int getDiffFromInitialHeight() { return compareStatusPanel.getDiffFromInitialHeight(); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/ExperimentGroupsPanel.java���������������������������������0000644�0001750�0001750�00000027501�14517772113�022533� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.compare; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; /** * @author vmezents */ public class ExperimentGroupsPanel extends javax.swing.JPanel implements ActionListener { private AnWindow window; private Frame frame; private String title; public List<String> listAbsPathes; private static int IdCount = 0; private final int id; /** Creates new form ExpGrpJPanel */ public ExperimentGroupsPanel( final AnWindow window, final Frame frame, final String title, String toolTip, char mnemonic) { this.window = window; this.frame = frame; this.title = title; id = ++IdCount; init(); label.setText(title); label.setToolTipText(toolTip); if (mnemonic != ' ') { label.setDisplayedMnemonic(mnemonic); label.setLabelFor(listExpNames); } listExpNames.setToolTipText(toolTip); } private void init() { initComponents(); btnRemove.setText(AnLocale.getString("Remove")); btnRemove.setToolTipText(AnLocale.getString("Remove experiment from the group")); btnRemove.addActionListener(this); btnAddExp.setText(AnLocale.getString("Add...")); btnAddExp.setToolTipText(AnLocale.getString("Add experiment to the group")); btnAddExp.addActionListener(this); listExpNames.setDragEnabled(true); listExpNames.setTransferHandler(new ListTransferHandler()); listExpNames.addListSelectionListener( new ListSelectionListener() { // This method is called each time the user changes the set of selected items // @Override public void valueChanged(ListSelectionEvent evt) { // When the user release the mouse button and completes the selection, // getValueIsAdjusting() becomes false if (!evt.getValueIsAdjusting()) { update_btnRemove(); } } }); update_exps_list(null); setVisible(true); jScrollPane1.setMinimumSize(new Dimension(10, 10)); listExpNames.setMinimumSize(new Dimension(10, 10)); // setBorder(javax.swing.BorderFactory.createTitledBorder(title)); } public void update_exps_list(final List<String> lst) { final List<String> listAbsNames = new ArrayList(); final List<String> listBaseNames = new ArrayList(); L_LOOP: for (int i = 0, sz = (lst == null) ? 0 : lst.size(); i < sz; i++) { String fname = lst.get(i); for (int j = 0; j < i; j++) { if (fname.compareTo(lst.get(j)) == 0) { continue L_LOOP; } } String bname = AnUtility.basename(fname); listBaseNames.add(bname); listAbsNames.add(fname); } listAbsPathes = listAbsNames; listExpNames.setListData(listBaseNames.toArray()); update_btnRemove(); } private void update_btnRemove() { btnRemove.setEnabled(listExpNames.getSelectedIndices().length != 0); } /** * Action performed * * @param event */ // @Override public void actionPerformed(final ActionEvent event) { String cmd = event.getActionCommand(); if (cmd.equals("btnAddExp")) { AnChooser ac = window.getAnChooser(AnLocale.getString("Select Experiment"), AnChooser.EXP_CHOOSER, null); if (ac.showDialog(this, null) == AnChooser.APPROVE_OPTION) { File files[] = ac.getSelectedAnFiles(); if (files != null) { List<String> lst = new ArrayList(); if (listAbsPathes != null) { lst.addAll(listAbsPathes); } for (File f : files) { String path = f.getAbsolutePath(); add_exp_or_grp(lst, path); } update_exps_list(lst); } } } else if (cmd.equals("btnRemove")) { int[] sel = listExpNames.getSelectedIndices(); if (sel.length > 0) { List<String> lst = new ArrayList(); if (listAbsPathes != null) { lst.addAll(listAbsPathes); } for (int i = sel.length - 1; i >= 0; i--) { int ind = sel[i]; if (ind < lst.size()) { lst.remove(ind); } } update_exps_list(lst); } } } public void add_exp_or_grp(List<String> lst, String path) { if ((path == null) || (path.length() == 0)) { return; } List<String> vec = AnUtility.getGroupList(path); for (String s : vec) { if (s.length() != 0) { lst.add(s); } } } // Support Drag and Drop, Copy/Paste private class ListTransferHandler extends AnTransferHandler { private int[] indices = null; // Bundle up the selected items in the list // as a single string, for export. @Override protected String exportString(JComponent c) { indices = listExpNames.getSelectedIndices(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < indices.length; i++) { if (indices[i] < listAbsPathes.size()) { if (sb.length() != 0) { sb.append("\n"); } sb.append(listAbsPathes.get(indices[i])); } } String str = sb.toString(); debug("ListTransferHandler::exportString: " + str); return str; } // Take the incoming string and wherever there is a // newline, break it into a separate item in the list. @Override protected void importString(JComponent c, String str) { debug("ListTransferHandler::importString: " + str); List<String> lst = new ArrayList(); if (listAbsPathes != null) { lst.addAll(listAbsPathes); } if (indices != null) { // Drag & Drop in the same list for (int i = 0; i < indices.length; i++) { lst.remove(indices[indices.length - 1 - i]); lst.add(listAbsPathes.get(indices[i])); } indices = null; } else { for (String s = str; true; ) { int ind = s.indexOf("\n"); if (ind == -1) { add_exp_or_grp(lst, s); break; } add_exp_or_grp(lst, s.substring(0, ind)); s = s.substring(ind + 1); } } update_exps_list(lst); } // If the remove argument is true, the drop has been // successful and it's time to remove the selected items // from the list. If the remove argument is false, it // was a Copy operation and the original list is left // intact. @Override protected void cleanup(JComponent c, boolean remove) { debug("ListTransferHandler::cleanup: " + id + " " + remove); if (remove && (indices != null)) { List<String> lst = new ArrayList(); if (listAbsPathes != null) { lst.addAll(listAbsPathes); } for (int i = indices.length - 1; i >= 0; i--) { debug( "ListTransferHandler::cleanup: " + id + " " + indices[i] + " " + lst.get(indices[i])); lst.remove(indices[i]); } update_exps_list(lst); } indices = null; } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; innerPanel = new javax.swing.JPanel(); label = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); listExpNames = new javax.swing.JList(); btnAddExp = new javax.swing.JButton(); btnRemove = new javax.swing.JButton(); setPreferredSize(new java.awt.Dimension(800, 150)); setLayout(new java.awt.GridBagLayout()); innerPanel.setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); innerPanel.add(label, gridBagConstraints); listExpNames.setVisibleRowCount(3); jScrollPane1.setViewportView(listExpNames); listExpNames.getAccessibleContext().setAccessibleName("Experiments list"); listExpNames.getAccessibleContext().setAccessibleDescription("Experiments list"); listExpNames.getAccessibleContext().setAccessibleParent(listExpNames); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridheight = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.ipadx = 384; gridBagConstraints.ipady = 71; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 4, 8, 0); innerPanel.add(jScrollPane1, gridBagConstraints); btnAddExp.setText("Add..."); btnAddExp.setActionCommand("btnAddExp"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new java.awt.Insets(4, 8, 0, 4); innerPanel.add(btnAddExp, gridBagConstraints); btnRemove.setText("Remove"); btnRemove.setActionCommand("btnRemove"); btnRemove.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { btnRemoveActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new java.awt.Insets(8, 8, 0, 4); innerPanel.add(btnRemove, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(innerPanel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void btnRemoveActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_btnRemoveActionPerformed // TODO add your handling code here: } // GEN-LAST:event_btnRemoveActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables public javax.swing.JButton btnAddExp; public javax.swing.JButton btnRemove; private javax.swing.JPanel innerPanel; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel label; public javax.swing.JList listExpNames; // End of variables declaration//GEN-END:variables } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareSimplePanel.java������������������������������������0000644�0001750�0001750�00000034607�14517772113�021760� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.compare; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnChooser; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.ExperimentPickListElement; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnGradientPanel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; import java.util.List; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.event.MouseInputAdapter; /** * @author tpreisle */ public class CompareSimplePanel extends javax.swing.JPanel { protected static final int MAX_GROUPS = 20; private CompareSimpleDialog compareSimpleDialog; private int gridy; private JPanel buttonPanel; private JButton addExperimentChooserButton; private JButton reverseButton; private int noExperimentChoosers; private ExperimentComboBox[] experimentChooserComboBoxes; private String[] experimentChooserLabelTexts; private char[] experimentChooserLabelMN; public CompareSimplePanel(CompareSimpleDialog compareSimpleDialog) { this.compareSimpleDialog = compareSimpleDialog; initComponents(); setLayout(new GridBagLayout()); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); experimentChooserComboBoxes = new ExperimentComboBox[MAX_GROUPS]; experimentChooserLabelTexts = new String[MAX_GROUPS]; experimentChooserLabelMN = new char[MAX_GROUPS]; for (int i = 0; i < MAX_GROUPS; i++) { experimentChooserComboBoxes[i] = new ExperimentComboBox(); if (i == 0) { experimentChooserLabelTexts[i] = AnLocale.getString("Baseline Experiment:"); experimentChooserLabelMN[i] = AnLocale.getString('B', "CompareSimpleDialog_BaselineExperiment"); } else { experimentChooserLabelTexts[i] = AnLocale.getString("Comparison Experiment") + " " + i + ":"; if (i < 10) { experimentChooserLabelMN[i] = ("" + i).charAt(0); } } } gridy = 0; addGuidanceText(); addButtonPanel(); noExperimentChoosers = 0; String[][] groups = AnWindow.getInstance().getExperimentGroups(); addExperimentChooser(); addExperimentChooser(); for (int i = 2; i < groups.length; i++) { addExperimentChooser(); } if (groups.length >= 1) { experimentChooserComboBoxes[0].setSelectedItem(groups[0][0]); } if (groups.length >= 2) { experimentChooserComboBoxes[1].setSelectedItem(groups[1][0]); } for (int i = 2; i < groups.length; i++) { experimentChooserComboBoxes[i].setSelectedItem(groups[i][0]); } addFiller(); } private void addButtonPanel() { GridBagConstraints gridBagConstraints; buttonPanel = new AnGradientPanel( AnEnvironment.FILTER_TOOLBAR_BACKGROUND1_COLOR, AnEnvironment.FILTER_TOOLBAR_BACKGROUND2_COLOR); buttonPanel.setLayout(new GridBagLayout()); addExperimentChooserButton = new JButton(); addExperimentChooserButton.setText(AnLocale.getString("More")); addExperimentChooserButton.setIcon(AnUtility.moreIcon); addExperimentChooserButton.setBorderPainted(false); addExperimentChooserButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); addExperimentChooserButton.setOpaque(false); addExperimentChooserButton.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); addExperimentChooserButton.setToolTipText(AnLocale.getString("Add a Comparison Experiment")); addExperimentChooserButton.setMnemonic(AnLocale.getString('M', "CompareSimpleDialog_More")); addExperimentChooserButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { addExperimentChooser(); compareSimpleDialog.pack(); } }); addExperimentChooserButton.addMouseListener( new MouseInputAdapter() { @Override public void mouseEntered(MouseEvent evt) { JButton btn = (JButton) evt.getSource(); if (btn.isEnabled()) { btn.setBorderPainted(true); } } @Override public void mouseExited(MouseEvent evt) { JButton btn = (JButton) evt.getSource(); if (btn.isEnabled()) { btn.setBorderPainted(false); } } }); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(2, 2, 2, 0); buttonPanel.add(addExperimentChooserButton, gridBagConstraints); reverseButton = new JButton(); reverseButton.setText(AnLocale.getString("Reverse")); reverseButton.setIcon(AnUtility.compareReverseIcon); reverseButton.setBorderPainted(false); reverseButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); reverseButton.setOpaque(false); reverseButton.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); reverseButton.setToolTipText(AnLocale.getString("Reverse comparison order")); reverseButton.setMnemonic(AnLocale.getString('R', "CompareSimpleDialog_ReverseButton")); reverseButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String[] selected = new String[MAX_GROUPS]; for (int i = 0; i < MAX_GROUPS; i++) { selected[i] = (String) experimentChooserComboBoxes[i].getSelectedItem(); } for (int i = 0; i < noExperimentChoosers; i++) { experimentChooserComboBoxes[i].setSelectedItem( selected[noExperimentChoosers - i - 1]); } } }); reverseButton.addMouseListener( new MouseInputAdapter() { @Override public void mouseEntered(MouseEvent evt) { JButton btn = (JButton) evt.getSource(); if (btn.isEnabled()) { btn.setBorderPainted(true); } } @Override public void mouseExited(MouseEvent evt) { JButton btn = (JButton) evt.getSource(); if (btn.isEnabled()) { btn.setBorderPainted(false); } } }); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.NORTHEAST; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(2, 0, 2, 2); buttonPanel.add(reverseButton, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridy++; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.insets = new Insets(5, 0, 0, 0); add(buttonPanel, gridBagConstraints); } private void addExperimentChooser() { JLabel label = new JLabel(); AnUtility.setTextAndAccessibleContext(label, experimentChooserLabelTexts[noExperimentChoosers]); addExperimentChooserGUI(label, experimentChooserComboBoxes[noExperimentChoosers]); label.setLabelFor(experimentChooserComboBoxes[noExperimentChoosers]); label.setDisplayedMnemonic(experimentChooserLabelMN[noExperimentChoosers]); noExperimentChoosers++; updateState(); } private void updateState() { addExperimentChooserButton.setEnabled(noExperimentChoosers < MAX_GROUPS); } private void addFiller() { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 20; gridBagConstraints.gridy = 20; gridBagConstraints.weighty = 1.0; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(0, 0, 16, 0); add(new JLabel(), gridBagConstraints); } private void addGuidanceText() { JTextArea textArea = new JTextArea(); AnUtility.setAccessibleContext( textArea.getAccessibleContext(), AnLocale.getString("Infomation area")); textArea.setEditable(false); textArea.setBorder(null); textArea.setWrapStyleWord(true); textArea.setLineWrap(true); textArea.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); textArea.setText( AnLocale.getString( "Comparing experiments. The Comparison experiment(s) are compared against the Baseline" + " experiment. Most data views support comparing experiments. When you compare" + " experiments, gprofng GUI displays data from the experiments or groups" + " in adjacent columns. The Advanced option allows grouping (aggregating) of" + " experiments before comparing them.")); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = gridy++; gridBagConstraints.weightx = 1.0; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(6, 0, 6, 0); add(textArea, gridBagConstraints); } private void addExperimentChooserGUI(JLabel label, final ExperimentComboBox combobox) { GridBagConstraints gridBagConstraints; combobox.setPreferredSize(new Dimension(600, combobox.getPreferredSize().height)); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = gridy++; gridBagConstraints.gridx = 0; gridBagConstraints.insets = new Insets(10, 0, 0, 0); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; add(label, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = gridy; gridBagConstraints.gridx = 0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; add(combobox, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = gridy++; gridBagConstraints.gridx = 1; gridBagConstraints.insets = new Insets(0, 4, 0, 0); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; JButton selectExperimentButton = new JButton("..."); selectExperimentButton.setToolTipText(AnLocale.getString("Browse for experiment...")); selectExperimentButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnChooser ac = AnWindow.getInstance() .getAnChooser( AnLocale.getString("Select Experiment"), AnChooser.EXP_CHOOSER, null); // ac.setMultiSelectionEnabled(false); // Doesn't work ????? if (ac.showDialog(AnWindow.getInstance().getFrame(), null) == AnChooser.APPROVE_OPTION) { File file = ac.getSelectedAnFile(); String path = file.getAbsolutePath(); combobox.setSelectedItem(path); } } }); add(selectExperimentButton, gridBagConstraints); } public String[][] getExperimentGroups() { List<String> experiments = new ArrayList<String>(); for (int i = 0; i < noExperimentChoosers; i++) { String experimentPath = (String) experimentChooserComboBoxes[i].getSelectedItem(); if (experimentPath != null && experimentPath.length() > 0) { experiments.add(experimentPath.trim()); } } String[][] groups = new String[experiments.size()][]; for (int i = 0; i < experiments.size(); i++) { groups[i] = new String[1]; groups[i][0] = experiments.get(i); } return groups; } private class ExperimentComboBox extends JComboBox { public ExperimentComboBox() { setEditable(true); addItem(""); List<ExperimentPickListElement> paths = UserPref.getInstance().getExperimentsPicklists().getPicklist().getRecentExperiments(20); for (ExperimentPickListElement eple : paths) { addItem(eple.getPath()); } setSelectedItem(""); } @Override public void setSelectedItem(Object anObject) { super.setSelectedItem( anObject); // To change body of generated methods, choose Tools | Templates. setToolTipText(anObject.toString()); } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 400, Short.MAX_VALUE)); layout.setVerticalGroup( layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 300, Short.MAX_VALUE)); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } �������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareSimpleDialog.java�����������������������������������0000644�0001750�0001750�00000004310�14517772113�022104� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.compare; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.AnDialog2; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; public class CompareSimpleDialog extends AnDialog2 { private CompareSimplePanel compareSimplePanel; public CompareSimpleDialog(Frame owner) { super(owner, owner, AnLocale.getString("Compare Experiments")); setHelpTag(AnVariable.HELP_Compare); compareSimplePanel = new CompareSimplePanel(this); setCustomPanel(compareSimplePanel); JButton advancedButton = new JButton(AnLocale.getString("Advanced")); advancedButton.setMnemonic(AnLocale.getString('D', "CompareSimpleDialog_Advanced")); advancedButton.setToolTipText(AnLocale.getString("Advanced options (aggregating experiments)")); advancedButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); AnWindow.getInstance().compareExperimentsAdvancedDialog(); } }); addAuxButton(advancedButton); pack(); } @Override protected void setStatus(Status status) { super.setStatus(status); if (status == Status.OK) { String[][] groups = compareSimplePanel.getExperimentGroups(); AnWindow anWindow = AnWindow.getInstance(); anWindow.loadExperimentGroups(groups, null, !anWindow.experimentsLoaded(), null, false); } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareStatusPanel.form������������������������������������0000644�0001750�0001750�00000003740�14517772113�022026� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,2,76"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Form> ��������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareAdvancedDialog.java���������������������������������0000644�0001750�0001750�00000034161�14517772113�022367� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.compare; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Container; import java.awt.Dimension; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.KeyStroke; import javax.swing.border.EmptyBorder; public final class CompareAdvancedDialog extends JDialog implements ItemListener, ActionListener { private AnWindow window; private final Frame frame; private final boolean compare_mode; private String[][] experimentGrops = null; private List<ExperimentGroupsPanel> expGrops; private JPanel workPanel; private JScrollPane scrollPane; private int maxGroups; private JPanel warningPanel = null; // Constructor public CompareAdvancedDialog( final AnWindow window, final Frame frame, final boolean compare_mode, String title) { super(frame, title, true); this.window = window; this.frame = frame; this.compare_mode = compare_mode; maxGroups = compare_mode ? CompareSimplePanel.MAX_GROUPS : 1; experimentGrops = window.getExperimentGroups(); initComponents(); pack(); setLocationRelativeTo(frame); // close/dispose when ESC getRootPane() .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "esc"); getRootPane() .getActionMap() .put( "esc", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); getRootPane() .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "F1"); getRootPane() .getActionMap() .put( "F1", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { showHelp(); } }); } private javax.swing.JButton btnOk; private javax.swing.JButton btnCancel; private javax.swing.JButton btnAddGrp; private javax.swing.JButton btnHelp; // Initialize GUI components private void initComponents() { expGrops = new ArrayList(); String groupTitle; String groupToolTip; char mnemonic; if (compare_mode) { groupTitle = AnLocale.getString("Baseline:"); groupToolTip = AnLocale.getString("Experiment(s) to be compared aginst"); mnemonic = AnLocale.getString('B', "CompareDialogBaselineMN"); } else { groupTitle = AnLocale.getString("Experiments:"); groupToolTip = AnLocale.getString("List of experiments to aggregate"); mnemonic = AnLocale.getString('E', "CompareDialogExperimentMN"); } expGrops.add(new ExperimentGroupsPanel(window, frame, groupTitle, groupToolTip, mnemonic)); if (compare_mode) { mnemonic = AnLocale.getString('C', "CompareDialogComparisonGroupMN"); expGrops.add( new ExperimentGroupsPanel( window, frame, AnLocale.getString("Comparison Group:"), AnLocale.getString("Exeriment(s) to compare against baseline experiments(s)"), mnemonic)); } else if (experimentGrops != null && experimentGrops.length > 1) { List<String> lst = new ArrayList(); for (String[] arr : experimentGrops) { for (String s : arr) { lst.add(s); } } experimentGrops = new String[1][]; experimentGrops[0] = (String[]) lst.toArray(new String[lst.size()]); } if (experimentGrops != null) { String fmt = AnLocale.getString("Comparison Group %d"); String toolTip = AnLocale.getString("Exeriment(s) to compare against baseline experiment(s)"); for (int i = 2; i < experimentGrops.length; i++) { expGrops.add(new ExperimentGroupsPanel(window, frame, String.format(fmt, i), toolTip, ' ')); // expGrops.add(new ExpGrpJPanel(window, frame, String.format(fmt))); } for (int i = 0; i < experimentGrops.length; i++) { ExperimentGroupsPanel grp = expGrops.get(i); String[] names = experimentGrops[i]; List<String> lst = new ArrayList<String>(); for (String s : names) { grp.add_exp_or_grp(lst, s); } grp.update_exps_list(lst); } } workPanel = new JPanel(); workPanel.setLayout(new BoxLayout(workPanel, BoxLayout.Y_AXIS)); for (ExperimentGroupsPanel pnl : expGrops) { workPanel.add(pnl); } btnOk = newButton(AnLocale.getString("OK"), "btnOk"); btnCancel = newButton(AnLocale.getString("Cancel"), "btnCancel"); btnAddGrp = newButton(AnLocale.getString("Add More"), "btnAddGrp"); btnAddGrp.setToolTipText(AnLocale.getString("Add a group")); btnHelp = newButton(AnLocale.getString("Help"), "btnHelp"); btnHelp.setMnemonic(AnLocale.getString('H', "CompareDialogHelpButtonMN")); getRootPane().setDefaultButton(btnOk); // default action (Return key) JPanel btnPanel = new JPanel(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); final JCheckBox showWarningCheckBox = new JCheckBox(AnLocale.getString("Show warning")); AnUtility.setAccessibleContext( showWarningCheckBox.getAccessibleContext(), showWarningCheckBox.getText()); showWarningCheckBox.setMnemonic(AnLocale.getString('S', "CompareDialogShowWarningButtonMN")); showWarningCheckBox.setSelected(UserPref.getInstance().showCompareSourceWarning()); showWarningCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { UserPref.getInstance().setShowCompareSourceWarning(showWarningCheckBox.isSelected()); warningPanel.setVisible(showWarningCheckBox.isSelected()); pack(); } }); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(0, 4, 0, 0); btnPanel.add(showWarningCheckBox, gridBagConstraints); JLabel warningIconLabel = new JLabel(); warningIconLabel.setIcon(AnUtility.warningIcon); JTextArea textArea = new JTextArea( AnLocale.getString( "To compare sources in experiments, first archive the sources in each experiment" + " using the command \"er_archive -s all <experiment-name>\". See er_archive" + " man page for details.")); textArea.getAccessibleContext().setAccessibleName(AnLocale.getString("Text Area")); textArea.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Text Area")); textArea.setWrapStyleWord(true); textArea.setLineWrap(true); textArea.setEditable(false); // textArea.setRows(4); textArea.setOpaque(false); warningPanel = new JPanel(); warningPanel.setBorder(BorderFactory.createLineBorder(AnEnvironment.ABOUT_BOX_BORDER_COLOR)); warningPanel.setLayout(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 2, 0, 0); warningPanel.add(warningIconLabel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 1.0; gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 8, 0, 0); warningPanel.add(textArea, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.insets = new Insets(4, 8, 0, 8); btnPanel.add(warningPanel, gridBagConstraints); warningPanel.setVisible(showWarningCheckBox.isSelected()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = GridBagConstraints.LINE_START; // gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(12, 8, 8, 0); btnPanel.add(btnAddGrp, gridBagConstraints); btnAddGrp.setVisible(expGrops.size() < maxGroups); // btnAddGrp.setEnabled(expGrops.size() < Max_Exp_Groups); gridBagConstraints.weightx = 1.0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; btnPanel.add(new JLabel(""), gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(12, 0, 8, 0); btnPanel.add(btnOk, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(12, 6, 8, 0); btnPanel.add(btnCancel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(12, 6, 8, 8); btnPanel.add(btnHelp, gridBagConstraints); scrollPane = new AnJScrollPane(workPanel); scrollPane.setBorder(new EmptyBorder(0, 4, 0, 4)); scrollPane.setPreferredSize(new Dimension(AnVariable.WIN_SIZE)); final Container cnt = getContentPane(); cnt.setLayout(new BorderLayout()); cnt.add(scrollPane, BorderLayout.CENTER); cnt.add(btnPanel, BorderLayout.SOUTH); pack(); } private JButton newButton(String txt, String cmd) { JButton btn = new JButton(); btn.setText(txt); AnUtility.setAccessibleContext(btn.getAccessibleContext(), txt); btn.setActionCommand(cmd); btn.addActionListener(this); return btn; } // Set visible public void setVisible(final boolean set, final int active_id) { CompareAdvancedDialog.super.setVisible(set); // SwingUtilities.invokeLater(new Runnable() { // @Override // public void run() { // CompareDialog.super.setVisible(set); // } // }); // if (UserPref.getInstance().showCompareSourceWarning()) { // showSourceWarningDialog(); // } } /** Listener to switch between file/printer */ @Override public void itemStateChanged(final ItemEvent event) { // final Object source = event.getItemSelectable(); } /** * Action performed * * @param event */ // @Override public void actionPerformed(final ActionEvent event) { String cmd = event.getActionCommand(); if (cmd.equals("btnAddGrp")) { int sz = expGrops.size(); String nm = sz > 1 ? String.format(AnLocale.getString("Comparison Group %d:"), sz) : // String.format(AnLocale.getString("And Compare Baseline to:")) : AnLocale.getString("Compare Group:"); ExperimentGroupsPanel pnl = new ExperimentGroupsPanel( window, frame, nm, "Experiment(s) to compare against baseline experiment(s)", ' '); expGrops.add(pnl); int ind = workPanel.getComponentZOrder(expGrops.get(sz - 1)); workPanel.add(pnl, ind + 1); btnAddGrp.setVisible(expGrops.size() < maxGroups); pack(); } else if (cmd.equals("btnOk")) { setExperimentsGroups(); setVisible(false); } else if (cmd.equals("btnCancel")) { setVisible(false); } else if (cmd.equals("btnHelp")) { showHelp(); } } private void showHelp() { if (compare_mode) { Analyzer.showHelp(AnVariable.HELP_Compare); } else { Analyzer.showHelp(AnVariable.HELP_Aggregate); } } private void setExperimentsGroups() { int cnt = 0; for (ExperimentGroupsPanel expGroup : expGrops) { if (!expGroup.listAbsPathes.isEmpty()) { cnt++; } } String[][] arr = new String[cnt][]; cnt = 0; for (ExperimentGroupsPanel expGroup : expGrops) { List<String> lst = expGroup.listAbsPathes; if (!lst.isEmpty()) { arr[cnt] = lst.toArray(new String[lst.size()]); cnt++; } } window.loadExperimentGroups(arr, null, !window.experimentsLoaded(), null, false); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/AnTransferHandler.java�������������������������������������0000644�0001750�0001750�00000005130�14517772113�021566� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.compare; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.StringSelection; import java.awt.datatransfer.Transferable; import java.awt.datatransfer.UnsupportedFlavorException; import java.io.IOException; import javax.swing.JComponent; import javax.swing.TransferHandler; abstract class AnTransferHandler extends TransferHandler { protected abstract String exportString(JComponent c); protected abstract void importString(JComponent c, String str); protected abstract void cleanup(JComponent c, boolean remove); protected Transferable createTransferable(JComponent c) { return new StringSelection(exportString(c)); } public int getSourceActions(JComponent c) { debug("AnTransferHandler::getSourceActions:"); return COPY_OR_MOVE; } public boolean importData(JComponent c, Transferable t) { debug("AnTransferHandler::importData:"); if (canImport(c, t.getTransferDataFlavors())) { try { String str = (String) t.getTransferData(DataFlavor.stringFlavor); importString(c, str); return true; } catch (UnsupportedFlavorException ex) { debug("AnTransferHandler::importData: " + ex); } catch (IOException ex) { debug("AnTransferHandler::importData: " + ex); } } return false; } protected void exportDone(JComponent c, Transferable data, int action) { debug("AnTransferHandler::exportDone: " + (action == MOVE) + " " + action); debug("AnTransferHandler::exportDone: " + data); cleanup(c, action == MOVE); } public boolean canImport(JComponent c, DataFlavor[] flavors) { for (int i = 0; i < flavors.length; i++) { if (DataFlavor.stringFlavor.equals(flavors[i])) { debug("AnTransferHandler::canImport: true"); return true; } } debug("AnTransferHandler::canImport: false"); return false; } protected void debug(final String msg) { // System.out.println(msg); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareStatusPanel.java������������������������������������0000644�0001750�0001750�00000051155�14517772113�022007� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.compare; import static org.gprofng.mpmt.event.AnChangeEvent.Type.DEBUG; import static org.gprofng.mpmt.event.AnChangeEvent.Type.EXPERIMENTS_LOADED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.EXPERIMENTS_LOADED_FAILED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.EXPERIMENTS_LOADING_ADDED_OR_REMOVED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.EXPERIMENTS_LOADING_NEW; import static org.gprofng.mpmt.event.AnChangeEvent.Type.FILTER_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.FILTER_CHANGING; import static org.gprofng.mpmt.event.AnChangeEvent.Type.MOST_RECENT_EXPERIMENT_LIST_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.REMOTE_CONNECTION_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.REMOTE_CONNECTION_CHANGING; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SELECTED_OBJECT_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SELECTION_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SELECTION_CHANGING; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SELECTION_UPDATE; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGING; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SOURCE_FINDING_CHANGED; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SOURCE_FINDING_CHANGING; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnIconButton; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.settings.CompareModeSetting; import org.gprofng.mpmt.settings.CompareModeSetting.CompareMode; import org.gprofng.mpmt.util.gui.AnGradientPanel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; public class CompareStatusPanel extends javax.swing.JPanel implements AnChangeListener { private javax.swing.JLabel compareLabel; private ToolbarToggleButton absoluteButton; private ToolbarToggleButton deltaButton; private ToolbarToggleButton ratioButton; private JButton reverseButton; private JButton configureButton; private CompareGroupsPanel compareGroupsPanel; private int initialHeight; /** Creates new form CompareNavigationPanel */ public CompareStatusPanel() { initComponents(); setOpaque(false); GridBagConstraints gridBagConstraints = new GridBagConstraints(); // Label compareLabel = new JLabel(); compareLabel.setText(AnLocale.getString("Compare")); AnUtility.setAccessibleContext(compareLabel.getAccessibleContext(), compareLabel.getText()); compareLabel.setFont(compareLabel.getFont().deriveFont(Font.BOLD)); compareLabel.setForeground(AnEnvironment.FILTER_HEADER_COLOR); compareLabel.setDisplayedMnemonic(AnLocale.getString('p', "CompareStatusPanelMN")); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; add(compareLabel, gridBagConstraints); // Button panel absoluteButton = new ToolbarToggleButton(AnUtility.compareAbsoluteIcon); absoluteButton.setToolTipText(AnLocale.getString("Absolute: show absolute numbers in tables")); absoluteButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { CompareModeSetting compareModeSetting = AnWindow.getInstance().getSettings().getCompareModeSetting(); if (compareModeSetting.get() != CompareModeSetting.CompareMode.CMP_ENABLE) { compareModeSetting.set( CompareStatusPanel.this, CompareModeSetting.CompareMode.CMP_ENABLE); } } }); deltaButton = new ToolbarToggleButton(AnUtility.compareDeltaIcon); deltaButton.setToolTipText( AnLocale.getString("Delta: show numbers in tables as +/- difference")); deltaButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { CompareModeSetting compareModeSetting = AnWindow.getInstance().getSettings().getCompareModeSetting(); if (compareModeSetting.get() != CompareModeSetting.CompareMode.CMP_DELTA) { compareModeSetting.set( CompareStatusPanel.this, CompareModeSetting.CompareMode.CMP_DELTA); } } }); ratioButton = new ToolbarToggleButton(AnUtility.compareRatioIcon); ratioButton.setToolTipText(AnLocale.getString("Ratio: show numbers in tables as ratio")); ratioButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { CompareModeSetting compareModeSetting = AnWindow.getInstance().getSettings().getCompareModeSetting(); if (compareModeSetting.get() != CompareModeSetting.CompareMode.CMP_RATIO) { compareModeSetting.set( CompareStatusPanel.this, CompareModeSetting.CompareMode.CMP_RATIO); } } }); reverseButton = new AnIconButton(AnUtility.compareReverseIcon); reverseButton.setToolTipText(AnLocale.getString("Reverse comparison order")); reverseButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow anWindow = AnWindow.getInstance(); String groups[][] = anWindow.getExperimentGroups(); int nGroups = groups.length; if (nGroups > 1) { String newGroups[][] = new String[nGroups][]; for (int n = 0; n < nGroups; n++) { newGroups[n] = groups[nGroups - 1 - n]; } anWindow.loadExperimentGroups( newGroups, null, !anWindow.experimentsLoaded(), null, false); } } }); configureButton = new AnIconButton(AnUtility.compareHamburgerIcon); compareLabel.setLabelFor(configureButton); configureButton.setToolTipText(AnLocale.getString("Configure comparison")); configureButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().compareExperimentsAction(); } }); JPanel buttonPanel = new AnGradientPanel( AnEnvironment.FILTER_TOOLBAR_BACKGROUND1_COLOR, AnEnvironment.FILTER_TOOLBAR_BACKGROUND2_COLOR); buttonPanel.setLayout(new GridBagLayout()); buttonPanel.setBorder( BorderFactory.createMatteBorder(1, 1, 1, 1, AnEnvironment.FILTER_STATUS_BORDER_COLOR)); gridBagConstraints = new GridBagConstraints(); int gridX = 0; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(2, 3, 2, 0); buttonPanel.add(absoluteButton, gridBagConstraints); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(2, 2, 2, 0); buttonPanel.add(deltaButton, gridBagConstraints); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(2, 2, 2, 0); buttonPanel.add(ratioButton, gridBagConstraints); gridBagConstraints.anchor = GridBagConstraints.EAST; gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(2, 2, 2, 0); buttonPanel.add(reverseButton, gridBagConstraints); // gridBagConstraints.anchor = GridBagConstraints.EAST; gridBagConstraints.gridx = gridX++; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 0.0; gridBagConstraints.insets = new Insets(2, 0, 2, 3); buttonPanel.add(configureButton, gridBagConstraints); JPanel buttonAndFiltersPanel = new JPanel(new GridBagLayout()); buttonAndFiltersPanel.setBackground(AnEnvironment.NAVIGATION_PANEL_SECTION_BACKGROUND_COLOR); // buttonAndFiltersPanel.setBorder(BorderFactory.createMatteBorder(1, 1, 1, 1, // AnEnvironment.NAVIGATION_SPLIT_PANE_DIVIDER_COLOR)); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); buttonAndFiltersPanel.add(buttonPanel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(3, 0, 0, 0); add(buttonAndFiltersPanel, gridBagConstraints); CompareGroupsPanel compareGroupsPanel = new CompareGroupsPanel(); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); add(compareGroupsPanel, gridBagConstraints); updateCompareModeStatus(); AnEventManager.getInstance().addListener(this); updateAllButtonStates(false); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getInputMap(JComponent.WHEN_FOCUSED) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getActionMap() .put( KeyboardShortcuts.helpActionShortcut, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { Analyzer.getInstance().showHelp(AnVariable.HELP_Compare); } }); initialHeight = getPreferredSize().height; } public int getDiffFromInitialHeight() { int diff = getPreferredSize().height - initialHeight; return diff; } private void updateToggleButtons(ToolbarToggleButton toolbarToggleButton) { if (toolbarToggleButton != absoluteButton) { absoluteButton.toggle(false); } if (toolbarToggleButton != deltaButton) { deltaButton.toggle(false); } if (toolbarToggleButton != ratioButton) { ratioButton.toggle(false); } } private void updateCompareButtonStates() { String groups[][] = AnWindow.getInstance().getExperimentGroups(); boolean on = groups != null && groups.length > 1; if (!on) { absoluteButton.toggle(false); deltaButton.toggle(false); ratioButton.toggle(false); } absoluteButton.setEnabled(on); deltaButton.setEnabled(on); ratioButton.setEnabled(on); reverseButton.setEnabled(on); } private void updateAllButtonStates(boolean on) { absoluteButton.setEnabled(on); deltaButton.setEnabled(on); ratioButton.setEnabled(on); reverseButton.setEnabled(on); configureButton.setEnabled(on); } class ToolbarToggleButton extends JButton { private boolean on; public ToolbarToggleButton(ImageIcon image) { this(image, true); } public ToolbarToggleButton(ImageIcon image, final boolean toggle) { super(image); setBorder(BorderFactory.createLineBorder(AnEnvironment.COMPARE_TOGGLE_ICON_BORDER_COLOR, 1)); setBackground(AnEnvironment.COMPARE_ICON_TOGGLE_BACKGROUND_COLOR); setContentAreaFilled(true); toggle(false); if (toggle) { addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (!on) { on = true; toggle(on); updateToggleButtons(ToolbarToggleButton.this); } } }); } addMouseListener( new MouseAdapter() { @Override public void mouseEntered(MouseEvent e) { if (!isEnabled()) { return; } setBorder( BorderFactory.createLineBorder( AnEnvironment.COMPARE_TOGGLE_ICON_BORDER_FOCUSED_COLOR, 1)); } @Override public void mouseExited(MouseEvent e) { if (!isEnabled()) { return; } setBorder( BorderFactory.createLineBorder( AnEnvironment.COMPARE_TOGGLE_ICON_BORDER_COLOR, 1)); } @Override public void mousePressed(MouseEvent e) { if (!isEnabled()) { return; } if (!on) { setBackground(AnEnvironment.COMPARE_ICON_MOUSE_PRESSED_BACKGROUND_COLOR); setContentAreaFilled(true); } } @Override public void mouseReleased(MouseEvent e) { if (!isEnabled()) { return; } if (!on) { setBackground(AnEnvironment.COMPARE_TOGGLE_ICON_SELECTED_COLOR); setContentAreaFilled(true); } } }); addFocusListener( new FocusListener() { @Override public void focusGained(FocusEvent e) { setBorder( BorderFactory.createLineBorder( AnEnvironment.COMPARE_TOGGLE_ICON_BORDER_FOCUSED_COLOR, 1)); validate(); repaint(); } @Override public void focusLost(FocusEvent e) { setBorder( BorderFactory.createLineBorder( AnEnvironment.COMPARE_TOGGLE_ICON_BORDER_COLOR, 1)); validate(); repaint(); } }); } public void toggle(boolean on) { this.on = on; if (on) { setContentAreaFilled(true); setBackground(AnEnvironment.COMPARE_TOGGLE_ICON_SELECTED_COLOR); } else { setContentAreaFilled(true); setBackground(AnEnvironment.COMPARE_ICON_TOGGLE_BACKGROUND_COLOR); } } /** * @return the on */ public boolean isOn() { return on; } } /** Called from settings */ private void updateCompareModeStatus() { CompareMode compareMode = AnWindow.getInstance().getSettings().getCompareModeSetting().get(); // System.out.println(compareMode); if (compareMode == CompareModeSetting.CompareMode.CMP_ENABLE) { absoluteButton.toggle(true); updateToggleButtons(absoluteButton); } else if (compareMode == CompareModeSetting.CompareMode.CMP_DELTA) { deltaButton.toggle(true); updateToggleButtons(deltaButton); } else if (compareMode == CompareModeSetting.CompareMode.CMP_RATIO) { ratioButton.toggle(true); updateToggleButtons(ratioButton); } else { // nothing } } private void updateCompareGroupPanel() { // Compare groups panel if (compareGroupsPanel != null) { remove(compareGroupsPanel); } compareGroupsPanel = new CompareGroupsPanel(); GridBagConstraints gridBagConstraints; gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); add(compareGroupsPanel, gridBagConstraints); setMinimumSize(getPreferredSize()); } private void updateHeight(int oldHeight) { int newHeight = getPreferredSize().height; int diff = newHeight - oldHeight; if (oldHeight == 0 || (diff >= -1 && diff <= 1)) { return; } AnWindow.getInstance().getNavigationPanel().adjustCompareNavigationPanelHeightChanged(diff); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("FilterStatusPanel stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: case EXPERIMENTS_LOADED_FAILED: updateAllButtonStates(false); break; case EXPERIMENTS_LOADED: int oldHeight = getPreferredSize().height; updateCompareGroupPanel(); updateAllButtonStates(true); updateCompareButtonStates(); updateHeight(oldHeight); break; case FILTER_CHANGED: case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getOriginalSource() != this) { if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE) { updateCompareModeStatus(); } } break; case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case DEBUG: break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.GridBagLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/ExperimentGroupsPanel.form���������������������������������0000644�0001750�0001750�00000017233�14517772113�022556� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <Properties> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[800, 150]"/> </Property> </Properties> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-88"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Container class="javax.swing.JPanel" name="innerPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="label"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JScrollPane" name="jScrollPane1"> <AuxValues> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="3" fill="1" ipadX="384" ipadY="71" insetsTop="4" insetsLeft="4" insetsBottom="8" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <SubComponents> <Component class="javax.swing.JList" name="listExpNames"> <Properties> <Property name="model" type="javax.swing.ListModel" editor="org.netbeans.modules.form.editors2.ListModelEditor"> <StringArray count="0"/> </Property> <Property name="visibleRowCount" type="int" value="3"/> </Properties> <AccessibilityProperties> <Property name="AccessibleContext.accessibleName" type="java.lang.String" value="Experiments list"/> <Property name="AccessibleContext.accessibleDescription" type="java.lang.String" value="Experiments list"/> <Property name="AccessibleContext.accessibleParent" type="javax.accessibility.Accessible" editor="org.netbeans.modules.form.ComponentChooserEditor"> <ComponentRef name="listExpNames"/> </Property> </AccessibilityProperties> <AuxValues> <AuxValue name="JavaCodeGenerator_SerializeTo" type="java.lang.String" value="ExpGrpJPanel_listExpNames"/> <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value=""/> <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/> </AuxValues> </Component> </SubComponents> </Container> <Component class="javax.swing.JButton" name="btnAddExp"> <Properties> <Property name="text" type="java.lang.String" value="Add..."/> <Property name="actionCommand" type="java.lang.String" value="btnAddExp"/> </Properties> <AuxValues> <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="8" insetsBottom="0" insetsRight="4" anchor="18" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="btnRemove"> <Properties> <Property name="text" type="java.lang.String" value="Remove"/> <Property name="actionCommand" type="java.lang.String" value="btnRemove"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="btnRemoveActionPerformed"/> </Events> <AuxValues> <AuxValue name="JavaCodeGenerator_VariableModifier" type="java.lang.Integer" value="1"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="8" insetsBottom="0" insetsRight="4" anchor="18" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> </SubComponents> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/compare/CompareGroupsPanel.java������������������������������������0000644�0001750�0001750�00000013434�14517772113�022001� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.compare; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.ActionTextField; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.JLabel; public class CompareGroupsPanel extends javax.swing.JPanel { private JLabel[] labels; private ActionTextField[] textFields; public CompareGroupsPanel() { String[][] groups = AnWindow.getInstance().getExperimentGroups(); initComponents(); setLayout(new GridBagLayout()); // setBorder(BorderFactory.createMatteBorder(0, 1, 1, 1, // AnEnvironment.FILTER_STATUS_BORDER_COLOR)); setBackground(AnEnvironment.FILTER_TOOLBAR_BACKGROUND1_COLOR); if (groups == null) { return; } if (groups.length == 1) { return; } labels = new JLabel[groups.length]; textFields = new ActionTextField[groups.length]; for (int n = 0; n < groups.length; n++) { String groupText = ""; String groupTTText = ""; GridBagConstraints gridBagConstraints; if (n == 0) { labels[n] = new JLabel(AnLocale.getString("Baseline:")); groupTTText = AnLocale.getString("Comparison Baseline: "); } else { String text; String ttText; if (AnWindow.getInstance().isExperimentGroupsSimple()) { text = AnLocale.getString("Exp."); ttText = AnLocale.getString("Comparison Experiment"); } else { text = AnLocale.getString("Group"); ttText = AnLocale.getString("Comparison Group"); } labels[n] = new JLabel(text + " " + n + ":"); groupTTText = ttText + " " + n + ": "; } for (int i = 0; i < groups[n].length; i++) { if (i > 0) { groupText = groupText + ", "; groupTTText = groupTTText + ", "; } groupText = groupText + AnUtility.basename(groups[n][i]); groupTTText = groupTTText + groups[n][i]; } labels[n].setToolTipText(groupTTText); textFields[n] = new ActionTextField(groupText); textFields[n].setEditable(false); textFields[n].setToolTipText(groupTTText); textFields[n].setBorder( BorderFactory.createLineBorder(AnEnvironment.FILTER_TOOLBAR_BACKGROUND2_COLOR, 1)); textFields[n].setBackground(new Color(243, 243, 243)); textFields[n].addActionListener(new TextFieldRemoveAction(n)); textFields[n].setActionToolTipText(AnLocale.getString("Remove this experiment/group")); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = n; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 2, 2, 2); add(labels[n], gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = n; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(2, 2, 2, 2); add(textFields[n], gridBagConstraints); } setBorder( BorderFactory.createMatteBorder(0, 1, 1, 1, AnEnvironment.FILTER_STATUS_BORDER_COLOR)); } class TextFieldRemoveAction implements ActionListener { private int groupNo; public TextFieldRemoveAction(int groupNo) { this.groupNo = groupNo; } @Override public void actionPerformed(ActionEvent e) { AnWindow anWindow = AnWindow.getInstance(); String groups[][] = anWindow.getExperimentGroups(); int nGroups = groups.length; String newGroups[][] = new String[nGroups - 1][]; int index = 0; for (int i = 0; i < nGroups; i++) { if (i == groupNo) { i++; // Skip the deleted one if (i == nGroups) { break; } } newGroups[index++] = groups[i]; } anWindow.loadExperimentGroups(newGroups, null, !anWindow.experimentsLoaded(), null, false); } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 400, Short.MAX_VALUE)); layout.setVerticalGroup( layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 300, Short.MAX_VALUE)); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnCompDisp.java����������������������������������������������������0000644�0001750�0001750�00000100373�14517772113�016601� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.util.gui.AnSplitPaneInternal; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.CardLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSplitPane; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; public class AnCompDisp extends FuncListDisp implements ExportSupport { protected FuncListDisp oneDispPanel; private Component multiDispPanel; private boolean initialized, inCompute; private CardLayout cardLayout; // private FuncListDisp[] funcDisps; private AnTable[] tables; private AnHotGap[] hotGps; private int[] groupIds; private JPanel[] jpanels; private Object[] raw_datas, raw_data_ids, src_types, met_labels, marks, marks_inc; private AnObject[][] cmp_totals; private long[] sel_objs; private int[] sel_indexes; private int focusedTable; private String[] str_errors; private final String help_id; // private JPanel cards; public AnCompDisp(final AnWindow w, final int type, final String help_id) { super(w, type, 0, help_id); this.help_id = help_id; initialized = inCompute = false; cardLayout = null; multiDispPanel = null; } @Override protected void initComponents() {} @Override public void requestFocus() { if (!window.getSettings().getCompareModeSetting().comparingExperiments()) { if (oneDispPanel != null) { oneDispPanel.requestFocus(); } } else { AnTable table = tables[focusedTable]; if (table != null) { table.requestFocus(); } } } public int getTableIndex(AnTable table) { int index = -1; for (AnTable at : tables) { index++; if (at == table) { return index; } } return -1; } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String text = ""; if ((null == tables) || (tables.length < 2)) { // Not comparison text = oneDispPanel.exportAsText(limit, format, delimiter); // exports the main table } else { // Comparison String sortedby = null; // Source and Disassembly are not sorted if (null == MaximumValues) { // Print error message and stack trace System.err.println("Internal Error: MaximumValues is null"); Exception e = new Exception(); e.printStackTrace(); return text; // empty report } int printLimit = limit != null ? limit : 0; // Export tables for (int i = 0; i < tables.length; i++) { table = tables[i]; if (i > 0) { text += "\n\n\n"; // Separator } int st = i + 1; AnObject[] totals = getTotals(type, st); // IPC call if (totals != null) { if (MaximumValues == null) { MaximumValues = new Object[2][totals.length]; MaximumValues[1] = totals; } MaximumValues[0] = totals; } text += table.printTableHeader(sortedby, MaximumValues); text += table.printTableContents(MaximumValues, printLimit); } } return text; } @Override public JPopupMenu getFilterPopup() { if (oneDispPanel != null) { return oneDispPanel.getFilterPopup(); } return null; } private static JPanel toolbarPanel = null; // Fixup: pass it to SourceDisp instead of being static!!!! public static JPanel getToolbarPanelInternal() { if (toolbarPanel == null) { toolbarPanel = new JPanel(); toolbarPanel.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); toolbarPanel.setLayout(new BorderLayout()); } return toolbarPanel; } @Override public JPanel getToolbarPanel() { return getToolbarPanelInternal(); } // Update view specific tool bar public void updateToolBar() { if ((jpanels.length == 1) && oneDispPanel != null) { oneDispPanel.updateToolBar(); } else { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { if (backForwardControls == null) { backForwardControls = new CompBackForwardControls(); } backForwardControls.updateToolBarStatus(); AnCompDisp.getToolbarPanelInternal().removeAll(); AnCompDisp.getToolbarPanelInternal().add(backForwardControls, BorderLayout.CENTER); AnCompDisp.getToolbarPanelInternal().repaint(); } }); } } protected class CompBackForwardControls extends BackForwardControls { public CompBackForwardControls() { setOpaque(false); this.removeAll(); setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints; // Back button gridBagConstraints = new GridBagConstraints(); backButton = new AnIconButton(AnUtility.goBackwardIcon); backButton.setMargin(new Insets(2, 4, 2, 4)); backButton.setToolTipText( AnLocale.getString("Back") + AnUtility.keyStrokeToStringFormatted(KeyboardShortcuts.backwardActionShortcut)); backButton.setEnabled(true); backButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // Hook it up to back action; tables[focusedTable].goBack(); } }); // Backward KeyStroke keyStrokeBackward = KeyboardShortcuts.backwardActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeBackward, keyStrokeBackward); getActionMap() .put( keyStrokeBackward, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { backButton.doClick(); } }); add(backButton, gridBagConstraints); // Back button gridBagConstraints = new GridBagConstraints(); forwardButton = new AnIconButton(AnUtility.goForwardIcon); forwardButton.setMargin(new Insets(2, 4, 2, 4)); forwardButton.setToolTipText( AnLocale.getString("Forward") + AnUtility.keyStrokeToStringFormatted(KeyboardShortcuts.forwardActionShortcut)); forwardButton.setEnabled(true); forwardButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // Hook it up to forward action; tables[focusedTable].goForward(); } }); // Forward KeyStroke keyStrokeForward = KeyboardShortcuts.forwardActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeForward, keyStrokeForward); getActionMap() .put( keyStrokeForward, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { forwardButton.doClick(); } }); add(forwardButton, gridBagConstraints); } public void updateToolBarStatus() { backButton.setEnabled(tables[focusedTable].canGoBack()); forwardButton.setEnabled(tables[focusedTable].canGoForward()); } } private FuncListDisp newFuncListDisp(final int dsp, final String help_id) { FuncListDisp fd = null; if (AnDisplay.DSP_Source == dsp) { fd = new SourceDisp(window, dsp, help_id); } else if (AnDisplay.DSP_Disassembly == dsp) { fd = new DisasmDisp(window, dsp, help_id); } else { fd = new FuncListDisp(window, dsp, 0, help_id); } fd.setMinimumSize(new Dimension(0, 0)); // make the both parts to be 0ed return fd; } private void init() { if (cardLayout == null) { cardLayout = new CardLayout(); setLayout(cardLayout); oneDispPanel = newFuncListDisp(type, help_id); add(oneDispPanel, ONE_DISP_PANEL); } if (multiDispPanel != null) { cardLayout.removeLayoutComponent(multiDispPanel); } String acName = AnLocale.getString("Source"); String acDesc = AnLocale.getString("Show source for selected function"); if ((type == AnDisplay.DSP_Disassembly) || (type == AnDisplay.DSP_DisassemblyV2)) { acName = AnLocale.getString("Disassembly"); acDesc = AnLocale.getString("Show disassembled code for selected function"); } JLabel acLabel = new JLabel(acName, JLabel.RIGHT); focusedTable = 0; groupIds = window.getGroupIds(); int sz = groupIds.length; if (sz <= 0) { // no experiments loaded return; } tables = new AnTable[sz]; hotGps = new AnHotGap[sz]; jpanels = new JPanel[sz]; for (int i = 0; i < sz; i++) { tables[i] = new AnTable( type == AnDisplay.DSP_Source ? AnDisplay.DSP_SourceV2 : AnDisplay.DSP_DisassemblyV2, true, true, false, false, true, true, (i == 0 ? true : false), acName, acDesc, acLabel); tables[i].setParent(this); tables[i].setGroupId(i); tables[i].addAnListener(new TableHandler(i)); jpanels[i] = new JPanel(new BorderLayout()); hotGps[i] = new AnHotGap(this, tables[i], 47); // FIXUP jpanels[i].add(tables[i], BorderLayout.CENTER); JPanel buttonPan = new JPanel(new GridBagLayout()); buttonPan.setBackground(Color.WHITE); JButton upButton = new AnIconButton(AnUtility.goUpIcon); JButton downButton = new AnIconButton(AnUtility.goDownIcon); upButton.addActionListener(new CompDispButtonListener(i, false)); downButton.addActionListener(new CompDispButtonListener(i, true)); upButton.setToolTipText( AnLocale.getString("Previous Hot Line") + AnUtility.keyStrokeToStringFormatted( KeyboardShortcuts.sourcePreviousHotLineActionShortcut)); downButton.setToolTipText( AnLocale.getString("Next Hot Line") + AnUtility.keyStrokeToStringFormatted( KeyboardShortcuts.sourceNextHotLineActionShortcut)); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = 0; buttonPan.add(upButton, gridBagConstraints); gridBagConstraints.gridy = 1; gridBagConstraints.anchor = GridBagConstraints.NORTH; gridBagConstraints.weighty = 1.0; buttonPan.add(downButton, gridBagConstraints); Dimension dim = new Dimension(AnHotGap.HOTGAP_WIDTH, 3 * (tables[i].getFont().getSize() + 3) + 2); buttonPan.setPreferredSize(dim); JPanel gapPan = new JPanel(); gapPan.setLayout(new BorderLayout()); gapPan.add(buttonPan, BorderLayout.NORTH); gapPan.add(hotGps[i]); gapPan.setBorder( BorderFactory.createMatteBorder(0, 1, 0, 0, AnEnvironment.SCROLLBAR_BORDER_COLOR)); jpanels[i].add(gapPan, BorderLayout.EAST); } // Previous Hot Line KeyStroke keyStrokeUp = KeyboardShortcuts.sourcePreviousHotLineActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeUp, keyStrokeUp); getActionMap() .put( keyStrokeUp, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (focusedTable >= 0 && focusedTable < hotGps.length) { hotGps[focusedTable].HG_Prev_Hot_Line(); } } }); // Next Hot Line KeyStroke keyStrokeDown = KeyboardShortcuts.sourceNextHotLineActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeDown, keyStrokeDown); getActionMap() .put( keyStrokeDown, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (focusedTable >= 0 && focusedTable < hotGps.length) { hotGps[focusedTable].HG_Next_Hot_Line(); } } }); // Next NZ Line KeyStroke keyStrokeNextNZ = KeyboardShortcuts.sourceNextNonZeroLineActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeNextNZ, keyStrokeNextNZ); getActionMap() .put( keyStrokeNextNZ, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (focusedTable >= 0 && focusedTable < hotGps.length) { hotGps[focusedTable].HG_Next_NZ_Line(); } } }); // Previous NZ Line KeyStroke keyStrokePreviousNZ = KeyboardShortcuts.sourcePreviousNonZeroLineActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokePreviousNZ, keyStrokePreviousNZ); getActionMap() .put( keyStrokePreviousNZ, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (focusedTable >= 0 && focusedTable < hotGps.length) { hotGps[focusedTable].HG_Prev_NZ_Line(); } } }); table = tables[0]; if (jpanels.length == 1) { add(jpanels[0], MULTI_DISP_PANEL); multiDispPanel = jpanels[0]; } else if (jpanels.length > 1) { JSplitPane sp = null; for (int i = jpanels.length - 2; i >= 0; i--) { if (sp == null) { sp = new AnSplitPaneInternal(JSplitPane.VERTICAL_SPLIT, jpanels[i], jpanels[i + 1]); } else { sp = new AnSplitPaneInternal(JSplitPane.VERTICAL_SPLIT, jpanels[i], sp); } sp.setMinimumSize(new Dimension(0, 0)); sp.setContinuousLayout(true); sp.setResizeWeight(0.5); } add(sp, MULTI_DISP_PANEL); multiDispPanel = sp; } getToolbarPanelInternal().removeAll(); initialized = true; } private class CompDispButtonListener implements ActionListener { private int compIdx; private boolean findNext; public CompDispButtonListener(int idx, boolean next) { compIdx = idx; findNext = next; } public void actionPerformed(ActionEvent e) { focusedTable = compIdx; find(null, findNext, true); hotGps[compIdx].update(); } } protected void addExperiment() { initialized = false; computed = false; } @Override public synchronized void doCompute() { AnUtility.checkIfOnAWTThread(false); if (!selected) { return; } if (!initialized) { init(); if (!initialized) { return; } } if (inCompute) { return; } inCompute = true; // cards.setPreferredSize(new Dimension(AnVariable.WIN_SIZE)); // cards.setPreferredSize(oneDispPanel.getPreferredSize()); if (!window.getSettings().getCompareModeSetting().comparingExperiments()) { // XXXX oneDispPanel's computed should have been set through AnCompDisp.setComputed(). // But it's not. So we set computed here. oneDispPanel.setComputed(computed); oneDispPanel.setSelected(true); // oneDispPanel.doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) oneDispPanel .computeOnAWorkerThread(); // 22131013 - Analyzer GUI: Drag-n-drop a table header can // cause a deadlock cardLayout.show(this, ONE_DISP_PANEL); computed = true; inCompute = false; return; } long sel_func = window.getSelectedObject().getSelObj(DSP_Functions, 0); if (sel_func == 0) { // Functions tab is not updated yet. // Let's try to update Functions tab window .getFunctionsView() .computeIfNeeded(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) sel_func = window.getSelectedObject().getSelObj(DSP_Functions, 0); } long sel_obj = window.getSelectedObject().getSelObj(type, 0); // sel_objs = getComparableObjsV2(sel_obj); sel_objs = getComparableObjsV2(sel_func); long[] cmpObjs = getComparableObjsV2(sel_func); oneDispPanel.setSelected(false); raw_datas = new Object[tables.length]; raw_data_ids = new Object[tables.length]; met_labels = new Object[tables.length]; src_types = new Object[tables.length]; str_errors = new String[tables.length]; sel_indexes = new int[tables.length]; marks = new Object[tables.length]; marks_inc = new Object[tables.length]; cmp_totals = new AnObject[tables.length][]; MaximumValues = null; if (focusedTable >= tables.length) { focusedTable = 0; } for (int i = 0; i < tables.length; i++) { long cmpObj = cmpObjs[i]; if (cmpObj == 0) { str_errors[i] = AnLocale.getString("No comparable object"); continue; } int met_type = MetricsSetting.MET_COMMON | COMPARE_BIT | ((i + 1) << GROUP_ID_SHIFT); sel_objs[i] = dbeConvertSelObj(cmpObj, type); Object[] raw_data_with_ids = getFuncListV2(met_type, cmpObj, type, subtype); Object[] raw_marks = getHotMarks(type); Object[] raw_marks_inc = getHotMarksInc(type); int[][] hot_marks = new int[2][]; hot_marks[0] = (int[]) raw_marks[0]; hot_marks[1] = (int[]) raw_marks[1]; int[][] hot_marks_inc = new int[2][]; hot_marks_inc[0] = (int[]) raw_marks_inc[0]; hot_marks_inc[1] = (int[]) raw_marks_inc[1]; marks[i] = hot_marks; marks_inc[i] = hot_marks_inc; String errstr = window.getMsg(AnUtility.ERROR_MSG); if (errstr != null) { str_errors[i] = errstr; raw_datas[i] = null; marks[i] = null; marks_inc[i] = null; continue; } str_errors[i] = null; int last_ind = raw_data_with_ids.length - 1; Object[] metrics_data = (Object[]) raw_data_with_ids[last_ind]; met_labels[i] = getSettings().getMetricList(metrics_data); long[] raw_data_id = (long[]) raw_data_with_ids[last_ind - 1]; raw_data_ids[i] = raw_data_id; src_types[i] = raw_data_with_ids[last_ind - 2]; final Object[][] data = get_data((AnMetric[]) met_labels[i], raw_data_with_ids); updateMaximumValues(data); raw_datas[i] = data; cmp_totals[i] = getTotals(type, i + 1); // IPC call int sel_ind = window.getSelectedObject().getSelIndex(sel_obj, type, subtype); if (sel_ind != -1) { sel_indexes[i] = sel_ind; } else { sel_indexes[i] = getSelIndex(raw_data_id, sel_objs[i]); } } SwingUtilities.invokeLater( new Runnable() { // 22131013 - Analyzer GUI: Drag-n-drop a table header can cause a deadlock @Override public void run() { update_tables(); } }); // Set toolbar and select subviews updateToolBar(); computed = true; if (tailAction != null) { tailAction.tailFunction(); tailAction = null; } inCompute = false; } private void update_tables() { long sel_obj = 0; for (int i = 0; i < tables.length; i++) { table = tables[i]; table.setViewport(); String errstr = str_errors[i]; if (errstr != null) { window.getExperimentsView().appendLog(AnLocale.getString("Error: ") + errstr); table.showMessage(errstr); hotGps[i].update(); continue; } Object[][] raw_data = (Object[][]) raw_datas[i]; int[][] mark = (int[][]) marks[i]; int[][] mark_inc = (int[][]) marks_inc[i]; int[] src_type = (int[]) src_types[i]; if (cmp_totals[i] != null) { if (MaximumValues == null) { MaximumValues = new Object[2][cmp_totals[i].length]; MaximumValues[1] = cmp_totals[i]; } MaximumValues[0] = cmp_totals[i]; } AnMetric[] mlist = (AnMetric[]) met_labels[i]; MetricLabel[] label = getSettings().getMetricsSetting().getLabel(raw_data, MaximumValues, mlist, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndex(mlist); int sort_ind = getSettings().getMetricsSetting().getSortIndex(mlist); long sel = sel_objs[i]; AnUtility.checkIPCOnWrongThread(false); String[] hdrContent = getNames(type, sel); // name column table header contents (?) AnUtility.checkIPCOnWrongThread(true); if (sel_obj == 0) { sel_obj = sel; } AnUtility.checkIPCOnWrongThread(false); table.setData( label, raw_data, hdrContent, src_type, sel_indexes[i], name_col, sort_ind, mark, mark_inc); AnUtility.checkIPCOnWrongThread(true); table.setSelectedRow(sel_indexes[i]); hotGps[i].update(); } cardLayout.show(this, MULTI_DISP_PANEL); table = tables[0]; updateSummary(sel_obj); } public void goToLine(final AnTable tbl, final int row) { for (int i = 0, sz = tables != null ? tables.length : 0; i < sz; i++) { if (tbl == tables[i]) { if (tables[i].getNavigationHistoryPool() != null) { if (type == DSP_Source || type == DSP_SourceV2) { tables[i].getNavigationHistoryPool().getHistory().goToSrcNew(row); } else if (type == DSP_Disassembly || type == DSP_DisassemblyV2) { tables[i].getNavigationHistoryPool().getHistory().goToDisNew(row); } updateToolBar(); } goToLine(i, row); } } } private void goToLine(final int cmp_index, final int row) { table = tables[cmp_index]; long[] raw_data_id = (long[]) raw_data_ids[cmp_index]; if (raw_data_id == null) { return; } if (row < 0 || row >= raw_data_id.length) { return; } long sel_obj = raw_data_id[row]; int sz_table = tables != null ? tables.length : 0; for (int i = 0; i < sz_table; i++) { tables[i].clearSelection(); } tables[cmp_index].setSelectedRow(row); int selType = type; if (type == AnDisplay.DSP_Source) { selType = AnDisplay.DSP_SourceV2; } else if (type == AnDisplay.DSP_Disassembly) { selType = AnDisplay.DSP_DisassemblyV2; } window.getSelectedObject().setSelObj(sel_obj, selType, subtype); updateSummary(sel_obj); AnUtility.checkIPCOnWrongThread(false); long[] cmpObjs = getComparableObjsV2(sel_obj); AnUtility.checkIPCOnWrongThread(true); if (cmpObjs == null) { return; } for (int i = 0; i < sz_table; i++) { if (cmpObjs[i] != 0 && cmp_index != i) { long[] ids = (long[]) raw_data_ids[i]; int sel_ind = getSelIndex(ids, cmpObjs[i]); if (sel_ind != -1) { long curRow = ((tables[i].srcRenderer != null) ? tables[i].srcRenderer : tables[i].disRenderer) .getFunctionBaseRowWhenCompare(tables[i].getSelectedRow()); long tgtRow = ((tables[i].srcRenderer != null) ? tables[i].srcRenderer : tables[i].disRenderer) .getFunctionBaseRowWhenCompare(sel_ind); if (tgtRow != curRow) { tables[i].setSelectedRow(sel_ind); } } } } } private int getSelIndex(long[] raw_data_id, long sel_obj) { if (raw_data_id == null || sel_obj == 0) { return -1; } for (int i = 0; i < raw_data_id.length; i++) { if (raw_data_id[i] == sel_obj) { return i; } } return -1; } private void updateMaximumValues(final Object[][] data) { int nc = (data == null) ? 0 : data.length; // Updates MaximumValues (Total and Max values) // Note: Total is not used, so only Maximum is updated. if (MaximumValues == null) { MaximumValues = new Object[2][nc]; AnAddress aa = new AnAddress(0); AnDouble ad = new AnDouble(0.0); AnInteger ai = new AnInteger(0); AnLong al = new AnLong(0); AnString as = new AnString(""); for (int i = 0; i < nc; i++) { Object obj, arr = data[i]; if (arr instanceof AnDouble[]) { obj = ad; } else if (arr instanceof AnInteger[]) { obj = ai; } else if (arr instanceof AnLong[]) { obj = al; } else if (arr instanceof AnAddress[]) { obj = aa; } else { obj = as; } MaximumValues[0][i] = obj; MaximumValues[1][i] = obj; } } for (int i = 0; i < nc; i++) { Object[] arr = data[i]; Object obj = MaximumValues[1][i]; int max_len = obj.toString().length(); for (int k = 0; k < arr.length; k++) { int len = arr[k].toString().length(); if (max_len < len) { max_len = len; obj = arr[k]; } } MaximumValues[0][i] = obj; MaximumValues[1][i] = obj; } } // Listener for updating table private final class TableHandler implements AnListener { private int cmp_index; TableHandler(int ind) { super(); cmp_index = ind; } public void valueChanged(final AnEvent event) { switch (event.getType()) { case AnEvent.EVT_SELECT: { table = tables[cmp_index]; int row = event.getValue(); focusedTable = cmp_index; boolean[] enabled = new boolean[tables.length]; for (int i = 0; i < tables.length; i++) { enabled[i] = tables[i].getNavigationHistoryPool().getHistory().enabled; tables[i].getNavigationHistoryPool().getHistory().enabled = false; } int[] sel_rows = table.getSelectedRows(); if (sel_rows.length > 1) { // multi-selection // Update Summary int len = sel_rows.length; long[] raw_data_id = (long[]) raw_data_ids[cmp_index]; long[] multi_sel_objs = new long[len]; for (int i = 0; i < len; i++) { multi_sel_objs[i] = raw_data_id[sel_rows[i]]; } window.getSelectionManager().updateSelection(multi_sel_objs, type, subtype, 2); break; } goToLine(cmp_index, row); for (int i = 0; i < tables.length; i++) { tables[i].getNavigationHistoryPool().getHistory().enabled = enabled[i]; } break; } case AnEvent.EVT_SORT: // Sorting break; case AnEvent.EVT_COPY_ALL: // Copy all lines copyAll(); break; case AnEvent.EVT_COPY_SEL: // Copy selected lines copySelected(); break; case AnEvent.EVT_SWITCH: { // Column switching table = tables[cmp_index]; if (table != null) { table.columnsSaved = false; } int from = event.getValue(); int to = ((Integer) event.getAux()).intValue(); getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, type); break; } } } } protected void filterChanged() { // System.out.println("AnCompDisp:filterChanged: " + this); if (!window.getSettings().getCompareModeSetting().comparingExperiments()) { if (oneDispPanel == null) { return; } if (oneDispPanel instanceof SourceDisp) { // FIXUP: REARCH: this is a mess. Just following previous code logic! ((SourceDisp) oneDispPanel).filterChanged(); } } } public void clearHistory() { if (!window.getSettings().getCompareModeSetting().comparingExperiments()) { if (oneDispPanel == null) { return; } oneDispPanel.clearHistory(); } } @Override protected boolean supportsFindText() { return true; } @Override public int find(final String str, final boolean next, boolean caseSensitive) { if (!window.getSettings().getCompareModeSetting().comparingExperiments()) { return oneDispPanel.find(str, next, caseSensitive); } AnTable tbl = tables[focusedTable]; if (tbl != null) { int find_row = table.findAfter(str, next, caseSensitive); if (find_row == -1) { find_row = table.findBefore(str, next, caseSensitive); } if (find_row != -1) { goToLine(tbl, find_row); return find_row; } } return -1; } private long[] getComparableObjsV2(long sel_obj) { synchronized (IPC.lock) { window.IPC().send("getComparableObjsV2"); window.IPC().send(0); window.IPC().send(sel_obj); window.IPC().send(type); return (long[]) window.IPC().recvObject(); } } protected Object[] getFuncListV2( final int met_type, final long sel_func, final int type, final int subtype) { synchronized (IPC.lock) { window.IPC().send("getFuncListV2"); window.IPC().send(0); window.IPC().send(met_type); window.IPC().send(sel_func); window.IPC().send(type); window.IPC().send(subtype); return (Object[]) window.IPC().recvObject(); } } protected long dbeConvertSelObj(final long obj, final int type) { synchronized (IPC.lock) { window.IPC().send("dbeConvertSelObj"); window.IPC().send(obj); window.IPC().send(type); return window.IPC().recvLong(); } } protected void updateSummary(final long sel_obj) { // final Object[] data; // long[] objs = new long[1]; // objs[0] = sel_obj; // synchronized (IPC.lock) { // window.IPC().send("getSummaryV2"); // window.IPC().send(window.getWindowID()); // window.IPC().send(objs); // window.IPC().send(type); // window.IPC().send(subtype); // data = (Object[]) window.IPC().recvObject(); // } // AnUtility.dispatchOnSwingThread(new Runnable() { // @Override // public void run() { // window.getSummaryPanel().updateSummary(data, type); // } // }); window.getSelectionManager().updateSelection(sel_obj, type, subtype, 2); } @Override public List<ExportFormat> getSupportedExportFormats() { List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.TEXT); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return false; } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); list.add(window.getTimelineCallStackSubview()); list.add(window.getIoCallStackSubview()); list.add(window.getHeapCallStackSubview()); if (!window.getSettings().getCompareModeSetting().comparingExperiments()) { if (type == AnDisplay.DSP_Source) { list.add(window.getCalledByCallsSrcSubview()); } else if (type == AnDisplay.DSP_Disassembly) { list.add(window.getCalledByCallsDisSubview()); } } return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } private final String MULTI_DISP_PANEL = "multiDispPanel"; private final String ONE_DISP_PANEL = "oneDispPanel"; private final int COMPARE_BIT = 1 << 8; private final int GROUP_ID_SHIFT = 16; } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/DataLayoutView.java������������������������������������������������0000644�0001750�0001750�00000007457�14517772113�017517� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import javax.swing.JPanel; public final class DataLayoutView extends FuncListDisp implements AnChangeListener { public DataLayoutView() { super(AnWindow.getInstance(), AnDisplay.DSP_DataLayout, 0, AnVariable.HELP_TabsDataLayout); setAccessibility(AnLocale.getString("Data Layout")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("DataLayoutView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public JPanel getToolbarPanel() { return null; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnAddress.java�����������������������������������������������������0000644�0001750�0001750�00000005476�14517772113�016460� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; // Analyzer Address object public final class AnAddress extends AnObject implements Comparable { static final long HI_BIT = 0x8000000000000000L; private static final String hexChars = "0123456789ABCDEF"; private final long value; private final Long obj; // Constructor public AnAddress(long value) { this.value = value & (~HI_BIT); obj = new Long(this.value); } // Analyzer Address printing format @Override public String toString() { if (value == 0) { if (!showZero) { return quote_space; } } return Integer.toString((int) (value >> 32)) + ":" + toHexString((int) (value & 0xFFFFFFFFL)); } // To Long private Long toLong() { return obj; } // To double @Override public double doubleValue() { return value; } // As Long.compareTo @Override public int compareTo(Object o) { return obj.compareTo(((AnAddress) o).toLong()); } // String representation as an unsigned integer in base 16 public static String toHexString(int i) { return toUnsignedString((long) i, 4, 8); } // String representation as an unsigned integer in base 16 public static String toHexString(long i) { return toUnsignedString(i, 4, 16); } // String representation as an unsigned integer in base 2^shift private static String toUnsignedString(long i, int shift, int min_len) { char[] buf = new char[32]; int charPos = 32; int end = 32 - min_len; int radix = 1 << shift; int mask = radix - 1; // Get the digits do { buf[--charPos] = hexChars.charAt((int) (i & mask)); i >>>= shift; } while (i != 0); // Fill zeros while (charPos > end) { buf[--charPos] = '0'; } return "0x" + new String(buf, charPos, (32 - charPos)); } // Check if an address element public static boolean isAddress(long value) { return (value & HI_BIT) != 0; } // Convert long[] to AnAddress[] public static AnAddress[] toArray(long[] list) { int length = list.length; AnAddress[] new_list = new AnAddress[length]; for (int i = 0; i < length; i++) { new_list[i] = new AnAddress(list[i]); } return new_list; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/InstructionFrequencyView.java��������������������������������������0000644�0001750�0001750�00000014255�14517772113�021645� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Font; import java.util.ArrayList; import java.util.List; import javax.swing.JTable; public final class InstructionFrequencyView extends AnDisplay implements ExportSupport, AnChangeListener { private static final Font table_font; private AnUtility.AnTextArea inst_log; static { JTable jtable = new JTable(); Font org_font = jtable.getFont(); table_font = new Font("Monospaced", org_font.getStyle(), org_font.getSize()); } // Constructor public InstructionFrequencyView() { super( AnWindow.getInstance(), AnDisplay.DSP_InstructionFrequency, AnVariable.HELP_WelcomeAnalyzer); setAccessibility(AnLocale.getString("Instruction Frequency")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("InstructionFrequencyView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: addExperiment(); if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { StringBuilder buf = new StringBuilder(); buf.append(getAnDispTab().getTName()); buf.append("\n"); buf.append(inst_log.getText()); return buf.toString(); } @Override public List<ExportFormat> getSupportedExportFormats() { List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.TEXT); // formats.add(ExportFormat.HTML); // formats.add(ExportFormat.CSV); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return false; } // Initialize GUI components @Override protected void initComponents() { setLayout(new BorderLayout()); inst_log = new AnUtility.AnTextArea(null, false); inst_log.setFont(table_font); add(new AnJScrollPane(inst_log), BorderLayout.CENTER); } // Clear the text area on add experiment private void addExperiment() { inst_log.setText(""); } // Compute & update Statistics display @Override public void doCompute() { String[] inst_data; int size; AnUtility.checkIfOnAWTThread(false); // Not selected if (!selected) { return; } if (!computed) { // need re-compute // Get data inst_log.setText(""); inst_data = getIfreqData(); if (inst_data != null) { size = inst_data.length; for (int i = 0; i < size; i++) { inst_log.append(AnUtility.trimNewLine(inst_data[i]) + "\n"); } } } computed = true; } // Native methods from liber_dbe.so private String[] getIfreqData() { synchronized (IPC.lock) { window.IPC().send("getIfreqData"); window.IPC().send(0); return (String[]) window.IPC().recvObject(); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnList.java��������������������������������������������������������0000644�0001750�0001750�00000010235�14517772113�015773� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.util.gui.AnJPanel; import java.awt.*; import javax.swing.*; public final class AnList extends AnJPanel { private final boolean resizable; private final JPanel label; private final JPanel value; // Constructor public AnList(final boolean resizable) { this.resizable = resizable; label = new AnJPanel(); label.setLayout(new BoxLayout(label, BoxLayout.Y_AXIS)); value = new AnJPanel(); value.setLayout(new BoxLayout(value, BoxLayout.Y_AXIS)); if (resizable) { BorderLayout borderLayout = new BorderLayout(); if (AnEnvironment.isLFNimbus()) { borderLayout.setHgap(4); } setLayout(borderLayout); add(label, BorderLayout.WEST); add(value, BorderLayout.CENTER); } else { add(label); add(value); } } // Add label public JComponent addLabel(final JComponent item) { return (JComponent) label.add((item != null) ? item : new AnJPanel()); } // Add value private JComponent addValue(final JComponent item) { return (JComponent) value.add((item != null) ? item : new AnJPanel()); } // Add label and value public void add(final JComponent litem, final JComponent vitem) { setAlignmentY(addLabel(litem), addValue(vitem)); } // Align labels and values vertically private void setAlignmentY(final JComponent litem, final JComponent vitem) { final Dimension lsize; final Dimension vsize; Dimension msize; lsize = new Dimension(litem.getPreferredSize()); vsize = new Dimension(vitem.getPreferredSize()); if (lsize.height < vsize.height) { lsize.height = vsize.height; } else { vsize.height = lsize.height; } // Set labels size if (resizable) { msize = litem.getMaximumSize(); msize.height = lsize.height; litem.setMaximumSize(msize); } else { litem.setMaximumSize(new Dimension(lsize)); } litem.setMinimumSize(new Dimension(lsize)); litem.setPreferredSize(new Dimension(lsize)); // Set values size if (resizable) { msize = vitem.getMaximumSize(); msize.height = vsize.height; vitem.setMaximumSize(msize); } else { vitem.setMaximumSize(new Dimension(vsize)); } vitem.setMinimumSize(new Dimension(vsize)); vitem.setPreferredSize(new Dimension(vsize)); } // Align Labels and Values vertically public void setAlignmentY() { final Component[] labels = label.getComponents(); final Component[] values = value.getComponents(); final int size = Math.min(labels.length, values.length); for (int i = 0; i < size; i++) { setAlignmentY((JComponent) labels[i], (JComponent) values[i]); } } // Align items horizontally private void setAlignmentX(final Component[] items) { final int size; int width; int max_width; Dimension psize; size = items.length; max_width = 0; for (int i = 0; i < size; i++) { width = items[i].getPreferredSize().width; if (max_width < width) { max_width = width; } } for (int i = 0; i < size; i++) { psize = items[i].getPreferredSize(); psize.width = max_width; ((JComponent) items[i]).setPreferredSize(psize); } } // Align the Values only horizontally, usually the Labels does not need // further alignment public void setAlignmentX() { setAlignmentX(value.getComponents()); } // Clean up public void removeAll() { label.removeAll(); value.removeAll(); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/MemoryIndexObjectView.java�����������������������������������������0000644�0001750�0001750�00000010666�14517772113�021033� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import java.util.ArrayList; import java.util.List; import javax.swing.JPanel; public final class MemoryIndexObjectView extends FuncListDisp implements AnChangeListener { // Constructor public MemoryIndexObjectView(final int type, final int subtype, final String help_id) { super(AnWindow.getInstance(), type, subtype, help_id); setAccessibility(AnLocale.getString("Memory or Index Object")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("MemoryIndexObjectView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public JPanel getToolbarPanel() { return null; } /** * Called before new memory/index objects are created. Cleanup old ones before they are removed. */ public void toBeRemoved() { // Remove listeners AnEventManager.getInstance().removeListener(this); } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } } ��������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/PCsView.java�������������������������������������������������������0000644�0001750�0001750�00000007404�14517772113�016125� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import javax.swing.JPanel; public final class PCsView extends FuncListDisp implements AnChangeListener { public PCsView() { super(AnWindow.getInstance(), AnDisplay.DSP_PCs, 0, AnVariable.HELP_TabsPCs); setAccessibility(AnLocale.getString("PCs")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("PCsView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public JPanel getToolbarPanel() { return null; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnWindow.java������������������������������������������������������0000644�0001750�0001750�00000446643�14517772113�016347� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.collect.CollectDialog; import org.gprofng.mpmt.collect.CollectPanel; import org.gprofng.mpmt.collect.Collector; import org.gprofng.mpmt.compare.CompareAdvancedDialog; import org.gprofng.mpmt.compare.CompareSimpleDialog; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.experiment_props.Experiments; import org.gprofng.mpmt.export.Export; import org.gprofng.mpmt.export.ExportDialog; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.export.ExportSupport.ExportFormat; import org.gprofng.mpmt.filter.Filters; import org.gprofng.mpmt.flame.FlameView; import org.gprofng.mpmt.guitesting.GUITesting; import org.gprofng.mpmt.ipc.IPCCancelledException; import org.gprofng.mpmt.ipc.IPCContext; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.mainview.MainViewPanel; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.metrics.IPCMetricsAPI; import org.gprofng.mpmt.metrics.MetricNode; import org.gprofng.mpmt.navigation.NavigationPanel; import org.gprofng.mpmt.navigation.View; import org.gprofng.mpmt.navigation.ViewsPanel; import org.gprofng.mpmt.overview.OverviewView; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.picklist.PickListElement; import org.gprofng.mpmt.progress.SystemProgressPanel; import org.gprofng.mpmt.remote.CloseExperimentDialog; import org.gprofng.mpmt.remote.ConnectionDialog; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.settings.CompareModeSetting; import org.gprofng.mpmt.settings.CompareModeSetting.CompareMode; import org.gprofng.mpmt.settings.ExportSettingsDialog; import org.gprofng.mpmt.settings.FormatSetting; import org.gprofng.mpmt.settings.ImportSettingsDialog; import org.gprofng.mpmt.settings.LibraryVisibilitySetting; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.settings.PathMapSetting; import org.gprofng.mpmt.settings.SearchPathSetting; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.settings.TimelineSetting; import org.gprofng.mpmt.settings.ViewModeEnabledSetting; import org.gprofng.mpmt.settings.ViewModeSetting; import org.gprofng.mpmt.settings.ViewModeSetting.ViewMode; import org.gprofng.mpmt.settings.ViewsSetting; import org.gprofng.mpmt.settings.ViewsSetting.CustomObject; import org.gprofng.mpmt.statecolors.AnColorChooser; import org.gprofng.mpmt.statuspanel.StatusHandleFactory; import org.gprofng.mpmt.statuspanel.StatusLabelHandle; import org.gprofng.mpmt.statuspanel.StatusLabelValueHandle; import org.gprofng.mpmt.statuspanel.StatusPanel; import org.gprofng.mpmt.timeline2.TimelineView; import org.gprofng.mpmt.toolbar.ToolBarFiller; import org.gprofng.mpmt.toolbar.ToolBarPanel; import org.gprofng.mpmt.toolbar.ToolBarSeparator; import org.gprofng.mpmt.util.gui.AnDialog2; import org.gprofng.mpmt.util.gui.AnSplitPane; import org.gprofng.mpmt.util.gui.AnTextIcon; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.gui.ToolTipPopup; import org.gprofng.mpmt.welcome.WelcomeView; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.accessibility.AccessibleContext; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JSplitPane; import javax.swing.JTextArea; import javax.swing.JToolBar; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.MenuEvent; import javax.swing.event.MenuListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; public final class AnWindow implements AnChangeListener { private static AnWindow instance; // Actions private static final String ACTION_PROFILE_APP = AnLocale.getString("Profile Application...", "ACTION_PROFILE_APP"); private static final String ACTION_PROFILE_APP_TT = AnLocale.getString( "Start an application and collect profiling data to create an experiment", "ACTION_PROFILE_APP_TT"); // GUI test failures!!! private static final String ACTION_PROFILE_APP_TT_GUITESTING = AnLocale.getString("Profile Application", "ACTION_PROFILE_APP_TT"); private static final String ACTION_PROFILE_APP_AC = ACTION_PROFILE_APP_TT; private static final String ACTION_PROFILE_RUNNING_PROCESS = AnLocale.getString("Profile Running Process...", "ACTION_PROFILE_RUNNING_PROCESS"); private static final String ACTION_PROFILE_RUNNING_PROCESS_TT = AnLocale.getString( "Attach to a running process and create an experiment", "ACTION_PROFILE_RUNNING_PROCESS_TT"); private static final String ACTION_PROFILE_RUNNING_PROCESS_AC = ACTION_PROFILE_RUNNING_PROCESS_TT; private static final String ACTION_PROFILE_KERNEL = AnLocale.getString("Profile Kernel...", "ACTION_PROFILE_KERNEL"); private static final String ACTION_PROFILE_KERNEL_TT = AnLocale.getString("Profile Kernel", "ACTION_PROFILE_KERNEL_TT"); private static final String ACTION_PROFILE_KERNEL_AC = ACTION_PROFILE_KERNEL_TT; private static final String ACTION_OPEN_EXPERIMENT = AnLocale.getString("Open Experiment...", "ACTION_OPEN_EXPERIMENT"); private static final String ACTION_OPEN_EXPERIMENT_TT = AnLocale.getString( "Select an experiment to view", "ACTION_OPEN_EXPERIMENT_TT"); // GUI test failures!!! private static final String ACTION_OPEN_EXPERIMENT_TT_GUITESTING = AnLocale.getString("Open Experiment", "ACTION_OPEN_EXPERIMENT_TT"); private static final String ACTION_OPEN_EXPERIMENT_AC = ACTION_OPEN_EXPERIMENT_TT; private static final String ACTION_COMPARE = AnLocale.getString("Compare Experiments...", "ACTION_COMPARE"); private static final String ACTION_COMPARE_TT = AnLocale.getString( "Select multiple experiments and compare their data", "ACTION_COMPARE_TT"); // GUI test failures!!! private static final String ACTION_COMPARE_TT_GUITESTING = AnLocale.getString("Compare Experiments", "ACTION_COMPARE_TT"); private static final String ACTION_COMPARE_AC = ACTION_COMPARE_TT; private static final String ACTION_AGGREGATE = AnLocale.getString("Aggregate Experiments...", "ACTION_AGGREGATE"); private static final String ACTION_AGGREGATE_TT = AnLocale.getString("Aggregate Experiments", "ACTION_AGGREGATE_TT"); private static final String ACTION_AGGREGATE_AC = ACTION_AGGREGATE_TT; private static final String ACTION_SHOW_ERRORS_WARNINGS = AnLocale.getString("Show Errors & Warnings", "ACTION_SHOW_ERRORS_WARNINGS"); private static final String ACTION_SHOW_ERRORS_WARNINGS_TT = AnLocale.getString("Show Errors & Warnings", "ACTION_SHOW_ERRORS_WARNINGS_TT"); private static final String ACTION_SHOW_ERRORS_WARNINGS_AC = ACTION_SHOW_ERRORS_WARNINGS_TT; private static final String ACTION_CONNECT = AnLocale.getString("Connect to Remote Host...", "ACTION_CONNECT"); private static final String ACTION_CONNECT_TT = AnLocale.getString( "Connect to a remote host to profile applications or view experiments", "ACTION_CONNECT_TT"); private static final String ACTION_CONNECT_AC = ACTION_CONNECT_TT; private static final String ACTION_EXPORT = AnLocale.getString("Export...", "ACTION_EXPORT"); private static final String ACTION_EXPORT_TT = AnLocale.getString("Export", "ACTION_EXPORT_TT"); private static final String ACTION_EXPORT_AC = ACTION_EXPORT_TT; private static final String ACTION_EXIT = AnLocale.getString("Exit", "ACTION_EXIT"); private static final String ACTION_PREVIOUS_VIEW = AnLocale.getString("Previous View", "ACTION_PREVIOUS_VIEW"); private static final String ACTION_PREVIOUS_VIEW_TT = AnLocale.getString("Previous View (Shift+F7)", "ACTION_PREVIOUS_VIEW_TT"); private static final String ACTION_PREVIOUS_VIEW_AC = ACTION_PREVIOUS_VIEW_TT; private static final String ACTION_NEXT_VIEW = AnLocale.getString("Next View", "ACTION_NEXT_VIEW"); private static final String ACTION_NEXT_VIEW_TT = AnLocale.getString("Next View (F7)", "ACTION_NEXT_VIEW_TT"); private static final String ACTION_NEXT_VIEW_AC = ACTION_PREVIOUS_VIEW_TT; private static final String ACTION_VIEWS_SETTINGS = AnLocale.getString("Views Settings...", "ACTION_VIEWS_SETTINGS"); private static final String ACTION_VIEWS_SETTINGS_TT = AnLocale.getString("Views Settings", "ACTION_VIEWS_SETTINGS_TT"); private static final String ACTION_VIEWS_SETTINGS_AC = ACTION_VIEWS_SETTINGS_TT; private static final String ACTION_METRICS_SETTINGS = AnLocale.getString("Metrics Settings...", "ACTION_METRICS_SETTINGS"); private static final String ACTION_METRICS_SETTINGS_TT = AnLocale.getString("Metrics Settings", "ACTION_METRICS_SETTINGS_TT"); private static final String ACTION_METRICS_SETTINGS_AC = ACTION_METRICS_SETTINGS_TT; private static final String ACTION_ADD_REMOVE_FILTERS = AnLocale.getString("Add or remove filters...", "ACTION_ADD_REMOVE_FILTERS"); private static final String ACTION_ADD_REMOVE_FILTERS_TT = AnLocale.getString("Add or remove filters", "ACTION_ADD_REMOVE_FILTERS_TT"); private static final String ACTION_ADD_REMOVE_FILTERS_AC = ACTION_ADD_REMOVE_FILTERS_TT; private static final String ACTION_LIBRARY_VISIBILITY = AnLocale.getString("Library Visibility...", "ACTION_LIBRARY_VISIBILITY"); private static final String ACTION_LIBRARY_VISIBILITY_TT = AnLocale.getString("Library Visibility", "ACTION_LIBRARY_VISIBILITY_TT"); private static final String ACTION_LIBRARY_VISIBILITY_AC = ACTION_LIBRARY_VISIBILITY_TT; private static final String ACTION_FUNCTION_COLORS = AnLocale.getString("Function Colors...", "ACTION_FUNCTION_COLORS"); private static final String ACTION_FUNCTION_COLORS_TT = AnLocale.getString("Function Colors", "ACTION_FUNCTION_COLORS_TT"); private static final String ACTION_FUNCTION_COLORS_AC = ACTION_FUNCTION_COLORS_TT; private static final String ACTION_SETTINGS = AnLocale.getString("Settings...", "ACTION_SETTINGS"); private static final String ACTION_SETTINGS_TT = AnLocale.getString("Settings", "ACTION_SETTINGS_TT"); private static final String ACTION_SETTINGS_AC = ACTION_SETTINGS_TT; private static final String ACTION_EXPORT_SETTINGS = AnLocale.getString("Export Settings...", "ACTION_EXPORT_SETTINGS"); private static final String ACTION_IMPORT_SETTINGS = AnLocale.getString("Import Settings...", "ACTION_IMPORT_SETTINGS"); private static final String ACTION_EXPORT_SETTINGS_AS = AnLocale.getString("Export Settings as .er.rc...", "ACTION_EXPORT_SETTINGS_AS"); private static final String ACTION_HELP_TT = AnLocale.getString("Opens a documentation window in the gprofng GUI"); private static final String ACTION_HELP_AC = ACTION_HELP_TT; private static final String ACTION_HELP_PERFORMANCE_ANALYZER = AnLocale.getString("gprofng Analyzer"); private static final String ACTION_HELP_NEW_FEATURES = AnLocale.getString("New Features"); private static final String ACTION_HELP_INFORMATION_MAP = AnLocale.getString("Information Map"); private static final String ACTION_HELP_KEYBOARD_SHORTCUTS = AnLocale.getString("Keyboard Shortcuts"); private static final String ACTION_HELP_SHORTCUTS = AnLocale.getString("Help Shortcuts"); private static final String ACTION_HELP_TROUBLESHOOTING = AnLocale.getString("Troubleshooting"); private static final String ACTION_ABOUT_ANALYZER = AnLocale.getString("About gprofng GUI"); // Experiment status private static final int EXP_SUCCESS = 0; private static final int EXP_BROKEN = 4; private static final int EXP_OBSOLETE = 8; // Panels/Panes/Components private final AnFrame frame; private JPanel mainPanel; private ToolBarPanel toolBarPanel; private JPanel centerPanel; private StatusPanel statusPanel; private JComponent menuBar; private JPanel centerPanelSplit; private MainViewPanel mainViewPanel; private AnSplitPane navigationPanelSplitPane; private NavigationPanel navigationPanel; private SystemProgressPanel systemProgressPanel; private StatusLabelHandle tableStatusHandle; private StatusLabelValueHandle localHostStatusHandle; private StatusLabelValueHandle remoteHostStatusHandle; private StatusLabelValueHandle compareStatusHandle; private StatusLabelValueHandle showErrorsWarningsStatusHandle; private StatusLabelValueHandle filterStatusHandle; private StatusLabelValueHandle workingDirectoryStatusHandle; private StatusLabelValueHandle debugStatusHandle; private SummaryPanel summaryPanel; // Dialogs private Settings settings = null; private AnColorChooser colorChooser; private AnChooser anFileChooser; private ConnectionDialog connectionChooser = null; private AnChooser anRemoteFileChooser; private JLabel viewModeLabel; private JComboBox viewModeComboBox; private ToolBarSeparator viewModeSeparator; private ToolBarFiller viewModeFiller; private CollectDialog profileApplicationDialog = null; private CollectDialog profileRunningProcessDialog = null; private CollectDialog profileKernelDialog = null; private LibraryVisibilityDialog libraryVisibilityDialog = null; // Actions private AnAction profileApplicationAction; private AnAction profileRunningProcessAction; private AnAction profileKernelAction; private AnAction openExperimentAction; private AnAction compareExperimentsAction; private AnAction aggregateExperimentsAction; private AnAction showErrorsWarningsAction; private AnAction connectAction; private AnAction exportAction; private AnAction exitAction; // private AnAction previousViewAction; private AnAction nextViewAction; private AnAction viewsSettingsAction; // private AnAction metricsSettingsAction; // private AnAction addRemoveFiltersAction; private AnAction libraryVisibilityAction; private AnAction functionColorsAction; private AnAction settingsAction; private AnAction exportSettingsAction; private AnAction importSettingsAction; private AnAction exportSettingsAsAction; // private AnAction helpAnalyzerAction; private AnAction helpNewFeaturesAction; private AnAction helpInformationMapAction; private AnAction helpKeyboardShortcutsAction; private AnAction helpShortcutsAction; private AnAction helpTroubleShootingAction; private AnAction aboutAnalyzerAction; // Menus private JMenu fileMenu; private JMenu recentExperimentsMenu; private JMenu metricsMenu; private JMenu viewsMenu; private JMenu toolsMenu; private JMenu filtersMenu; private JMenu helpMenu; private JSeparator showErrorsWarningsSeparator; private JMenuItem showErrorsWarningsMenuItem; // States private Analyzer analyzer; private ViewDisplayPanel viewDisplayPanel; private Filters filters = null; // Holding and managing filters private Experiments experimentProperties; private SelectedObject selectedObject = null; private SelectionManager selectionManager = null; private String[][] experimentGroups = null; // The groups of loaded experiments private boolean hasErrorsAndWarnings = false; // AnDispTab's private AnDispTab welcomeDispTab = null; private AnDispTab overviewDispTab = null; // Current View and View lists private List<AnDisplay> standardDisplayList; // Display list (static) private List<AnDisplay> memoryIndexDisplayList; // Memory/Index objects Display list (dynamic) // Main Views (AnDisplay) private WelcomeView welcomeView; private OverviewView overviewView; private FunctionsView functionsView; private CallerCalleesView callerCalleesView; private CallTreeView callTreeView; private FlameView flameView; private SourceView sourceView; private DisassemblyView disassemblyView; private LinesView linesView; private PCsView pcsView; private DataLayoutView dataLayoutView; private DataObjectsView dataObjectsView; private IOView ioView; private HeapView heapView; private StatisticsView statisticsView; private SourceDisassemblyView sourceDisassemblyView; private ExperimentsView experimentsView; private TimelineView timelineView; private DualSourceView dualSourceView; private InstructionFrequencyView instructionFrequencyView; // Others views private CalledByCallsSourceView calledByCallsSourceView; private CalledByCallsDisassemblyView calledByCallsDisassemblyView; private CalledByCallsFunctionsView calledByCallsFunctionsView; // Subviews private List<Subview> subviewList = new ArrayList(); // List of all subviews, may contain null's private Subview selectedDetailsSubview = null; private Subview selectedDetailsSubviewTimeLine = null; private Subview timelineCallStackSubview = null; private Subview ioCallStackSubview = null; private Subview heapCallStackSubview = null; private Subview calledByCallsSrcSubview = null; private Subview calledByCallsDisSubview = null; private Subview calledByCallsFuncSubview = null; // ********************************************************************************************** // Constructor public AnWindow(Analyzer parent, AnFrame frame, Container contentPane, JComponent manuBar) { instance = this; this.analyzer = parent; this.frame = frame; this.menuBar = manuBar; manuBar.setBackground(AnEnvironment.MENUBAR_BACKGROUND_COLOR); initComponents(); enableSessionActions(false, false); selectedObject = new SelectedObject(); selectionManager = new SelectionManager(); AnEventManager.getInstance().addListener(this); } public static AnWindow getInstance() { return instance; } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("AnWindow stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: case EXPERIMENTS_LOADED_FAILED: break; case EXPERIMENTS_LOADED: if (connectionChooser != null) { if (connectionChooser.isVisible()) { connectionChooser.requestFocus(); } } break; case FILTER_CHANGED: case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE) { updateViewMode(); } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE_ENABLED) { updateViewModeVisibility(); } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEWS) { ViewsSetting.Setting oldSetting = (ViewsSetting.Setting) anSettingChangeEvent.getOldValue(); ViewsSetting.Setting newSetting = (ViewsSetting.Setting) anSettingChangeEvent.getNewValue(); updateViews(oldSetting, newSetting); } else if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE) { updateCompareModeStatus(); } break; case DEBUG: // debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } // Initialize GUI components private void initComponents() { mainPanel = new JPanel(new BorderLayout()); getFrame().getContentPane().add(mainPanel); initActions(); toolBarPanel = initToolBarPanel(); initMenus(); initViewsAndOtherComponents(); centerPanel = initCenterPanel(); statusPanel = initStatusPanel(); mainPanel.add(toolBarPanel, BorderLayout.NORTH); mainPanel.add(centerPanel, BorderLayout.CENTER); mainPanel.add(statusPanel, BorderLayout.SOUTH); } private void initActions() { profileApplicationAction = new AnAction( ACTION_PROFILE_APP, AnUtility.collect_icon, GUITesting.getInstance().isRunningUnderGUITesting() ? ACTION_PROFILE_APP_TT_GUITESTING : ACTION_PROFILE_APP_TT, ACTION_PROFILE_APP_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { profileApplicationAction(null); } }); profileApplicationAction.setKeyboardShortCut( KeyboardShortcuts.profileApplicationActionShortcut); profileApplicationAction.setMnemonic(AnLocale.getString('E', "ACTION_PROFILE_APP_MN")); profileRunningProcessAction = new AnAction( ACTION_PROFILE_RUNNING_PROCESS, null, ACTION_PROFILE_RUNNING_PROCESS_TT, ACTION_PROFILE_RUNNING_PROCESS_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { profileRunningProcessAction(); } }); profileRunningProcessAction.setKeyboardShortCut( KeyboardShortcuts.profileRunningProcessActionShortcut); profileRunningProcessAction.setMnemonic( AnLocale.getString('R', "ACTION_PROFILE_RUNNING_PROCESS_MN")); profileKernelAction = new AnAction( ACTION_PROFILE_KERNEL, null, ACTION_PROFILE_KERNEL_TT, ACTION_PROFILE_KERNEL_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { profileKernelAction(); } }); profileKernelAction.setKeyboardShortCut(KeyboardShortcuts.profileKernelActionShortcut); profileKernelAction.setMnemonic(AnLocale.getString('K', "ACTION_PROFILE_KERNEL_MN")); openExperimentAction = new AnAction( ACTION_OPEN_EXPERIMENT, AnUtility.open_icon, GUITesting.getInstance().isRunningUnderGUITesting() ? ACTION_OPEN_EXPERIMENT_TT_GUITESTING : ACTION_OPEN_EXPERIMENT_TT, ACTION_OPEN_EXPERIMENT_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { openExperimentAction(); } }); openExperimentAction.setKeyboardShortCut(KeyboardShortcuts.openExperimentActionShortcut); openExperimentAction.setMnemonic(AnLocale.getString('O', "ACTION_OPEN_EXPERIMENT_MN")); compareExperimentsAction = new AnAction( ACTION_COMPARE, AnUtility.compare_icon, GUITesting.getInstance().isRunningUnderGUITesting() ? ACTION_COMPARE_TT_GUITESTING : ACTION_COMPARE_TT, ACTION_COMPARE_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { compareExperimentsAction(); } }); compareExperimentsAction.setKeyboardShortCut( KeyboardShortcuts.compareExperimentsActionShortcut); compareExperimentsAction.setMnemonic(AnLocale.getString('m', "ACTION_COMPARE_MN")); aggregateExperimentsAction = new AnAction( ACTION_AGGREGATE, AnUtility.add_icon, ACTION_AGGREGATE_TT, ACTION_AGGREGATE_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { aggregateExperimentsAction(); } }); aggregateExperimentsAction.setKeyboardShortCut( KeyboardShortcuts.aggregateExperimentsActionShortcut); aggregateExperimentsAction.setMnemonic(AnLocale.getString('A', "ACTION_AGGREGATE_MN")); showErrorsWarningsAction = new AnAction( ACTION_SHOW_ERRORS_WARNINGS, null, ACTION_SHOW_ERRORS_WARNINGS_TT, ACTION_SHOW_ERRORS_WARNINGS_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { showErrorsWarningsAction(); } }); showErrorsWarningsAction.setKeyboardShortCut( KeyboardShortcuts.showErrorsWarningsActionShortcut); showErrorsWarningsAction.setMnemonic(AnLocale.getString('W', "ACTION_SHOW_ERRORS_WARNINGS_MN")); connectAction = new AnAction( ACTION_CONNECT, AnUtility.connect_icon, ACTION_CONNECT_TT, ACTION_CONNECT_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { connectAction(); } }); connectAction.setKeyboardShortCut(KeyboardShortcuts.connectActionShortcut); connectAction.setMnemonic(AnLocale.getString('C', "ACTION_CONNECT_MN")); exportAction = new AnAction( ACTION_EXPORT, null, ACTION_EXPORT_TT, ACTION_EXPORT_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { exportAction(); } }); exportAction.setKeyboardShortCut(KeyboardShortcuts.exportActionShortcut); exportAction.setMnemonic(AnLocale.getString('P', "ACTION_EXPORT_MN")); exitAction = new AnAction( ACTION_EXIT, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { exitAction(); } }); exitAction.setMnemonic(AnLocale.getString('x', "ACTION_EXIT_MN")); previousViewAction = new AnAction( ACTION_PREVIOUS_VIEW, AnUtility.previousViewIcon, ACTION_PREVIOUS_VIEW_TT, ACTION_PREVIOUS_VIEW_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { previousViewAction(); } }); previousViewAction.setKeyboardShortCut(KeyboardShortcuts.previousViewActionShortcut); nextViewAction = new AnAction( ACTION_NEXT_VIEW, AnUtility.nextViewIcon, ACTION_NEXT_VIEW_TT, ACTION_NEXT_VIEW_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { nextViewAction(); } }); nextViewAction.setKeyboardShortCut(KeyboardShortcuts.nextViewActionShortcut); viewsSettingsAction = new AnAction( ACTION_VIEWS_SETTINGS, null, ACTION_VIEWS_SETTINGS_TT, ACTION_VIEWS_SETTINGS_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { viewsSettingsAction(); } }); viewsSettingsAction.setKeyboardShortCut(KeyboardShortcuts.viewsSettingsActionShortcut); metricsSettingsAction = new AnAction( ACTION_METRICS_SETTINGS, null, ACTION_METRICS_SETTINGS_TT, ACTION_METRICS_SETTINGS_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { metricsSettingsAction(); } }); metricsSettingsAction.setKeyboardShortCut(KeyboardShortcuts.metricsSettingsShortcut); addRemoveFiltersAction = new AnAction( ACTION_ADD_REMOVE_FILTERS, AnUtility.filt_icon, ACTION_ADD_REMOVE_FILTERS_TT, ACTION_ADD_REMOVE_FILTERS_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { addRemoveFiltersAction(e.getSource()); } }); libraryVisibilityAction = new AnAction( ACTION_LIBRARY_VISIBILITY, AnUtility.epcl_icon, ACTION_LIBRARY_VISIBILITY_TT, ACTION_LIBRARY_VISIBILITY_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { libraryVisibilityAction(); } }); libraryVisibilityAction.setKeyboardShortCut(KeyboardShortcuts.libraryVisibilityActionShortcut); libraryVisibilityAction.setMnemonic(AnLocale.getString('L', "ACTION_LIBRARY_VISIBILITY_MN")); functionColorsAction = new AnAction( ACTION_FUNCTION_COLORS, AnUtility.colr_icon, ACTION_FUNCTION_COLORS_TT, ACTION_FUNCTION_COLORS_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { functionColorsAction(); } }); functionColorsAction.setKeyboardShortCut(KeyboardShortcuts.functionColorsActionShortcut); functionColorsAction.setMnemonic(AnLocale.getString('C', "ACTION_FUNCTION_COLORS_MN")); settingsAction = new AnAction( ACTION_SETTINGS, AnUtility.gear_icon, ACTION_SETTINGS_TT, ACTION_SETTINGS_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { settingsAction(); } }); settingsAction.setKeyboardShortCut(KeyboardShortcuts.settingsActionShortcut); settingsAction.setMnemonic(AnLocale.getString('S', "ACTION_SETTINGS_MN")); exportSettingsAction = new AnAction( ACTION_EXPORT_SETTINGS, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { exportSettingsAction(); } }); exportSettingsAction.setKeyboardShortCut(KeyboardShortcuts.exportSettingsActionShortcut); exportSettingsAction.setMnemonic(AnLocale.getString('x', "ACTION_EXPORT_SETTINGS_MN")); ; importSettingsAction = new AnAction( ACTION_IMPORT_SETTINGS, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { importSettingsAction(); } }); importSettingsAction.setMnemonic(AnLocale.getString('i', "ACTION_IMPORT_SETTINGS_MN")); ; importSettingsAction.setKeyboardShortCut(KeyboardShortcuts.importSettingsActionShortcut); exportSettingsAsAction = new AnAction( ACTION_EXPORT_SETTINGS_AS, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { exportSettingsAsAction(); } }); exportSettingsAsAction.setMnemonic(AnLocale.getString('A', "ACTION_EXPORT_SETTINGS_AS_MN")); helpAnalyzerAction = new AnAction( ACTION_HELP_PERFORMANCE_ANALYZER, null, ACTION_HELP_TT, ACTION_HELP_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { helpAnalyzerAction(); } }); helpAnalyzerAction.setMnemonic(AnLocale.getString('P', "ACTION_HELP_PERFORMANCE_ANALYZER_MN")); helpNewFeaturesAction = new AnAction( ACTION_HELP_NEW_FEATURES, null, ACTION_HELP_TT, ACTION_HELP_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { helpNewFeaturesAction(); } }); helpNewFeaturesAction.setMnemonic(AnLocale.getString('N', "ACTION_HELP_NEW_FEATURES_MN")); helpInformationMapAction = new AnAction( ACTION_HELP_INFORMATION_MAP, null, ACTION_HELP_TT, ACTION_HELP_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { helpInformationMapAction(); } }); helpInformationMapAction.setMnemonic(AnLocale.getString('I', "ACTION_HELP_INFORMATION_MAP_MN")); helpKeyboardShortcutsAction = new AnAction( ACTION_HELP_KEYBOARD_SHORTCUTS, null, ACTION_HELP_TT, ACTION_HELP_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { helpKeyboardShortcutsAction(); } }); helpKeyboardShortcutsAction.setMnemonic( AnLocale.getString('K', "ACTION_HELP_KEYBOARD_SHORTCUTS_MN")); helpShortcutsAction = new AnAction( ACTION_HELP_SHORTCUTS, null, ACTION_HELP_TT, ACTION_HELP_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { helpShortcutsAction(); } }); helpShortcutsAction.setMnemonic(AnLocale.getString('S', "ACTION_HELP_SHORTCUTS_MN")); helpTroubleShootingAction = new AnAction( ACTION_HELP_TROUBLESHOOTING, null, ACTION_HELP_TT, ACTION_HELP_AC, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { helpTroubleShootingAction(); } }); helpTroubleShootingAction.setMnemonic( AnLocale.getString('r', "ACTION_HELP_TROUBLESHOOTING_MN")); aboutAnalyzerAction = new AnAction( ACTION_ABOUT_ANALYZER, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { aboutAnalyzerAction(); } }); aboutAnalyzerAction.setMnemonic(AnLocale.getString('A', "ACTION_ABOUT_ANALYZER_MN")); } private ToolBarPanel initToolBarPanel() { return new ToolBarPanel(initToolBar()); } // Initialize tool bar area private JToolBar initToolBar() { JToolBar toolBar = new JToolBar(); AnUtility.setAccessibleContext(toolBar.getAccessibleContext(), AnLocale.getString("Toolbar")); toolBar.setBorder(null); toolBar.setOpaque(false); toolBar.add(profileApplicationAction.createActionButton()); toolBar.add(openExperimentAction.createActionButton()); toolBar.add(compareExperimentsAction.createActionButton()); toolBar.add(aggregateExperimentsAction.createActionButton()); toolBar.add(connectAction.createActionButton()); toolBar.add(new ToolBarSeparator(8, 7)); toolBar.add(addRemoveFiltersAction.createActionButton()); toolBar.add(libraryVisibilityAction.createActionButton()); toolBar.add(settingsAction.createActionButton()); // View mode toolBar.add(viewModeSeparator = new ToolBarSeparator(7, 11)); viewModeLabel = new JLabel(AnLocale.getString("View Mode: ")); viewModeLabel.setDisplayedMnemonic(AnLocale.getString('d', "ViewMode")); toolBar.add(viewModeLabel); String viewModeComboBoxName = AnLocale.getString("View Mode: "); String viewModeComboBoxDesc = AnLocale.getString("Select View Mode"); String viewModeComboBoxTT = AnLocale.getString( "The View Mode setting controls the processing of Java experiments and OpenMP" + " experiments"); viewModeComboBox = new JComboBox(); viewModeLabel.setLabelFor(viewModeComboBox); viewModeComboBox.setFont(viewModeComboBox.getFont().deriveFont(Font.PLAIN)); viewModeComboBox.setToolTipText(viewModeComboBoxTT); viewModeComboBox.getAccessibleContext().setAccessibleName(viewModeComboBoxName); viewModeComboBox.getAccessibleContext().setAccessibleDescription(viewModeComboBoxDesc); viewModeComboBox.addItem(ViewModeSetting.ViewMode.USER); viewModeComboBox.addItem(ViewModeSetting.ViewMode.EXPERT); viewModeComboBox.addItem(ViewModeSetting.ViewMode.MACHINE); viewModeComboBox.setSelectedIndex(0); viewModeComboBox.setPreferredSize(new Dimension(viewModeComboBox.getPreferredSize().width, 20)); viewModeComboBox.setMaximumSize(viewModeComboBox.getPreferredSize()); viewModeComboBox.addPopupMenuListener( new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { ViewMode viewMode = (ViewMode) viewModeComboBox.getSelectedItem(); getSettings().getViewModeSetting().set(this, viewMode); } @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); toolBar.add(viewModeComboBox); toolBar.add(viewModeFiller = new ToolBarFiller(5)); updateViewModeVisibility(false); return toolBar; } // Initialize menu items private void initMenus() { // File Menu menuBar.add(fileMenu = new JMenu(AnLocale.getString("File"))); AnUtility.setAccessibleContext(fileMenu.getAccessibleContext(), fileMenu.getText()); fileMenu.setMnemonic(AnLocale.getString('F', "MNEM_MENU_FILE")); fileMenu.add(profileApplicationAction.getMenuItem()); fileMenu.add(profileRunningProcessAction.getMenuItem()); fileMenu.add(profileKernelAction.getMenuItem()); fileMenu.addSeparator(); fileMenu.add(openExperimentAction.getMenuItem()); fileMenu.add(initOpenRecentExperiments()); fileMenu.add(compareExperimentsAction.getMenuItem()); fileMenu.add(aggregateExperimentsAction.getMenuItem()); fileMenu.add(showErrorsWarningsSeparator = new JSeparator()); fileMenu.add(showErrorsWarningsMenuItem = showErrorsWarningsAction.getMenuItem()); fileMenu.addSeparator(); fileMenu.add(connectAction.getMenuItem()); fileMenu.add(exportAction.getMenuItem()); fileMenu.addSeparator(); fileMenu.add(exitAction.getMenuItem()); // Views Menu. Note: this menu is dynamic menuBar.add(viewsMenu = new JMenu(AnLocale.getString("Views"))); AnUtility.setAccessibleContext(viewsMenu.getAccessibleContext(), viewsMenu.getText()); viewsMenu.setMnemonic(AnLocale.getString('V', "MNEM_MENU_VIEWS")); viewsMenu.addMenuListener(new ViewsMenuListener(viewsMenu)); // Metrics Menu. Note: this menu is dynamic menuBar.add(metricsMenu = new JMenu(AnLocale.getString("Metrics"))); AnUtility.setAccessibleContext(metricsMenu.getAccessibleContext(), metricsMenu.getText()); metricsMenu.setMnemonic(AnLocale.getString('M', "MNEM_MENU_METRICS")); metricsMenu.addMenuListener(new MetricsMenuListener(metricsMenu)); // Tools Menu menuBar.add(toolsMenu = new JMenu(AnLocale.getString("Tools"))); AnUtility.setAccessibleContext(toolsMenu.getAccessibleContext(), toolsMenu.getText()); toolsMenu.setMnemonic(AnLocale.getString('T', "MNEM_MENU_TOOLS")); filtersMenu = new JMenu(AnLocale.getString("Filters")); AnUtility.setAccessibleContext(filtersMenu.getAccessibleContext(), filtersMenu.getText()); filtersMenu.setMnemonic(AnLocale.getString('F', "MNEM_MENU_FILTER")); filtersMenu.setIcon(AnUtility.filt_icon); toolsMenu.add(filtersMenu); filtersMenu.addMenuListener( new MenuListener() { @Override public void menuSelected(MenuEvent e) { filtersMenu.removeAll(); JPopupMenu popup = getViews().getCurrentViewDisplay().getFilterPopup(); if (popup == null) { popup = getViews().getCurrentViewDisplay().getDefaultFilterPopup(); } Component[] components = popup.getComponents(); for (Component component : components) { filtersMenu.add(component); } } @Override public void menuDeselected(MenuEvent e) {} @Override public void menuCanceled(MenuEvent e) {} }); toolsMenu.add(libraryVisibilityAction.getMenuItem()); toolsMenu.add(functionColorsAction.getMenuItem()); toolsMenu.add(settingsAction.getMenuItem()); toolsMenu.addSeparator(); toolsMenu.add(exportSettingsAction.getMenuItem()); toolsMenu.add(importSettingsAction.getMenuItem()); toolsMenu.add(exportSettingsAsAction.getMenuItem()); // Help menu menuBar.add(helpMenu = new JMenu(AnLocale.getString("Help", "MENU_HELP"))); AnUtility.setAccessibleContext(helpMenu.getAccessibleContext(), helpMenu.getText()); helpMenu.setMnemonic(AnLocale.getString('H', "MNEM_MENU_HELP")); helpMenu.add(helpAnalyzerAction.getMenuItem()); helpMenu.add(helpNewFeaturesAction.getMenuItem()); helpMenu.add(helpInformationMapAction.getMenuItem()); helpMenu.add(helpKeyboardShortcutsAction.getMenuItem()); helpMenu.add(helpShortcutsAction.getMenuItem()); helpMenu.add(helpTroubleShootingAction.getMenuItem()); helpAnalyzerAction.setEnabled(false); helpNewFeaturesAction.setEnabled(false); helpInformationMapAction.setEnabled(false); helpKeyboardShortcutsAction.setEnabled(false); helpShortcutsAction.setEnabled(false); helpTroubleShootingAction.setEnabled(false); helpMenu.addSeparator(); helpMenu.add(aboutAnalyzerAction.getMenuItem()); } private JMenu initOpenRecentExperiments() { recentExperimentsMenu = new JMenu(AnLocale.getString("Open Recent Experiment")); AnUtility.setAccessibleContext( recentExperimentsMenu.getAccessibleContext(), recentExperimentsMenu.getText()); recentExperimentsMenu.setMnemonic(AnLocale.getString('n', "MNEM_MENU_OPEN_RECENT_EXPERIMENT")); recentExperimentsMenu.addMenuListener( new MenuListener() { @Override public void menuSelected(MenuEvent e) { recentExperimentsMenu.removeAll(); List<ExperimentPickListElement> paths = UserPref.getInstance() .getExperimentsPicklists() .getPicklist() .getRecentExperiments(20); // Collections.sort(paths, new Comparator<ExperimentPickListElement>() { // @Override // public int compare(ExperimentPickListElement f1, // ExperimentPickListElement f2) { // String f11 = AnUtility.basename(f1.getPath()); // String f22 = AnUtility.basename(f2.getPath()); // return f11.toString().compareTo(f22.toString()); // } // }); for (ExperimentPickListElement experimentElement : paths) { String name = AnUtility.basename(experimentElement.getPath()); JMenuItem menuItem = new JMenuItem(name); AnUtility.setAccessibleContext(menuItem.getAccessibleContext(), " "); if (experimentElement.getPath().endsWith("erg")) { menuItem.setIcon( new ImageIcon( getClass() .getResource( "/org/gprofng/mpmt/icons/expgroup.png"))); // FIXUP: make // static } else { menuItem.setIcon( new ImageIcon( getClass() .getResource( "/org/gprofng/mpmt/icons/experiment.png"))); // FIXUP: make // static } menuItem.setActionCommand(experimentElement.getPath()); menuItem.setToolTipText(experimentElement.getToolTip()); menuItem.addActionListener(new RecentExperimentActionListener(experimentElement)); recentExperimentsMenu.add(menuItem); } if (!paths.isEmpty()) { recentExperimentsMenu.addSeparator(); JMenuItem clearMenuItem = new JMenuItem(AnLocale.getString("Clear Recent History")); AnUtility.setAccessibleContext( clearMenuItem.getAccessibleContext(), clearMenuItem.getText()); clearMenuItem.setMnemonic(AnLocale.getString('C', "ClearRecentHistoryMenuMN")); clearMenuItem.addActionListener(new ClearRecentHistoryActionListener()); recentExperimentsMenu.add(clearMenuItem); } } // @Override @Override public void menuDeselected(MenuEvent e) {} // @Override @Override public void menuCanceled(MenuEvent e) {} }); return recentExperimentsMenu; } private class ClearRecentHistoryActionListener implements ActionListener { @Override public void actionPerformed(ActionEvent e) { String asWhenClosedConfigDirPath = UserPref.getAsWhenClosedConfigDirPath(); File[] files = new File(asWhenClosedConfigDirPath).listFiles(); for (File file : files) { file.delete(); } UserPref.getInstance().getExperimentsPicklists().getPicklist().removeAllElements(); saveAnalyzerSettings(); } } private class RecentExperimentActionListener implements ActionListener { ExperimentPickListElement experimentPickListElement; public RecentExperimentActionListener(ExperimentPickListElement experimentPickListElement) { this.experimentPickListElement = experimentPickListElement; } @Override public void actionPerformed(ActionEvent e) { ArrayList<String> list = new ArrayList<String>(); list.add(experimentPickListElement.getPath()); String confPath; boolean always; if (experimentPickListElement.getConfPath() != null) { confPath = experimentPickListElement.getConfPath(); always = true; } else { confPath = UserPref.getAsWhenClosedConfigPath(experimentPickListElement.getPath()); always = false; } loadExperimentList( list, false, experimentPickListElement.getWorkingDirectory(), true, confPath, always); } } /** Called after startup */ private void initViewsAndOtherComponents() { // System.out.println("initViewsAndOtherComponents"); // Misc filters = new Filters(this, frame); experimentProperties = new Experiments(this); settings = new Settings(this, frame); colorChooser = new AnColorChooser(this, frame); summaryPanel = new SummaryPanel(); // Views viewDisplayPanel = new ViewDisplayPanel(); AccessibleContext context = viewDisplayPanel.getAccessibleContext(); String loc_string = AnLocale.getString("Analyzer Main Window"); context.setAccessibleName(loc_string); context.setAccessibleDescription(loc_string); standardDisplayList = new ArrayList<AnDisplay>(); // welcomeDisp pane welcomeView = new WelcomeView(); standardDisplayList.add(welcomeView); // Overview view overviewView = new OverviewView(); standardDisplayList.add(overviewView); // functions view functionsView = new FunctionsView(); standardDisplayList.add(functionsView); // caller-callee view callerCalleesView = new CallerCalleesView(); standardDisplayList.add(callerCalleesView); // Call Tree view callTreeView = new CallTreeView(); standardDisplayList.add(callTreeView); // Flame view flameView = new FlameView(); // flameView = new FlameViewCallTreeIPC(); standardDisplayList.add(flameView); // Source view sourceView = new SourceView(); standardDisplayList.add(sourceView); // Disassembly view disassemblyView = new DisassemblyView(); standardDisplayList.add(disassemblyView); // Lines view linesView = new LinesView(); standardDisplayList.add(linesView); // PCs view pcsView = new PCsView(); standardDisplayList.add(pcsView); // DataLayout view dataLayoutView = new DataLayoutView(); standardDisplayList.add(dataLayoutView); // DataObjects view dataObjectsView = new DataObjectsView(); standardDisplayList.add(dataObjectsView); // IO view ioView = new IOView(); standardDisplayList.add(ioView); // Heap view heapView = new HeapView(); standardDisplayList.add(heapView); // Statistics view statisticsView = new StatisticsView(); standardDisplayList.add(statisticsView); // Source/Disassembly view sourceDisassemblyView = new SourceDisassemblyView(); standardDisplayList.add(sourceDisassemblyView); // Experiments view experimentsView = new ExperimentsView(); standardDisplayList.add(experimentsView); // Timeline view timelineView = new TimelineView(); standardDisplayList.add(timelineView); // Dual Source view dualSourceView = new DualSourceView(); standardDisplayList.add(dualSourceView); // Instruction Frequency view instructionFrequencyView = new InstructionFrequencyView(); standardDisplayList.add(instructionFrequencyView); // Called By Calls Source view calledByCallsSourceView = new CalledByCallsSourceView(); standardDisplayList.add(calledByCallsSourceView); // Called By Calls Disassembly view calledByCallsDisassemblyView = new CalledByCallsDisassemblyView(); standardDisplayList.add(calledByCallsDisassemblyView); // Called By Calls Functions view calledByCallsFunctionsView = new CalledByCallsFunctionsView(); standardDisplayList.add(calledByCallsFunctionsView); } private JPanel initCenterPanel() { mainViewPanel = new MainViewPanel(); navigationPanel = new NavigationPanel(this); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; centerPanelSplit = new JPanel(new BorderLayout()); centerPanelSplit.add(mainViewPanel, BorderLayout.CENTER); JPanel centerPanelNoSplitOrSplit = new JPanel(new GridBagLayout()); centerPanelNoSplitOrSplit.setBorder( BorderFactory.createMatteBorder( 5, 0, 5, 4, AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR)); centerPanelNoSplitOrSplit.add(centerPanelSplit, gridBagConstraints); navigationPanelSplitPane = new AnSplitPane( JSplitPane.HORIZONTAL_SPLIT, navigationPanel, centerPanelNoSplitOrSplit, UserPref.getInstance().getNavigationPanelDividerPosition()); centerPanel = new JPanel(new GridBagLayout()); centerPanel.add(navigationPanelSplitPane, gridBagConstraints); navigationPanelSplitPane.setHidden(true); mainViewPanel.getMainview().add(viewDisplayPanel); return centerPanel; } private StatusPanel initStatusPanel() { statusPanel = new StatusPanel(); // Table status tableStatusHandle = StatusHandleFactory.createStatusLabel( this, "", AnLocale.getString("Selected row(s)/Total rows"), StatusPanel.Orientation.RIGHT); // Progress status systemProgressPanel = new SystemProgressPanel(); StatusHandleFactory.createStatusComponent( this, systemProgressPanel, StatusPanel.Orientation.RIGHT); // Local Host status localHostStatusHandle = StatusHandleFactory.createStatusLabelValue( this, null, AnLocale.getString("Local Host"), AnLocale.getString("Local Host"), null); String localHost = analyzer.getLocalHostName(); if (localHost != null) { localHostStatusHandle.update(AnUtility.getShortString(analyzer.getLocalHostName(), 30)); } localHostStatusHandle.setVisible(true); final KeyStroke statusFocusShortCut = KeyboardShortcuts.statusAreaShortCut; localHostStatusHandle .getTextLabel() .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(statusFocusShortCut, statusFocusShortCut); localHostStatusHandle .getTextLabel() .getActionMap() .put( statusFocusShortCut, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { localHostStatusHandle.getTextLabel().requestFocus(); } }); // Remote Host status remoteHostStatusHandle = StatusHandleFactory.createStatusLabelValue( this, null, AnLocale.getString("Remote Host"), AnLocale.getString("Connect to remote host...") + AnUtility.keyStrokeToStringFormatted(KeyboardShortcuts.connectActionShortcut), new ActionListener() { // @Override @Override public void actionPerformed(ActionEvent e) { connectAction(); } }); remoteHostStatusHandle.update("localhost"); if (!Analyzer.getInstance().IPC_started) { remoteHostStatusHandle.update(""); /* "not connected" */ } // Working Directory workingDirectoryStatusHandle = StatusHandleFactory.createStatusLabelValue( this, null, AnLocale.getString("Working Directory"), AnLocale.getString("Current working directory"), new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String currentWD = analyzer.getWorkingDirectory(); // AnChooser chooser = new AnChooser(frame, AnChooser.DIR_CHOOSER, // AnWindow.this, (boolean)false, (String)currentWD); AnChooser chooser = getAnChooser( AnLocale.getString("Working Directory"), AnChooser.DIR_CHOOSER, currentWD); int res = chooser.showDialog(frame, null); if (res == AnChooser.APPROVE_OPTION) { File wdFile = chooser.getSelectedAnFile(); String wd = wdFile.getAbsolutePath(); AnUtility.checkIPCOnWrongThread(false); analyzer.setWorkingDirectory(wd); // IPC call AnUtility.checkIPCOnWrongThread(true); // readRCFile(".er.rc"); // IPC call // viewMode = null; // Clean cache <=== FIXUP: need to refresh // other states too.... } } }); updateWorkingDirectoryStatus(); // Compare status compareStatusHandle = StatusHandleFactory.createStatusLabelValue( this, null, AnLocale.getString("Compare"), AnLocale.getString("Compare experiments...") + AnUtility.keyStrokeToStringFormatted( KeyboardShortcuts.compareExperimentsActionShortcut), new ActionListener() { // @Override @Override public void actionPerformed(ActionEvent e) { compareExperimentsAction(); } }); updateCompareModeStatus(); // Filter status filterStatusHandle = StatusHandleFactory.createStatusLabelValue( this, null, AnLocale.getString("Filters"), AnLocale.getString("Add or remove filters"), new ActionListener() { @Override public void actionPerformed(ActionEvent e) { getViews() .getCurrentViewDisplay() .showFilterPopup(filterStatusHandle.getValueLabel()); } }); filterStatusHandle.update(AnLocale.getString("off")); // Dump if (GUITesting.getInstance().guiTestingExtraEnabled()) { debugStatusHandle = StatusHandleFactory.createStatusLabelValue( this, null, AnLocale.getString("Debug"), AnLocale.getString("Debug(GUI testing)"), new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String dump; // dump = GUITesting.getInstance().dumpMainview(); // System.out.println(dump); // dump = GUITesting.getInstance().dumpViewsVisibility(); // System.out.println(dump); // dump = GUITesting.getInstance().dumpSubviews(); // System.out.println(dump); // // System.out.println(""); //// AnEventManager.getInstance().fireAnChangeEvent(new // AnChangeEvent(this, AnChangeEvent.Type.DEBUG)); //// AnEventManager.getInstance().fireAnChangeEvent(new // AnChangeEvent(this, AnChangeEvent.Type.TEST1)); // AnUtility.dispatchOnAWorkerThread(new // IPCTester.IPCTestSender(), "CCSender"); // IPCLogger.setIpcDelay(500); // int dtype = getViews().getCurrentViewDisplay().getType(); // getSettings().getMetricsSetting().dumpMetricsByDType(dtype); // getSettings().getMetricsSetting().dump(); // getSettings().getMetricsSetting().dumpSelections(); // getSettings().getMetricsSetting().getMetricStates().dump(); // // // System.out.println(GUITesting.getInstance().dumpAvailableViews()); // // AnTable.setUseAllHeaderPanel(!AnTable.isUseAllHeaderPanel()); // getSettings().getTableSettings().setWrapMetricNames(this, // !getSettings().getTableSettings().wrapMetricNames()); // // AnDisplay currentAnDisplay = // getViews().getCurrentViewDisplay(); // int dtype = currentAnDisplay.getType(); // int mtype = MetricsSetting.dtype2mtype(dtype); // System.out.println(String.format("%2d", dtype) + " " + mtype // + " " + currentAnDisplay.getAnDispTab().getTName() + " " + // currentAnDisplay.getAnDispTab().getTCmd()); // FilterClause clause = new FilterClause("1", "1", "1", // FilterClause.Kind.STANDARD); // getFilters().addClause(clause, false); System.out.println(GUITesting.getInstance().dumpMainview(7)); } }); } // Error/Warning status showErrorsWarningsStatusHandle = StatusHandleFactory.createStatusLabelValue( this, null, null, AnLocale.getString( "Experiment has errors or warnings. Click for details... (Ctrl+Shift-W)"), getShowErrorsWarningsAction()); showErrorsWarningsStatusHandle.setVisible(false); // Focus (tab) traversal localHostStatusHandle .getTextLabel() .setNextFocusableComponent(localHostStatusHandle.getValueLabel()); localHostStatusHandle .getValueLabel() .setNextFocusableComponent(remoteHostStatusHandle.getTextLabel()); remoteHostStatusHandle .getTextLabel() .setNextFocusableComponent(remoteHostStatusHandle.getValueLabel()); remoteHostStatusHandle .getValueLabel() .setNextFocusableComponent(workingDirectoryStatusHandle.getTextLabel()); workingDirectoryStatusHandle .getTextLabel() .setNextFocusableComponent(workingDirectoryStatusHandle.getValueLabel()); workingDirectoryStatusHandle .getValueLabel() .setNextFocusableComponent(compareStatusHandle.getTextLabel()); compareStatusHandle .getTextLabel() .setNextFocusableComponent(compareStatusHandle.getValueLabel()); compareStatusHandle .getValueLabel() .setNextFocusableComponent(filterStatusHandle.getTextLabel()); filterStatusHandle.getTextLabel().setNextFocusableComponent(filterStatusHandle.getValueLabel()); filterStatusHandle .getValueLabel() .setNextFocusableComponent(showErrorsWarningsStatusHandle.getTextLabel()); showErrorsWarningsStatusHandle .getTextLabel() .setNextFocusableComponent(showErrorsWarningsStatusHandle.getValueLabel()); return statusPanel; } public StatusLabelHandle getTableStatusHandle() { return tableStatusHandle; } public SystemProgressPanel getSystemProgressPanel() { return systemProgressPanel; } /** Called when IPC successfully started when connecting or re-connecting (remote). */ public void initializeAfterIPCStarted() { if (!analyzer.IPC_started) { return; } initView(0, -1); analyzer.initWorkingDirectory(); updateWorkingDirectoryStatus(); } // ********************************************************************************************** private void updateViews(ViewsSetting.Setting oldSetting, ViewsSetting.Setting newSetting) { AnUtility.checkIfOnAWTThread(true); if (ViewsSetting.viewsChanged(oldSetting, newSetting)) { addVisibleViewsInternal(); } updateSelectedDisplay(); } private void updateViewMode() { viewModeComboBox.setSelectedItem(getSettings().getViewModeSetting().get()); } private void updateViewModeVisibility() { boolean visible = getSettings().getViewModeEnabledSetting().isViewModeEnabled(); updateViewModeVisibility(visible); } private void updateViewModeVisibility(boolean val) { AnUtility.checkIfOnAWTThread(true); viewModeSeparator.setVisible(val); viewModeLabel.setVisible(val); viewModeComboBox.setVisible(val); viewModeFiller.setVisible(val); } /** * @return the filters */ public Filters getFilters() { return filters; } /** * @return the experimentNames */ public String[][] getExperimentGroups() { return experimentGroups; } public boolean isExperimentGroupsSimple() { String[][] groups = getExperimentGroups(); if (groups == null) { return true; } boolean simple = true; for (int i = 0; i < groups.length; i++) { if (groups[i].length > 1) { simple = false; break; } } return simple; } /** * @return whether experiments are loaded */ public boolean experimentsLoaded() { return getExperimentGroups() != null && getExperimentGroups().length > 0; } public boolean hasErrorsAndWarnings() { return hasErrorsAndWarnings; } public AnDispTab getWelcomeDispTab() { if (welcomeDispTab == null) { welcomeDispTab = new AnDispTab(AnDisplay.DSP_Welcome, "welcome", null, null); } return welcomeDispTab; } public AnDispTab getOverviewDispTab() { if (overviewDispTab == null) { overviewDispTab = new AnDispTab(AnDisplay.DSP_Overview, "overview", null, null); } return overviewDispTab; } public ViewsPanel getViewsPanel() { return getNavigationPanel().getViewsPanel(); } public ViewDisplayPanel getViews() { return viewDisplayPanel; } public NavigationPanel getNavigationPanel() { return navigationPanel; } public StatusPanel getStatusPanel() { return statusPanel; } public Analyzer getAnalyzer() { return analyzer; } public IPC IPC() { return analyzer.IPC_session; } public StatusLabelValueHandle getFilterStatusHandle() { return filterStatusHandle; } private void updateCompareModeStatus() { if (compareStatusHandle != null && getSettings() != null) { if (getSettings().getCompareModeSetting().comparingExperiments()) { compareStatusHandle.update(AnLocale.getString("on"), StatusLabelValueHandle.Mode.SET); } else { compareStatusHandle.update(AnLocale.getString("off"), StatusLabelValueHandle.Mode.DEFAULT); } } } public ToolBarPanel getToolBarPanel() { return toolBarPanel; } public void updateWorkingDirectoryStatus() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { String wd = analyzer.getWorkingDirectory(); int i = wd.lastIndexOf("/"); if (i > 0) { wd = "..." + wd.substring(i); } workingDirectoryStatusHandle.updateToolTip( AnLocale.getString("Current working directory: ") + analyzer.getWorkingDirectory()); workingDirectoryStatusHandle.update(wd); } }); } public WelcomeView getWelcomeView() { return welcomeView; } public OverviewView getOverviewView() { return overviewView; } private SummaryPanel getSummaryPanel() { return summaryPanel; } public FunctionsView getFunctionsView() { return functionsView; } public CallerCalleesView getCallerCalleesView() { return callerCalleesView; } public CallTreeView getCallTreeView() { return callTreeView; } public FlameView getFlameView() { return flameView; } public SourceDisassemblyView getSourceDisassemblyView() { return sourceDisassemblyView; } public SourceView getSourceView() { return sourceView; } public LinesView getLinesView() { return linesView; } public DisassemblyView getDisassemblyView() { return disassemblyView; } public PCsView getPcsView() { return pcsView; } public TimelineView getTimelineView() { return timelineView; } public ExperimentsView getExperimentsView() { return experimentsView; } public IOView getIOView() { return ioView; } public HeapView getHeapView() { return heapView; } public StatisticsView getStatisticsView() { return statisticsView; } public DataLayoutView getDataLayoutView() { return dataLayoutView; } public DataObjectsView getDataObjectsView() { return dataObjectsView; } public DualSourceView getDualSourceView() { return dualSourceView; } public InstructionFrequencyView getInstructionFrequencyView() { return instructionFrequencyView; } public CalledByCallsSourceView getCalledByCallsSourceView() { return calledByCallsSourceView; } public CalledByCallsDisassemblyView getCalledByCallsDisassemblyView() { return calledByCallsDisassemblyView; } public CalledByCallsFunctionsView getCalledByCallsFunctionsView() { return calledByCallsFunctionsView; } public Settings getSettings() { return settings; } public Experiments getExperimentProperties() { return experimentProperties; } class ViewsMenuListener implements MenuListener { private JMenu viewsMenu; public ViewsMenuListener(JMenu viewsMenu) { this.viewsMenu = viewsMenu; } @Override public void menuCanceled(MenuEvent e) {} @Override public void menuDeselected(MenuEvent e) {} @Override public void menuSelected(MenuEvent e) { if (experimentsLoaded()) { getViewsPanel().createViewsMenu(viewsMenu); } } } class MetricsMenuListener implements MenuListener { private JMenu metricsMenu; public MetricsMenuListener(JMenu metricsMenu) { this.metricsMenu = metricsMenu; } @Override public void menuCanceled(MenuEvent e) {} @Override public void menuDeselected(MenuEvent e) {} @Override public void menuSelected(MenuEvent e) { metricsMenu.removeAll(); if (experimentsLoaded()) { AnWindow.getInstance() .getSettings() .getMetricsSetting() .addMetricMenuSelector(metricsMenu, getViews().getCurrentViewDisplay().getType(), true); metricsMenu.add(new JSeparator(SwingConstants.HORIZONTAL)); for (JComponent component : getSettings().getMetricsSetting().createMetricSettingsSelector()) { metricsMenu.add(component); } } } } public void welcomeViewOnly() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { List<AnDispTab> list = new ArrayList<AnDispTab>(); getViewsPanel().removeAllViews(); AnDispTab welcome = getWelcomeDispTab(); welcome.getTComp().setSelected(true); welcome.getTComp().setAvailable(true); list.add(welcome); getViewsPanel().createView(instance, welcome, View.Type.STATIC_VIEW); boolean[] selected = new boolean[list.size()]; for (int i = 0; i < selected.length; i++) { selected[i] = true; } getSettings().getViewsSetting().init(this, list, selected, welcome.getTCmd()); addVisibleViews(); showHideNavigationAndSubviews(welcome.getTComp()); } }); } private void welcomeAndOverviewViewsOnly() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { List<AnDispTab> list = new ArrayList<AnDispTab>(); getViewsPanel().removeAllViews(); AnDispTab welcome = getWelcomeDispTab(); welcome.getTComp().setAvailable(true); list.add(welcome); getViewsPanel().createView(instance, welcome, View.Type.STATIC_VIEW); AnDispTab overview = getOverviewDispTab(); overview.getTComp().setAvailable(true); overview.getTComp().setSelected(true); list.add(overview); getViewsPanel().createView(instance, overview, View.Type.STATIC_VIEW); boolean[] selected = new boolean[list.size()]; for (int i = 0; i < selected.length; i++) { selected[i] = true; } getSettings().getViewsSetting().init(this, list, selected, overview.getTCmd()); addVisibleViews(); showHideNavigationAndSubviews(overview.getTComp()); } }); } /** Called every time an experimentsDisp is loaded */ private void resetSubviews() { hideAllSubviews(); if (selectedDetailsSubview == null) { createSubviews(); } getTimelineCallStackSubview().setReadyToShow(false); getIoCallStackSubview().setReadyToShow(false); getHeapCallStackSubview().setReadyToShow(false); } /** Called only once */ private void createSubviews() { selectedDetailsSubview = new Subview( "selectedDetailsSubview", AnLocale.getString("Selection Details"), getSummaryPanel(), MainViewPanel.SubviewArea.SUBVIEW_AREA_1); selectedDetailsSubviewTimeLine = new Subview( "selectedDetailsSubviewTimeLine", AnLocale.getString("Selection Details "), getTimelineView().getDetailsInfoTabComp(), MainViewPanel.SubviewArea.SUBVIEW_AREA_1); timelineCallStackSubview = new Subview( "timelineCallStackSubview", getTimelineView().getStackInfoTabName(), getTimelineView().getStackInfoTabComp(), MainViewPanel.SubviewArea.SUBVIEW_AREA_3); ioCallStackSubview = new Subview( "ioCallStackSubview", getIOView().getStackInfoTabName(), getIOView().getStackInfoTabComp(), MainViewPanel.SubviewArea.SUBVIEW_AREA_3); heapCallStackSubview = new Subview( "heapCallStackSubview", getHeapView().getStackInfoTabName(), getHeapView().getStackInfoTabComp(), MainViewPanel.SubviewArea.SUBVIEW_AREA_3); calledByCallsSrcSubview = new Subview( "calledByCallsSrcSubview", AnLocale.getString("Called-by / Calls"), getCalledByCallsSourceView(), MainViewPanel.SubviewArea.SUBVIEW_AREA_2); calledByCallsDisSubview = new Subview( "calledByCallsDisSubview", AnLocale.getString("Called-by / Calls"), getCalledByCallsDisassemblyView(), MainViewPanel.SubviewArea.SUBVIEW_AREA_2); calledByCallsFuncSubview = new Subview( "calledByCallsFuncSubview", AnLocale.getString("Called-by / Calls"), getCalledByCallsFunctionsView(), MainViewPanel.SubviewArea.SUBVIEW_AREA_2); // Add all subviews to list subviewList.clear(); subviewList.add(selectedDetailsSubview); subviewList.add(selectedDetailsSubviewTimeLine); subviewList.add(timelineCallStackSubview); subviewList.add(ioCallStackSubview); subviewList.add(heapCallStackSubview); subviewList.add(calledByCallsSrcSubview); subviewList.add(calledByCallsDisSubview); subviewList.add(calledByCallsFuncSubview); } private void hideAllSubviews() { mainViewPanel.hideAllSubviews(); } public void setSubviewReadyToShow(String subviewName, boolean value) { Subview subview = mainViewPanel.findSubview(subviewName); if (subview != null && subview.isReadyToShow() != value) { subview.setReadyToShow(value); showHideNavigationAndSubviews(getViews().getCurrentViewDisplay()); } } private void showHideNavigationAndSubviews(AnDisplay anDisplay) { // show/hide subviews List<Subview> visibleSubviews = anDisplay.getVisibleSubviews(); if (visibleSubviews != null) { for (Subview subview : subviewList) { if (subview != null) { boolean visible = visibleSubviews.contains(subview); subview.showSubview(visible); } } } // set selected subviews List<Subview> selectedSubviews = anDisplay.getSelectedSubviews(); if (selectedSubviews != null) { for (Subview subview : selectedSubviews) { subview.setSelected(); } } // Toolbar JPanel toolbarPanel = anDisplay.getToolbarPanel(); if (toolbarPanel != null) { getToolBarPanel().setControls(toolbarPanel); } // Show or hide navigation area? getNavigationPanelSplitPane().setHidden(getViewsPanel().onlyWelcomeView()); // Show or hide sub view areas? mainViewPanel.showHideSubviewAreas(); return; } public void showSubview(Subview subview, boolean show) { subview.showSubview(show); mainViewPanel.showHideSubviewAreas(); // check whether to show or hide a subview area } public Subview getSelectedDetailsSubview() { return selectedDetailsSubview; } public Subview getSelectedDetailsSubviewTimeLine() { return selectedDetailsSubviewTimeLine; } public Subview getTimelineCallStackSubview() { return timelineCallStackSubview; } public Subview getIoCallStackSubview() { return ioCallStackSubview; } public Subview getHeapCallStackSubview() { return heapCallStackSubview; } public Subview getCalledByCallsSrcSubview() { return calledByCallsSrcSubview; } public Subview getCalledByCallsDisSubview() { return calledByCallsDisSubview; } public Subview getCalledByCallsFuncSubview() { return calledByCallsFuncSubview; } /** * Called when clicking on a view * * @param cmd */ public void setSelectedView(String cmd) { setSelectedViewInternal(cmd); // direct call allowing to switch views during doCompute. } /** * Called from other views when switching view. View may not be viewing. Can be called from any * thread. * * @param dtype */ public void setSelectedView(int dtype) { ViewsSetting.View view = settings.getViewsSetting().findView(dtype); if (view != null) { final String cmd = view.getAnDispTab().getTCmd(); if (!getSettings().getViewsSetting().isAvailableAndShowing(cmd)) { getSettings().getViewsSetting().toggleTab(cmd, cmd); // Will fire AnChangeEvent } else { // getSettings().getViewsSetting().setPreferredViewName(this, cmd); // Will // fire AnChangeEvent AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { setSelectedViewInternal( cmd); // direct call allowing to switch views during doCompute. } }); } } } private void setSelectedViewInternal(String cmd) { // System.out.println("setSelectedViewInternal " + cmd + " " + viewStackDirection); AnUtility.checkIfOnAWTThread(true); if (getSettings().getViewsSetting().isAvailableAndShowing(cmd)) { boolean viewChanged = viewDisplayPanel.viewComponent(cmd); if (viewChanged) { changeView(); getNavigationPanel().getViewsPanel().setSelectedComponent(cmd); } } } private void addVisibleViews() { AnUtility.checkIfOnAWTThread(true); addVisibleViewsInternal(); updateSelectedDisplay(); } private void addVisibleViewsInternal() { AnUtility.checkIfOnAWTThread(true); getNavigationPanel().getViewsPanel().resetAllViews(); List<AnDispTab> list = getSettings().getViewsSetting().getSelectedViews(); for (AnDispTab anDispTab : list) { getNavigationPanel().getViewsPanel().showView(anDispTab); } getNavigationPanel().getViewsPanel().refresh(); } private void updateSelectedDisplay() { boolean nameChanged = false; String currentViewName = getViews().getCurrentViewName(); String preferredViewName = getSettings().getViewsSetting().getPreferredViewName(); String newPreferredViewName = preferredViewName; if (preferredViewName != null && getSettings().getViewsSetting().isAvailableAndShowing(preferredViewName)) { newPreferredViewName = preferredViewName; nameChanged = true; } else if (currentViewName != null && getSettings().getViewsSetting().isAvailableAndShowing(currentViewName)) { newPreferredViewName = currentViewName; nameChanged = true; } else { ViewsSetting.View dataView = getSettings().getViewsSetting().getFirstDataView(); if (dataView != null) { newPreferredViewName = dataView.getAnDispTab().getTCmd(); nameChanged = true; } } if (nameChanged) { setSelectedViewInternal(newPreferredViewName); } } /** * Enable/disable session actions Called at initMetricListsByMType Called when loading * experiment(s) */ public void enableSessionActions(boolean loadingExperiments, boolean experimentsLoaded) { AnUtility.checkIfOnAWTThread(true); boolean connected = Analyzer.getInstance().isConnected(); // Hide if no experiment and during experiment loading filterStatusHandle.setVisible(!loadingExperiments && experimentsLoaded); // Hide during experiment loading compareStatusHandle.setVisible(!loadingExperiments); workingDirectoryStatusHandle.setVisible(!loadingExperiments); if (debugStatusHandle != null) { debugStatusHandle.setVisible(!loadingExperiments); } // Disable during experiment loading connectAction.setEnabled(!loadingExperiments); remoteHostStatusHandle.setEnabled(!loadingExperiments); // Disable during experiment loading and enabled only if connected profileApplicationAction.setEnabled(!loadingExperiments && connected); profileKernelAction.setEnabled( !loadingExperiments && connected && Analyzer.getInstance().isKernelProfilingEnabled()); profileRunningProcessAction.setEnabled(!loadingExperiments && connected); openExperimentAction.setEnabled(!loadingExperiments && connected); recentExperimentsMenu.setEnabled(!loadingExperiments && connected); compareExperimentsAction.setEnabled(!loadingExperiments && connected); aggregateExperimentsAction.setEnabled(!loadingExperiments && connected); // Disable during experiment loading and enabled only if experiments loaded metricsMenu.setEnabled(!loadingExperiments && experimentsLoaded); settingsAction.setEnabled(!loadingExperiments && experimentsLoaded); viewsSettingsAction.setEnabled(!loadingExperiments && experimentsLoaded); metricsSettingsAction.setEnabled(!loadingExperiments && experimentsLoaded); addRemoveFiltersAction.setEnabled(!loadingExperiments && experimentsLoaded); filtersMenu.setEnabled(!loadingExperiments && experimentsLoaded); libraryVisibilityAction.setEnabled(!loadingExperiments && experimentsLoaded); functionColorsAction.setEnabled(!loadingExperiments && experimentsLoaded); exportSettingsAction.setEnabled(!loadingExperiments && experimentsLoaded); importSettingsAction.setEnabled(!loadingExperiments && experimentsLoaded); exportSettingsAsAction.setEnabled(!loadingExperiments && experimentsLoaded); exportAction.setEnabled(!loadingExperiments && experimentsLoaded); showErrorsWarningsAction.setEnabled( !loadingExperiments && experimentsLoaded && hasErrorsAndWarnings()); showErrorsWarningsSeparator.setVisible( !loadingExperiments && experimentsLoaded && hasErrorsAndWarnings()); showErrorsWarningsMenuItem.setVisible( !loadingExperiments && experimentsLoaded && hasErrorsAndWarnings()); } /** Enable/disable per-view actions Called when switching view */ private void enablePerViewActions(AnDisplay currentDisplay) { getToolBarPanel().getFindTextPanel().setConrolsEnabled(currentDisplay.supportsFindText()); exportAction.setEnabled(currentDisplay instanceof ExportSupport); previousViewAction.setEnabled(getNavigationPanel().getViewsPanel().hasPreviousViewName()); nextViewAction.setEnabled(getNavigationPanel().getViewsPanel().hasNextViewName()); } public JFrame getFrame() { return frame; } public MainViewPanel getMainViewPanel() { return mainViewPanel; } public JPanel getMainPanel() { return mainPanel; } public AnSplitPane getNavigationPanelSplitPane() { return navigationPanelSplitPane; } public View getSelectedView() { return getViewsPanel().getSelectedViewPanel().getView(); } public AnColorChooser getColorChooser() { return colorChooser; } public LibraryVisibilityDialog getLibraryVisibilityDialog() { // Create dialog if it is not created yet if (libraryVisibilityDialog == null) { libraryVisibilityDialog = new LibraryVisibilityDialog(getFrame()); } return libraryVisibilityDialog; } // AnColorChooser calls this //XXXmpview bogus! // FIXUP: REARCH public void setCPUIdleColor(final boolean set, final Color color) { getTimelineView().setCPUIdleColor(set, color); } // Export main view as text private String exportAsText(Integer limit, ExportFormat format, Character delimiter) { String text = getViews().getCurrentViewDisplay().exportAsText(limit, format, delimiter); // Export subviews if format is TEXT if (format == ExportFormat.TEXT) { // text += ... } return text; } /** * GUI testing. Use GUITesting.dumpMainview * * @param maxLines * @return */ public String dumpMainview(int maxLines) { String text = exportAsText(maxLines, ExportFormat.TEXT, null); return text; } /** * GUI testing. Use GUITesting.dumpSubviews * * @return */ public String dumpSubviews() { StringBuilder buf = new StringBuilder(); buf.append(getMainViewPanel().dumpSubviews()); return buf.toString(); } /** * GUI testing. Use GUITesting.dumpViewsVisibility() * * @return */ public String dumpViewsVisibility() { StringBuilder buf = new StringBuilder(); buf.append(getMainViewPanel().dumpMainviewAreaVisibility()); buf.append(getMainViewPanel().dumpSubviewAreasVisibility()); return buf.toString(); } public String[][] getExperimentGroupsIPC() { synchronized (IPC.lock) { String task = "Load experiments..."; IPCContext ipcContext = IPCContext.getCurrentContext(); ipcContext.setTaskName(task); ipcContext.setCancellable(false); final IPC ipc = IPC(); ipc.send("getExperimentsGroups"); String[][] grops = (String[][]) (ipc.recvObject()); return grops; } } private void setTitle() { String experimentsTitle = null; if (getExperimentGroups() == null || getExperimentGroups().length == 0 || getExperimentGroups()[0] == null) { experimentsTitle = null; } else { StringBuilder buf = new StringBuilder(); int got = 0; outer: for (int i = 0; i < getExperimentGroups().length; i++) { for (int j = 0; j < getExperimentGroups()[i].length; j++) { if (getExperimentGroups()[i][j] != null) { if (got >= 1) { buf.append(", ..."); break outer; } buf.append(AnUtility.basename(getExperimentGroups()[i][j])); got++; } } } experimentsTitle = buf.toString(); setTitle(experimentsTitle); } } private void setTitle(String experimentsTitle) { String title = Analyzer.getAnalyzerReleaseName(); if (experimentsTitle != null) { title = experimentsTitle + " - " + title; } getFrame().setTitle(title); } private void saveExperimentSettings(String[][] groups) { // System.out.println("AnWindow:saveExperimentSettings"); if (groups != null && groups.length > 0) { String configPath = UserPref.getAsWhenClosedConfigPath(groups[0][0]); // System.out.println("AnWindow:saveExperimentSettings:configPath: " + configPath); List<UserPref.What> what = new ArrayList<UserPref.What>(); what.add(UserPref.What.VIEWS); what.add(UserPref.What.METRICS); what.add(UserPref.What.TIMELINE); what.add(UserPref.What.SOURCEDISASSEMBLY); what.add(UserPref.What.CALLTREE); what.add(UserPref.What.FORMATS); what.add(UserPref.What.SEARCHPATH); what.add(UserPref.What.PATHMAP); what.add(UserPref.What.FUNCTIONCOLORS); what.add(UserPref.What.LIBRARYVISIBILITY); what.add(UserPref.What.MISC); UserPref.getInstance().save(configPath, what); // Always local! UserPref.getInstance().setLastClosedExpConfPath(configPath); } } private void saveAnalyzerSettings() { List<UserPref.What> what = new ArrayList<UserPref.What>(); what.add(UserPref.What.USER); UserPref.getInstance().save(UserPref.getAnalyzerInitFilePath(), what); } private void restoreExperimentSettings(String confPath) { if (confPath != null) { AnLog.log("Configuration file to be processed: " + confPath); boolean homeDefaultConfiguration = confPath.startsWith(UserPref.getAnalyzerDirPath()); // home default configuration is always on local machine if (Analyzer.getInstance().isRemote() && !homeDefaultConfiguration) { confPath = AnWindow.copyFromRemote(confPath); } if (confPath != null) { UserPref.getInstance().restore(confPath); } } } /** Open and load experiment(s) from chooser */ public void openExperimentAction() { AnChooser ac = getAnChooser(AnLocale.getString("Open Experiment"), AnChooser.EXP_CHOOSER, null); int res = ac.showDialog(frame, null); if (res == AnChooser.APPROVE_OPTION) { String wd = ac.getWorkingDirectory(); String confPath = ac.getConfiguration(); boolean alwaysUseThisConf = ac.alwaysUseThisConfiguration(); List<String> expList = ac.getExperiments(); if (expList != null && expList.size() > 0) { loadExperimentList(expList, false, wd, true, confPath, alwaysUseThisConf); } } } /** * @param experimentList * @param cmpMode * @param workingDirectory * @param restartEngine * @param confPath * @param alwaysUseThisConf */ public void loadExperimentList( final List<String> experimentList, final boolean cmpMode, String workingDirectory, boolean restartEngine, String confPath, boolean alwaysUseThisConf) { String[][] arr; if (cmpMode) { arr = new String[experimentList.size()][]; for (int i = 0; i < experimentList.size(); i++) { String[] expName = new String[1]; expName[0] = experimentList.get(i); arr[i] = expName; } } else if (experimentList.size() > 0) { String[] expName = new String[experimentList.size()]; for (int i = 0; i < experimentList.size(); i++) { expName[i] = experimentList.get(i); } arr = new String[1][]; arr[0] = expName; } else { arr = new String[0][]; } loadExperimentGroups(arr, workingDirectory, restartEngine, confPath, alwaysUseThisConf); } /** * @param grops * @param workingDirectory * @param restartEngine * @param confPath * @param alwaysUseThisConf */ public void loadExperimentGroups( final String[][] grops, final String workingDirectory, final boolean restartEngine, final String confPath, final boolean alwaysUseThisConf) { AnUtility.checkIfOnAWTThread(true); AnUtility.dispatchOnAWorkerThread( () -> { synchronized (AnVariable.mainFlowLock) { loadExperimentGroupsInternal( grops, workingDirectory, restartEngine, confPath, alwaysUseThisConf); } }, "Set Experiments Thread"); } private void loadExperimentGroupsInternal( final String[][] groups, final String workingDirectory, final boolean restartEngine, final String confPath, final boolean alwaysUseThisConf) { // AnUtility.checkIfOnAWTThread(false); final boolean restart = experimentsLoaded() ? true : restartEngine; final boolean anyExperiments = groups.length > 0; final UserPref userPref = UserPref.getInstance(); AnUtility.dispatchOnSwingThread( () -> { showErrorsWarningsStatusHandle.setVisible(false); enableSessionActions(true, false); // Close all (non-modal) dialogs getSettings().showDialog(false); colorChooser.setVisible(false); saveExperimentSettings(getExperimentGroups()); if (restart) { AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(groups, AnChangeEvent.Type.EXPERIMENTS_LOADING_NEW)); userPref.resetExperimentPreferences(); } else { AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent( groups, AnChangeEvent.Type.EXPERIMENTS_LOADING_ADDED_OR_REMOVED)); } }); hasErrorsAndWarnings = false; IPCContext.newCurrentContext( AnLocale.getString("Loading experiment(s)..."), IPCContext.Scope.SESSION, false, AnWindow.this); Object progressBarHandle = getSystemProgressPanel().progressBarStart(AnLocale.getString("Loading Experiment(s)")); resetAllViews(); if (restart) { // <=== FIXUP: check // re-exec gp-display-text Analyzer.getInstance() .restartEngine(); // Note: do this early so it has a chance to start! FIXUP: need a way to // find out when it has starte } // getSettings().getMetricsSetting().initMetricListsByMType(); // AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { memoryIndexDisplayList = new ArrayList<AnDisplay>(); getFilters().resetAllFiltersAction(); setTitle(null); if (anyExperiments) { welcomeAndOverviewViewsOnly(); } else { welcomeViewOnly(); } getSettings().getViewModeEnabledSetting().init(false); updateViewModeVisibility(); resetSubviews(); } }); try { final String msg; restoreExperimentSettings(confPath); // Writes into UserPref if (anyExperiments) { try { if (workingDirectory != null) { synchronized (IPC.lock) { analyzer.setWorkingDirectory(workingDirectory); // IPC } } } catch (Exception e) { } } // Set search path and pathmap efter restart but before loading if (groups.length > 0 && !GUITesting.getInstance().isRunningUnderGUITesting()) { // Accept search path and pathmaps from .gprofng.rc if first time experiment is being loaded String experiment = groups[0][0]; String asClosedPath = UserPref.getAsWhenClosedConfigPath(experiment); if (!new File(asClosedPath).exists()) { String[][] pathMaps = PathMapSetting.getPathMapsIPC(); String[] searchPath = SearchPathSetting.getSearchPathIPC(); UserPref.getInstance().setPathmap(pathMaps); UserPref.getInstance().setSearchPath(Arrays.asList(searchPath)); } } if (groups.length > 0) { getSettings().getSearchPathSetting().init(this, UserPref.getInstance().getSearchPath()); getSettings().getPathMapSetting().init(this, UserPref.getInstance().getPathmap()); } synchronized (IPC.lock) { IPC().send("setExperimentsGroups"); IPC().send(groups); msg = (String) (IPC().recvString()); } if (msg == null) { // Experiment(s) did load but may have non-fatal errors or warnings getSettings() .getFormatSetting() .init( this, FormatSetting.Style.fromValue(userPref.getFormatsStyle()), userPref.getFormatsAppendSoName()); IPCResult compareModeIPC = CompareModeSetting.getCompareModeV2IPCRequest(); // ASYNC IPC IPCResult machineModelIPC = ViewsSetting.getMachineModelIPCRequest(); // ASYNC IPC // Capture Experiment Data Descriptors and Properties experimentProperties.ipcUpdateExps(); CompareMode compareMode = CompareMode.fromValue(compareModeIPC.getInt()); getSettings().getCompareModeSetting().init(this, compareMode); IPCResult viewModeEnabledIPC = ViewModeEnabledSetting.getViewModeEnabledIPCRequest(); // ASYNC IPC IPCResult tlEntpropsIPC = TimelineSetting.ipcGetEntityPropsRequest(); // ASYNC IPC final boolean viewModeEnabled = viewModeEnabledIPC.getBoolean(); final Object[] tlEntprops = tlEntpropsIPC.getObjects(); // Metrics getSettings().getMetricsSetting().initMetricListsByMType(); Object[] ref_data = MetricsSetting.getRefMetricsV2(); IPCMetricsAPI.getJavaEnableIPC(); MetricNode metricsRootNode = IPCMetricsAPI.getAllAvailableMetricsIPC(0); getSettings() .getMetricsSetting() .init( this, userPref.getMetricSelectionList(), ref_data, metricsRootNode, userPref.getMetricReversedSort(), userPref.getMetricSortByMTypeList(), userPref.getMetricOrderLists()); // Views. Load machine model and custom index/memmory objects before // asking for available views final String machineModel; final String loadedMachineModel = machineModelIPC.getString(); String savedMachineModel = userPref.getMachineModel(); if (savedMachineModel != null && !savedMachineModel.equals(loadedMachineModel)) { machineModel = savedMachineModel; ViewsSetting.loadMachineModelIPC(machineModel); // SYNC IPC } else { machineModel = loadedMachineModel; } final String[] availableMachineModels = ViewsSetting.listMachineModelsIPC(); final List<CustomObject> customIndexObjects = userPref.getCustomIndexObjects(); if (customIndexObjects != null) { for (CustomObject customObject : customIndexObjects) { ViewsSetting.defineIndxObjIPC( customObject.getName(), customObject.getFormula(), customObject.getShortDesc(), customObject.getLongDesc()); } } final List<CustomObject> customMemoryObjects = userPref.getCustomMemoryObjects(); if (customMemoryObjects != null) { for (CustomObject customObject : customMemoryObjects) { ViewsSetting.defineMemObjIPC( customObject.getName(), customObject.getFormula(), customObject.getShortDesc(), customObject.getLongDesc()); } } // Use "async" IPC calls to minimize the "high latency" effect IPCResult standardViewsIPC = ViewsSetting.getTabListInfoIPCRequest(); // ASYNC IPC IPCResult standardViewsSelectedIPC = ViewsSetting.getTabSelectionStateIPCRequest(); // ASYNC IPC IPCResult indexViewsIPC = ViewsSetting.getIndxObjDescriptionsIPCRequest(); // ASYNC IPC IPCResult indexViewsSelectedIPC = ViewsSetting.getIndxTabSelectionStateIPCRequest(); // ASYNC IPC IPCResult memoryViewsIPC = ViewsSetting.getMemObjectsIPCRequest(); // ASYNC IPC IPCResult memoryViewsSelectedIPC = ViewsSetting.getMemTabSelectionStateIPCRequest(); // ASYNC IPC IPCResult libraryVisibilityIPC = LibraryVisibilitySetting.getLoadObjectListIPCRequest(0); // ASYNC IPC // Get the results from those "async" IPC calls final Object[] standardViews = standardViewsIPC.getObjects(); final boolean[] standardViewsSelected = standardViewsSelectedIPC.getBooleans(); final Object[] indexViews = indexViewsIPC.getObjects(); final boolean[] indexViewsSelected = indexViewsSelectedIPC.getBooleans(); final Object[] memoryViews = memoryViewsIPC.getObjects(); final boolean[] memoryViewsSelected = memoryViewsSelectedIPC.getBooleans(); getColorChooser().getColorMap().initRules(userPref.getActiveColorRules(), false); Object[] libraryVisibility = libraryVisibilityIPC.getObjects(); getSettings() .getLibraryVisibilitySetting() .init(this, libraryVisibility, userPref.getLibraryVisibilitySettings()); final String[] errors = getExperimentErrorsIPC(); final String[] warnings = getExperimentWarningsIPC(); // ------------------- IPC END AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { if (errors != null || warnings != null) { hasErrorsAndWarnings = true; handleErrorsAndWarnings(errors, warnings); } getExperimentsView().initErrorsAndWarnings(errors, warnings); // Set settings (GUI updates) // Note: change events are not fired until experiments finished loading getLibraryVisibilityDialog() .initStates( userPref.getLibraryVisibilityJava(), userPref.getLibraryVisibilitySettings(), userPref.getLibraryVisibilityIncludePickList(), userPref.getLibraryVisibilityIncludeFilter(), userPref.getLibraryVisibilityExcludePickList(), userPref.getCurrenLibraryVisibilityExcludeFilter()); // getSettings().getViewModeSetting().init(this, // ViewModeSetting.ViewMode.fromValue(viewModeValue)); // getSettings().getFormatSetting().init(this, // FormatSetting.Style.fromValue(nameFormat), soName); getSettings().getViewModeEnabledSetting().init(this, viewModeEnabled); // getSettings().getSourceDisassemblySetting().init(this, // srcDisSettings); getSettings() .getTimelineSetting() .init( this, tlEntprops, userPref.getTimelineTLDataCmd(), userPref.getTimelineGroupDataByButtonName(), userPref.getTimelineStackAlign(), userPref.getTimelineStackDepth(), userPref.getTimelineStackFramePixels(), userPref.getTimelineShowEventStates(), userPref.getTimelineShowEventDensity()); getSettings() .getViewsSetting() .init( this, userPref.getViewPanelOrder(), groups, standardViews, standardViewsSelected, indexViews, indexViewsSelected, memoryViews, memoryViewsSelected, availableMachineModels, machineModel, customIndexObjects, customMemoryObjects); if (restart) { getToolBarPanel() .getFindTextPanel() .initializeFindTexts(userPref.getFindPickList(), null); // Find text getSettings() .getCallTreeSetting() .setThreshold(this, userPref.getCallStackThreshold()); // Call Tree properties getSettings() .getViewModeSetting() .set( null, ViewModeSetting.ViewMode.fromValue( userPref.getFormatsViewMode())); // View Mode property getSettings() .getFormatSetting() .set( this, FormatSetting.Style.fromValue(userPref.getFormatsStyle()), userPref.getFormatsAppendSoName()); getSettings() .getSourceDisassemblySetting() .set(null, userPref.getSourceDisassemblySettings()); // View Mode property } if (comparingExperiments(groups)) { if (userPref.getFormatsCompareMode() != userPref.getFormatsCompareModeDefault()) { getSettings() .getCompareModeSetting() .set(this, CompareMode.fromValue(userPref.getFormatsCompareMode())); } } getSettings() .getTableSettings() .initWrapMetricNames(userPref.wrapMetricNamesInTables()); experimentGroups = groups; setTitle(); updatePickList(groups, workingDirectory, confPath, alwaysUseThisConf); // enableSessionActions(false, anyExperiments); AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(groups, AnChangeEvent.Type.EXPERIMENTS_LOADED)); } }); } else { AnUtility.dispatchOnSwingThread( () -> { AnEventManager.getInstance() .fireAnChangeEvent( new AnChangeEvent(groups, AnChangeEvent.Type.EXPERIMENTS_LOADED_FAILED)); // Error(s) handleFatalError(msg); if (anyExperiments) { String exp = groups[0][0]; userPref.getExperimentsPicklists().getPicklist().removeExperiment(exp); } welcomeViewOnly(); enableSessionActions(false, false); }); } } catch (IPCCancelledException ex) { System.out.println("\nloadExperiments cancelled..."); welcomeViewOnly(); } getSystemProgressPanel().progressBarStop(progressBarHandle); IPCContext.newCurrentContext(null, IPCContext.Scope.SESSION, false, AnWindow.this); } private boolean comparingExperiments(String[][] groups) { return groups != null && groups.length > 1 && groups[1] != null && groups[1].length > 0; } private void updatePickList( String[][] groups, String workingDirectory, String confPath, boolean alwaysUseThisConf) { List<PickListElement> list = new ArrayList<PickListElement>(); for (String[] group : groups) { for (String experiment : group) { experiment = AnUtility.toFullPath(experiment); list.add( new ExperimentPickListElement( experiment, workingDirectory, alwaysUseThisConf ? confPath : null)); } } UserPref.getInstance().getExperimentsPicklists().getPicklist().addElements(list); } private void handleFatalError(String msg) { JTextArea textArea = new JTextArea(); textArea.setText(AnLocale.getString("Experiment(s) failed to load.\n\n")); textArea.append(msg); textArea.setCaretPosition(0); textArea.setEditable(false); textArea.setOpaque(false); textArea.setWrapStyleWord(true); textArea.setLineWrap(true); textArea.setOpaque(true); textArea.setBackground(AnEnvironment.DEFAULT_DIALOG_BACKGROUND); JScrollPane scrollPane = new JScrollPane(textArea); scrollPane.setBorder(BorderFactory.createLineBorder(AnEnvironment.SCROLLBAR_BORDER_COLOR)); scrollPane.setPreferredSize(new Dimension(700, 160)); JPanel panel = new JPanel(new BorderLayout()); panel.add(scrollPane, BorderLayout.CENTER); JOptionPane pane = new JOptionPane(panel, JOptionPane.ERROR_MESSAGE); JDialog dialog = pane.createDialog(frame, AnLocale.getString("Error")); dialog.setResizable(true); dialog.setVisible(true); } /** * Handle non-fatal errors and warnings * * @param errors * @param warnings */ private void handleErrorsAndWarnings(String[] errors, String[] warnings) { showErrorsWarningsStatusHandle.setVisible(false); String labelText = null; ImageIcon labelIcon = null; if (errors != null && warnings != null) { labelIcon = AnUtility.errorWarningNewIcon; labelText = AnLocale.getString("Errors & Warnings"); } else if (errors != null) { labelIcon = AnUtility.errorNewIcon; labelText = AnLocale.getString("Errors"); } else if (warnings != null) { labelIcon = AnUtility.warningNewIcon; labelText = AnLocale.getString("Warnings"); } showErrorsWarningsStatusHandle.update(labelText); showErrorsWarningsStatusHandle.update(labelIcon); showErrorsWarningsStatusHandle.setVisible(true); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { showErrorsWarningsTooltipPopup(); } }); } private void showErrorsWarningsTooltipPopup() { JPanel panel = new JPanel(); panel.setOpaque(false); panel.setLayout(new GridBagLayout()); int gridx = 0; GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; JLabel label0 = new JLabel(); label0.setText(AnLocale.getString("Experiment has errors or wanings:")); label0.setForeground(AnEnvironment.TOOLTIP_POPUP_FOREGROUND_COLOR); label0.setFont(label0.getFont().deriveFont(Font.BOLD)); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 0, 0, 0); panel.add(label0, gridBagConstraints); JLabel label1 = new JLabel(); label1.setFont(label1.getFont().deriveFont(Font.BOLD)); label1.setText(AnLocale.getString("Click flag for details...")); label1.setForeground(AnEnvironment.FILTER_FOREGROUND_COLOR); gridBagConstraints.gridx = gridx++; gridBagConstraints.insets = new Insets(0, 4, 0, 0); panel.add(label1, gridBagConstraints); ToolTipPopup toolTipPopup = new ToolTipPopup( showErrorsWarningsStatusHandle.getTextLabel(), panel, ToolTipPopup.Location.NORTHEAST, true); toolTipPopup.show(750, 5000); } /** Drops all experimentsDisp */ private void dropAllExperiments() { if (experimentsLoaded()) { AnUtility.checkIPCOnWrongThread(false); loadExperimentGroupsInternal(new String[0][0], null, false, null, false); AnUtility.checkIPCOnWrongThread(true); } } /** Reset Collect Dialogs */ public synchronized void resetProfileDialogs() { profileApplicationDialog = null; profileRunningProcessDialog = null; profileKernelDialog = null; } // ********************************************************************************* public AnAction getProfileApplicationAction() { return profileApplicationAction; } public AnAction getProfileRunningProcessAction() { return profileRunningProcessAction; } public AnAction getProfileKernelAction() { return profileKernelAction; } public AnAction getOpenExperimentAction() { return openExperimentAction; } public AnAction getCompareExperimentsAction() { return compareExperimentsAction; } public AnAction getAggregateExperimentsAction() { return aggregateExperimentsAction; } public AnAction getShowErrorsWarningsAction() { return showErrorsWarningsAction; } public AnAction getConnectAction() { return connectAction; } public AnAction getExportAction() { return exportAction; } public AnAction getExitAction() { return exitAction; } public AnAction getPreviousViewAction() { return previousViewAction; } public AnAction getNextViewAction() { return nextViewAction; } public AnAction getViewsSettingsAction() { return viewsSettingsAction; } public AnAction getMetricsSettingsAction() { return metricsSettingsAction; } public AnAction getAddRemoveFiltersAction() { return addRemoveFiltersAction; } public AnAction getLibraryVisibilityAction() { return libraryVisibilityAction; } public AnAction getFunctionColorsAction() { return functionColorsAction; } public AnAction getSettingsAction() { return settingsAction; } public AnAction getExportSettingsAction() { return exportSettingsAction; } public AnAction getImportSettingsAction() { return importSettingsAction; } public AnAction getExportSettingsAsAction() { return exportSettingsAsAction; } public AnAction getHelpAnalyzerAction() { return helpAnalyzerAction; } public AnAction getHelpNewFeaturesAction() { return helpNewFeaturesAction; } public AnAction getHelpInformationMapAction() { return helpInformationMapAction; } public AnAction getHelpKeyboardShortcutsAction() { return helpKeyboardShortcutsAction; } public AnAction getHelpShortcutsAction() { return helpShortcutsAction; } public AnAction getHelpTroubleShootingAction() { return helpTroubleShootingAction; } public AnAction getAboutAnalyzerAction() { return aboutAnalyzerAction; } // ********************************************************************************* public void profileApplicationAction(String[] arguments) { if (profileApplicationAction.isEnabled()) { if (null == profileApplicationDialog) { profileApplicationDialog = new CollectDialog(this, getFrame(), Collector.PROFILE_APPLICATION, CollectPanel.title); } profileApplicationDialog.doDialog(arguments); } } public void profileRunningProcessAction() { if (profileRunningProcessAction.isEnabled()) { if (null == profileRunningProcessDialog) { profileRunningProcessDialog = new CollectDialog( this, getFrame(), Collector.PROFILE_RUNNING_APPLICATION, CollectPanel.title1); } profileRunningProcessDialog.doDialog(); } } public void profileKernelAction() { if (profileKernelAction.isEnabled()) { if (null == profileKernelDialog) { profileKernelDialog = new CollectDialog(this, getFrame(), Collector.SYSTEM_PROFILING, CollectPanel.title2); } profileKernelDialog.doDialog(); } } public void showErrorsWarningsAction() { if (showErrorsWarningsAction.isEnabled()) { String experimentsViewName = "header"; getNavigationPanel().getViewsPanel().selectView(experimentsViewName); } } public void aggregateExperimentsAction() { if (aggregateExperimentsAction.isEnabled()) { String title = AnLocale.getString("Aggregate Experiments"); CompareAdvancedDialog dlg = new CompareAdvancedDialog(this, getFrame(), false, title); dlg.setVisible(true, 0); } } public void compareExperimentsAction() { if (compareExperimentsAction.isEnabled()) { // if (GUITesting.getInstance().isRunningUnderGUITesting()) { // compareExperimentsAdvancedDialog(); // return; // } if (isExperimentGroupsSimple()) { CompareSimpleDialog compareSimpleDialog = new CompareSimpleDialog(getFrame()); compareSimpleDialog.setVisible(true); } else { compareExperimentsAdvancedDialog(); } } } public void compareExperimentsAdvancedDialog() { String title = AnLocale.getString("Compare Experiments"); CompareAdvancedDialog dlg = new CompareAdvancedDialog(this, getFrame(), true, title); dlg.setVisible(true, 0); } public void connectAction() { if (connectAction.isEnabled()) { // Check if there are loaded experimentsDisp if (experimentsLoaded()) { CloseExperimentDialog closeExperientDialog = new CloseExperimentDialog(getFrame()); closeExperientDialog.setVisible(true); if (closeExperientDialog.getStatus() == AnDialog2.Status.OK) { try { dropAllExperiments(); } catch (Exception e) { // We can get an exception if IPC is not connected } } else { return; } } Object progressBarHandle = getSystemProgressPanel().progressBarStart(AnLocale.getString("Connecting")); if (null == connectionChooser) { connectionChooser = new ConnectionDialog(this, frame, remoteHostStatusHandle); } getSystemProgressPanel().progressBarStop(progressBarHandle); connectionChooser.setVisible(true, 0); // Requesting connectionChooser focus here may not work because unloading experiments // may be running in the background and steel the focus. Also requesting focus when // experiments have done unloading (AnChangeEvent.EXPERIMENTS_LOADED). connectionChooser.requestFocus(); } } public void exportAction() { if (exportAction.isEnabled()) { if (!(getViews().getCurrentViewDisplay() instanceof ExportSupport)) { return; } ExportSupport exportSupport = (ExportSupport) getViews().getCurrentViewDisplay(); // List<ExportFormat> formats = exportSupport.getSupportedExportFormats(); ExportDialog exportDialog = new ExportDialog(frame, exportSupport); exportDialog.setVisible(true); if (exportDialog.getStatus() == ExportDialog.Status.OK) { ExportSupport.ExportFormat format = exportDialog.getExportFormat(); if (format == ExportFormat.JPG) { boolean includeSubvies = exportDialog.getIncludeSubviews(); String outputFilePath = exportDialog.getOutputFilePath(); Component component; if (includeSubvies) { component = getMainViewPanel(); } else { component = getViews().getCurrentViewDisplay(); } Export.exportImage(component, outputFilePath); } else { Integer limit = exportDialog.getLimit(); Character delimiter = exportDialog.getDelimiter(); String text = exportAsText(limit, format, delimiter); String outputFilePath = exportDialog.getOutputFilePath(); Export.exportText(text, outputFilePath); } } } } public void exitAction() { AnUtility.checkIfOnAWTThread(true); frame.setVisible(false); /* Everything below should be done on a worker thread */ AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { saveExperimentSettings(getExperimentGroups()); if (!GUITesting.getInstance().isRunningUnderGUITesting()) { saveAnalyzerSettings(); } UserPref.getInstance().cleanupAsWhenClosedFolder(); analyzer.IPC_session.destroyIPCProc(); if (null != analyzer.old_IPC_session) { analyzer.old_IPC_session.destroyIPCProc(); } System.exit(0); } }, "Exit Thread"); } public void previousViewAction() { if (previousViewAction.isEnabled()) { String previousViewName = getNavigationPanel().getViewsPanel().previousViewName(); if (previousViewName != null) { // setSelectedViewInternal(previousViewName, -1); getNavigationPanel().getViewsPanel().moveViewStackPointer(-1); getNavigationPanel().getViewsPanel().selectView(previousViewName); } } } public void nextViewAction() { if (nextViewAction.isEnabled()) { String nextViewName = getNavigationPanel().getViewsPanel().nextViewName(); if (nextViewName != null) { // setSelectedViewInternal(nextViewName, 1); getNavigationPanel().getViewsPanel().moveViewStackPointer(+1); getNavigationPanel().getViewsPanel().selectView(nextViewName); } } } public void viewsSettingsAction() { if (viewsSettingsAction.isEnabled()) { if (experimentsLoaded()) { getSettings().showDialog(getSettings().settingsviewsIndex); } } } public void metricsSettingsAction() { if (metricsSettingsAction.isEnabled()) { if (experimentsLoaded()) { getSettings().showDialog(getSettings().settingsMetricsIndex); } } } public void addRemoveFiltersAction(Object source) { if (addRemoveFiltersAction.isEnabled()) { Component parent = null; if (source != null && (source instanceof Component)) { parent = (Component) source; } getViews().getCurrentViewDisplay().showFilterPopup(parent); } } public void libraryVisibilityAction() { if (libraryVisibilityAction.isEnabled()) { if (libraryVisibilityDialog == null) { libraryVisibilityDialog = new LibraryVisibilityDialog(getFrame()); } libraryVisibilityDialog.setVisible(true); } } public void functionColorsAction() { if (functionColorsAction.isEnabled()) { colorChooser.setVisible(true); } } public void settingsAction() { if (settingsAction.isEnabled()) { int index = -1; if (getViews().getCurrentViewDisplay().getType() == AnDisplay.DSP_Timeline) { index = getSettings().settingsTimelineIndex; } else if (getViews().getCurrentViewDisplay().getType() == AnDisplay.DSP_CallTree) { index = getSettings().settingsCalltreeIndex; } else if (getViews().getCurrentViewDisplay().getType() == AnDisplay.DSP_Source || getViews().getCurrentViewDisplay().getType() == AnDisplay.DSP_Disassembly || getViews().getCurrentViewDisplay().getType() == AnDisplay.DSP_SourceDisassembly) { index = getSettings().settingsSourceDisassemblyIndex; } else if (getViews().getCurrentViewDisplay().getType() == AnDisplay.DSP_Overview) { index = getSettings().settingsMetricsIndex; } getSettings().showDialog(index); } } public void exportSettingsAction() { if (exportSettingsAction.isEnabled()) { new ExportSettingsDialog(frame).setVisible(true); } } public void importSettingsAction() { if (importSettingsAction.isEnabled()) { new ImportSettingsDialog(frame).setVisible(true); } } public void exportSettingsAsAction() { if (exportSettingsAsAction.isEnabled()) { getSettings().saveAsDotErRc(); } } public void helpAnalyzerAction() { if (helpAnalyzerAction.isEnabled()) { Analyzer.showHelp(AnVariable.HELP_WelcomeAnalyzer); } } public void helpNewFeaturesAction() { if (helpNewFeaturesAction.isEnabled()) { Analyzer.showHelp(AnVariable.HELP_NewFeatures); } } public void helpInformationMapAction() { if (helpInformationMapAction.isEnabled()) { Analyzer.showHelp(AnVariable.HELP_InformationMap); } } public void helpKeyboardShortcutsAction() { if (helpKeyboardShortcutsAction.isEnabled()) { Analyzer.showHelp(AnVariable.HELP_KeyboardShortcuts); } } public void helpShortcutsAction() { if (helpShortcutsAction.isEnabled()) { Analyzer.showHelp(AnVariable.HELP_HelpShortcuts); } } public void helpTroubleShootingAction() { if (helpTroubleShootingAction.isEnabled()) { Analyzer.showHelp(AnVariable.HELP_Troubleshooting); } } public void aboutAnalyzerAction() { if (aboutAnalyzerAction.isEnabled()) { AboutPanel.showDialog(); } } // ********************************************************************************* /** * Get AnFile with correct AnFileSystemView for remote case * * @param path * @return AnFile */ public AnFile getAnFile(final String path) { if (path == null) { return null; } AnFile afile = new AnFile(path); if (analyzer.remoteConnection != null) { AnFileSystemView afsv = AnFileSystemView.getFileSystemView(); afsv.setAnWindow(this); afsv.updateFileAttributes(afile); } else { File f = new File(path); if (!f.exists()) { afile.existsFlag = false; } if (!f.isDirectory()) { afile.isDirectoryFlag = false; } } return afile; } /** * Gets current remote AnChooser * * @return anRemoteFileChooser */ public AnChooser getAnChooserRemote() { return anRemoteFileChooser; } /** * return files in remote directory * * @param remoteDirectoryPath * @return */ public File[] getFiles(String remoteDirectoryPath) { AnFileSystemView afsv = AnFileSystemView.getFileSystemView(); File[] ret = afsv.getFiles(new File(remoteDirectoryPath), false); return ret; } /** * Get AnChooser with correct AnFileSystemView for remote case * * @param title * @param chooser_type * @param st_dir * @return AnChooser */ public AnChooser getAnChooser(final String title, final int chooser_type, String st_dir) { AnFileSystemView afsv = null; String host = null; if (analyzer.remoteConnection != null) { if (st_dir == null) { st_dir = getCurrentRemoteDirectory(); if (st_dir == null) { st_dir = analyzer.getWorkingDirectory(); if (st_dir == null) { st_dir = "/"; } } } host = AnLocale.getString("Remote host: ") + analyzer.remoteHost; afsv = AnFileSystemView.getFileSystemView(); afsv.setAnWindow(this); AnFile dir = new AnFile(st_dir); // NM incomplete initMetricListsByMType anRemoteFileChooser = new AnChooser(frame, chooser_type, this, title, dir, host, afsv); anRemoteFileChooser.setFileHidingEnabled(true); afsv.setAnChooser(anRemoteFileChooser); return anRemoteFileChooser; } else { if (st_dir == null) { st_dir = Analyzer.getInstance().getWorkingDirectory(); String cd = null; if (null != anFileChooser) { if (null != anFileChooser.getCurrentDirectory()) { cd = anFileChooser.getCurrentDirectory().getPath(); if (null != cd) { st_dir = cd; } } } } afsv = null; if (null != analyzer.localHost) { host = AnLocale.getString("Host: ") + analyzer.localHost; } anFileChooser = new AnChooser(frame, chooser_type, this, title, st_dir, host, afsv); anFileChooser.setFileHidingEnabled(true); return anFileChooser; } } /** * Gets Current Remote Directory * * @return */ public String getCurrentRemoteDirectory() { String cd = null; if (null != anRemoteFileChooser) { if (null != anRemoteFileChooser.getCurrentDirectory()) { cd = anRemoteFileChooser.getCurrentDirectory().getPath(); } } return cd; } private void unSelectAllViews() { for (AnDisplay anDisplay : standardDisplayList) { anDisplay.setSelected(false); } if (memoryIndexDisplayList != null) { for (AnDisplay anDisplay : memoryIndexDisplayList) { anDisplay.setSelected(false); } } } private void resetAllViews() { for (AnDisplay anDisplay : standardDisplayList) { anDisplay.setSelected(false); anDisplay.setAvailable(false); } if (memoryIndexDisplayList != null) { for (AnDisplay anDisplay : memoryIndexDisplayList) { anDisplay.setSelected(false); anDisplay.setAvailable(false); } } } private void changeView() { // System.out.println("AnWindow:changeView"); tableStatusHandle.setVisible(false); AnUtility.checkIfOnAWTThread(true); // AnMemoryManager.getInstance().checkMemoryUsage(); getToolBarPanel().removeControls(); unSelectAllViews(); final AnDisplay sel = getViews().getCurrentViewDisplay(); if (sel == null) { return; } showHideNavigationAndSubviews(sel); sel.setSelected(true); sel.computeOnAWorkerThread( null, new AbstractAction() { // ?????? FIXUP Don't do Swing stuff on worker thread!!!! @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().getViews().getCurrentViewDisplay().requestFocus(); enablePerViewActions(sel); // AnMemoryManager.getInstance().checkMemoryUsage(); // AnMain.showImportOldSettingsDialog(); // Do this after request view // focus.... } }); // Set table status visible for most table views if (sel instanceof FuncListDisp && sel.getType() != AnDisplay.DSP_Callers) { tableStatusHandle.setVisible(true); } } public class AnDispTab { private final int type; private final int subtype; private String tname; private char tmnem; private final String cmd; private AnDisplay tcomp; private String shortDescr; private String longDescr; public AnDispTab(int dtype, String cmdstr, String shortDescr, String longDescr) { // System.out.println("AnWindow.AnDispTab standard: " + cmdstr + " " + shortDescr + // " " + longDescr); type = dtype; cmd = cmdstr; subtype = 0; // Only relevant for memobj this.shortDescr = shortDescr; this.longDescr = longDescr; initDispTab(); } // fixme, Code should move to mem/index classes public AnDispTab( int dtype, int sub, String sname, char mnem, String cmdstr, String shortDesc, String longDesc) { // System.out.println("AnWindow.AnDispTab index/memory: " + dtype + " " + sub + " " // + sname + " " + cmdstr); type = dtype; cmd = cmdstr; tname = sname; tmnem = mnem; subtype = sub; this.shortDescr = shortDesc; this.longDescr = longDesc; String HELP_token_ID = null; if (type == AnDisplay.DSP_MemoryObject) { HELP_token_ID = AnVariable.HELP_TabsMemObj; } else if (type == AnDisplay.DSP_IndexObject) { switch (cmd) { case "Threads": HELP_token_ID = AnVariable.HELP_TabsThreads; break; case "CPUs": HELP_token_ID = AnVariable.HELP_TabsCPUs; break; case "Samples": HELP_token_ID = AnVariable.HELP_TabsSamples; break; case "GCEvents": HELP_token_ID = null; // AnVariable.HELP_TabsIndxObj; break; case "Seconds": HELP_token_ID = AnVariable.HELP_TabsSeconds; break; case "Processes": HELP_token_ID = AnVariable.HELP_TabsProcesses; break; case "Experiment_IDs": HELP_token_ID = AnVariable.HELP_TabsExperimentIDs; break; case "Datasize": HELP_token_ID = AnVariable.HELP_DataSize; break; case "Duration": HELP_token_ID = AnVariable.HELP_Duration; break; case "OMP_preg": HELP_token_ID = AnVariable.HELP_TabsOMPParallelRegions; break; case "OMP_task": HELP_token_ID = AnVariable.HELP_TabsOpenMPTasks; break; default: HELP_token_ID = null; // AnVariable.HELP_TabsIndxObj; break; } } // System.out.println("HELP_token_ID:" + HELP_token_ID); MemoryIndexObjectView memoryIndexAnDisplay = new MemoryIndexObjectView(dtype, subtype, HELP_token_ID); memoryIndexDisplayList.add(memoryIndexAnDisplay); tcomp = memoryIndexAnDisplay; tcomp.setAnDispTab(this); tcomp.setAvailable(true); } private void initDispTab() { switch (type) { case AnDisplay.DSP_Welcome: tname = AnLocale.getString("Welcome"); tmnem = AnLocale.getString('W', "MNEM_TAB_WELCOME"); tcomp = getWelcomeView(); shortDescr = getWelcomeView().getShortDescr(); longDescr = getWelcomeView().getLongDescr(); break; case AnDisplay.DSP_Overview: tname = AnLocale.getString("Overview"); tmnem = AnLocale.getString('i', "MNEM_TAB_OVERVIEW"); tcomp = getOverviewView(); shortDescr = getOverviewView().getShortDescr(); longDescr = getOverviewView().getLongDescr(); break; case AnDisplay.DSP_Functions: tname = AnLocale.getString("Functions"); tmnem = AnLocale.getString('F', "MNEM_TAB_FUNCTION"); tcomp = getFunctionsView(); break; case AnDisplay.DSP_Callers: tname = AnLocale.getString("Callers-Callees"); tmnem = AnLocale.getString('e', "MNEM_TAB_CALL"); tcomp = getCallerCalleesView(); break; case AnDisplay.DSP_CallTree: tname = AnLocale.getString("Call Tree"); tmnem = AnLocale.getString('t', "MNEM_TAB_CALLTREE"); tcomp = getCallTreeView(); break; case AnDisplay.DSP_CallFlame: // tname = AnLocale.getString("Visual Call Tree"); // tmnem = AnLocale.getString('v', "MNEM_TAB_FLAME"); tname = AnLocale.getString("Flame Graph"); tmnem = AnLocale.getString('m', "MNEM_TAB_FLAME"); tcomp = getFlameView(); break; case AnDisplay.DSP_Source: case AnDisplay.DSP_SourceV2: tname = AnLocale.getString("Source"); tmnem = AnLocale.getString('r', "MNEM_TAB_SOURCE"); tcomp = getSourceView(); break; case AnDisplay.DSP_Lines: tname = AnLocale.getString("Lines"); tmnem = AnLocale.getString('L', "MNEM_TAB_LINES"); tcomp = getLinesView(); break; case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_DisassemblyV2: tname = AnLocale.getString("Disassembly"); tmnem = AnLocale.getString('D', "MNEM_TAB_DISASM"); tcomp = getDisassemblyView(); break; case AnDisplay.DSP_PCs: tname = AnLocale.getString("PCs"); tmnem = AnLocale.getString('P', "MNEM_TAB_PCS"); tcomp = getPcsView(); break; case AnDisplay.DSP_DataLayout: tname = AnLocale.getString("DataLayout"); tmnem = AnLocale.getString('u', "MNEM_TAB_DATALAY"); tcomp = getDataLayoutView(); break; case AnDisplay.DSP_DataObjects: tname = AnLocale.getString("DataObjects"); tmnem = AnLocale.getString('O', "MNEM_TAB_DATAOBJ"); tcomp = getDataObjectsView(); break; case AnDisplay.DSP_Timeline: tname = AnLocale.getString("Timeline"); tmnem = AnLocale.getString('T', "MNEM_TAB_TIMELINE_V2"); tcomp = getTimelineView(); // YXXX what is purpose of above linesDisp? break; // case AnDisplay.DSP_LEAKLIST: // tname = AnLocale.getString("Leaks"); // tmnem = AnLocale.getString('k', "MNEM_TAB_LEAKLIST"); // tcomp = getLeaksView(); // break; case AnDisplay.DSP_Heap: tname = AnLocale.getString("Heap"); tmnem = AnLocale.getString('H', "MNEM_TAB_HEAPCALLSTACK"); tcomp = getHeapView(); break; case AnDisplay.DSP_IO: tname = AnLocale.getString("I/O"); tmnem = AnLocale.getString('A', "MNEM_TAB_IOACTIVITY"); tcomp = getIOView(); break; case AnDisplay.DSP_Statistics: tname = AnLocale.getString("Statistics"); tmnem = AnLocale.getString('i', "MNEM_TAB_STATIS"); tcomp = getStatisticsView(); break; case AnDisplay.DSP_Experiments: tname = AnLocale.getString("Experiments"); tmnem = AnLocale.getString('n', "MNEM_TAB_EXPERIMENT"); tcomp = getExperimentsView(); break; case AnDisplay.DSP_InstructionFrequency: tname = AnLocale.getString("Instruction Frequency"); tmnem = AnLocale.getString('q', "MNEM_TAB_IFREQ"); tcomp = getInstructionFrequencyView(); break; case AnDisplay.DSP_DualSource: tname = AnLocale.getString("Dual Source"); tmnem = AnLocale.getString('R', "MNEM_TAB_DUALSOURCES"); tcomp = getDualSourceView(); break; case AnDisplay.DSP_SourceDisassembly: tname = AnLocale.getString("Source/Disassembly"); tmnem = AnLocale.getString('u', "MNEM_TAB_SOURCE_DISASM"); tcomp = getSourceDisassemblyView(); break; default: System.err.println("Anwindow: unknown view: " + type); tname = "Unknown"; // tmnem = AnLocale.getString('W', "MNEM_TAB_WELCOME"); tcomp = getWelcomeView(); break; } tcomp.setAnDispTab(this); tcomp.setAvailable(true); } public int getTType() { return type; } public String getTName() { return tname; } public char getTMnem() { return tmnem; } public AnDisplay getTComp() { return tcomp; } public String getTCmd() { return cmd; } public String getShortDescr() { return shortDescr; } public String getLongDesc() { return longDescr; } } public void showError(final String msg) { if (msg != null) { getExperimentsView().appendLog(AnLocale.getString("Error: ") + msg); AnUtility.showMessage(frame, msg, JOptionPane.ERROR_MESSAGE); } } public void showWarning(final String msg) { if (msg != null) { getExperimentsView().appendLog(AnLocale.getString("Warning: ") + msg); // AnUtility.showMessage(frame, msg, JOptionPane.WARNING_MESSAGE); } } public void showProcessorWarning(final String msg) { if (msg != null) { getExperimentsView().appendLog(msg); AnUtility.showMessage(frame, msg, JOptionPane.WARNING_MESSAGE); } } /** * Copy file from local host to remote host * * @param from * @param to * @return res (number of bytes, or -1 - error) */ public int cp(File from, AnFile to) { int res = 0; String contents = ""; // Read file from local host try { final java.io.FileReader fr = new java.io.FileReader(from); java.io.BufferedReader br = new java.io.BufferedReader(fr); String s = br.readLine(); while (null != s) { s += "\n"; // Line feed is not passed by readLine() res += s.length(); contents += s; s = br.readLine(); } } catch (java.io.IOException ex) { return -1; // Error: cannot read file } // Write file to remote host String dir = to.getDirectoryName(); createDirectories(dir); String sto = to.getAbsolutePath(); // res = writeFile(sto, " "); // Hack to work-around problem with remote doesn't always // create a new file when written to the first time res = writeFile(sto, contents); // System.out.println("Remote: " + dir + " " + to + " " + res); return res; } public static String copyFromRemote(String remotePath) { AnFile anFile = new AnFile(remotePath); String toFilePath = null; if (anFile.exists()) { File tempFile = tempFile(); if (tempFile != null) { AnWindow.getInstance().cp(anFile, tempFile); toFilePath = tempFile.getAbsolutePath(); } } return toFilePath; } public static File tempFile() { File tempFile = null; try { tempFile = File.createTempFile("configuration", ".tmp"); tempFile.deleteOnExit(); } catch (IOException ioe) { System.err.println(ioe); } return tempFile; } public static int copyToRemote(String fromPath, String toRemotePath) { String dirs = AnUtility.dirname(toRemotePath); new AnFile(dirs).mkdir(); File fromFile = new File(fromPath); AnFile anFile = new AnFile(toRemotePath); int res = 0; if (fromFile.exists()) { res = AnWindow.getInstance().cp(fromFile, anFile); } return res; } /** * Copy file from remote host to local host * * @param from * @param to * @return res (number of bytes, or -1 - error) */ public int cp(AnFile from, File to) { // Read file from remote host String[] in = readFile(from.getAbsolutePath()); String contents = in[0]; // Write file to local host if (contents != null) { try { final java.io.FileWriter fw = new java.io.FileWriter(to); java.io.BufferedWriter bw = new java.io.BufferedWriter(fw); bw.write(contents, 0, contents.length()); bw.flush(); bw.close(); fw.close(); return contents.length(); } catch (java.io.IOException ex) { return -1; // Error: cannot write file } } return -1; } // ========================================================================// // Native methods from liber_dbe.so public void initView(final int win_id, final int clone_id) { synchronized (IPC.lock) { IPC().send("initView"); IPC().send(win_id); IPC().send(clone_id); IPC().recvString(); // synchronize } } /** * A method to create directory. * * @param path - full path * @return String - error */ public String createDirectories(final String path) { synchronized (IPC.lock) { IPC().send("dbeCreateDirectories"); IPC().send(path); return IPC().recvString(); } } /** * A method to delete file or directory. * * @param path - full path * @return String - error */ public String deleteFile(final String path) { synchronized (IPC.lock) { IPC().send("dbeDeleteFile"); IPC().send(path); return IPC().recvString(); } } /** * Read File If the operation was successful, the contents is in the first element, and second * element is NULL. If the operation failed, then first element is NULL, and second element * contains the error message. * * @param file_name * @return String[] result */ public final String[] readFile(final String file_name) { synchronized (IPC.lock) { IPC().send("dbeReadFile"); IPC().send(file_name); return (String[]) IPC().recvObject(); } } /** * Write File * * @param file_name * @param contents * @return result (written bytes) */ public final int writeFile(final String file_name, final String contents) { synchronized (IPC.lock) { IPC().send("dbeWriteFile"); IPC().send(file_name); IPC().send(contents); return IPC().recvInt(); } } public final String getHomeDir() { synchronized (IPC.lock) { IPC().send("getHomeDirectory"); return IPC().recvString(); } } // Native methods from liber_dbe.so public String[] getExpPreview(final String exp_name) { synchronized (IPC.lock) { IPC().send("getExpPreview"); IPC().send(exp_name); return (String[]) IPC().recvObject(); } } private int[] getUserExpId(final int[] expIds) { synchronized (IPC.lock) { IPC().send("getUserExpId"); IPC().send(expIds); return (int[]) IPC().recvObject(); } } public String[] getExpName() { synchronized (IPC.lock) { IPC().send("getExpName"); return (String[]) IPC().recvObject(); } } private int[] getExpState() { synchronized (IPC.lock) { IPC().send("getExpState"); return (int[]) IPC().recvObject(); } } public boolean[] getExpEnable() { synchronized (IPC.lock) { IPC().send("getExpEnable"); IPC().send(0); return (boolean[]) IPC().recvObject(); } } public String[] getExpInfo() { synchronized (IPC.lock) { IPC().send("getExpInfo"); IPC().send(0); return (String[]) IPC().recvObject(); } } protected String composeFilterClause( final int type, final int subtype, final int[] selected_ids) { synchronized (IPC.lock) { IPC().send("composeFilterClause"); IPC().send(0); IPC().send(type); IPC().send(subtype); IPC().send(selected_ids); return IPC().recvString(); } } public String getMsg(final int type) { synchronized (IPC.lock) { IPC().send("getMsg"); IPC().send(0); IPC().send(type); return IPC().recvString(); } } // Get experimentsDisp list with icons public AnTextIcon[] getExperimentList() { final String[] names; final int[] state; final AnTextIcon[] exp_list; final int size; ImageIcon ex_icon; names = getExpName(); // IPC state = getExpState(); // IPC if (names == null) { return null; } int expIds[] = new int[names.length]; for (int i = 0; i < expIds.length; i++) { expIds[i] = i; } int userExpIds[] = getUserExpId(expIds); // IPC int maxUserExpId = 0; for (int id : userExpIds) { if (id > maxUserExpId) { maxUserExpId = id; } } // Get icons for experimentsDisp size = names.length; exp_list = new AnTextIcon[size]; for (int i = 0; i < size; i++) { if (state[i] == EXP_SUCCESS) { ex_icon = AnUtility.expt_icon; } else if ((state[i] & EXP_OBSOLETE) != 0) { ex_icon = AnUtility.eold_icon; } else if ((state[i] & EXP_BROKEN) != 0) { ex_icon = AnUtility.ebad_icon; } else { ex_icon = AnUtility.ewarn_icon; } String padding = ""; if (maxUserExpId >= 10 && userExpIds[i] < 10) { padding = " "; } exp_list[i] = new AnTextIcon(padding + userExpIds[i] + " " + names[i], ex_icon); } return exp_list; } public SelectedObject getSelectedObject() { return selectedObject; } public SelectionManager getSelectionManager() { return selectionManager; } public String[] getStackNames(final long stack) { synchronized (IPC.lock) { IPC().send("getStackNames"); IPC().send(0); IPC().send(stack); return (String[]) IPC().recvObject(); } } // Histable::Function* public long[] getStackFunctions(final long stack) { synchronized (IPC.lock) { IPC().send("getStackFunctions"); IPC().send(stack); return (long[]) IPC().recvObject(); } } // Histable::Function* public Object[] getStacksFunctions(final long stacks[]) { synchronized (IPC.lock) { IPC().send("getStacksFunctions"); IPC().send(stacks); return (Object[]) IPC().recvObject(); } } // Histable::DbeInstr* public long[] getStackPCs(final long stack) { synchronized (IPC.lock) { IPC().send("getStackPCs"); IPC().send(stack); return (long[]) IPC().recvObject(); } } public String getFuncName(final long func) { synchronized (IPC.lock) { IPC().send("getFuncName"); IPC().send(0); IPC().send(func); return IPC().recvString(); } } public String[] getFuncNames(final long[] funcs) { synchronized (IPC.lock) { IPC().send("getFuncNames"); IPC().send(0); IPC().send(funcs); return (String[]) IPC().recvObject(); } } public long[] getFuncIds(final long[] funcs) { synchronized (IPC.lock) { AnUtility.checkIPCOnWrongThread(false); IPC().send("getFuncIds"); IPC().send(0); IPC().send(funcs); long[] ll = (long[]) IPC().recvObject(); AnUtility.checkIPCOnWrongThread(true); return ll; } } public String getFilterStr() { synchronized (IPC.lock) { IPC().send("getFilterStr"); IPC().send(0); return IPC().recvString(); } } /** * A generic method to get data for Analyzer tabs. * * @param mlistStr metric list: "MET_NORMAL", "MET_CALL", "MET_CALL_AGR", ... * @param modeStr mode: "ALL", "CALLERS", "CALLEES", "SELF" * @param typeStr type: "FUNCTION", "INDEXOBJ" * @param subtypeStr string of subtype for index objects, e.q. "0", "1", ... * @param cstack array of function IDs (can be null if modeStr="ALL") * @return */ public Object[] getTableDataV2( final String mlistStr, final String modeStr, final String typeStr, final String subtypeStr, final long[] cstack) { synchronized (IPC.lock) { IPC().send("getTableDataV2"); IPC().send(0); IPC().send(mlistStr); IPC().send(modeStr); IPC().send(typeStr); IPC().send(subtypeStr); IPC().send(cstack); return (Object[]) IPC().recvObject(); } } public String getObjNameV2(final long id) { synchronized (IPC.lock) { IPC().send("getObjNameV2"); IPC().send(0); IPC().send(id); return IPC().recvString(); } } public String[] getObjNamesV2(final long[] ids) { synchronized (IPC.lock) { IPC().send("getObjNamesV2"); IPC().send(0); IPC().send(ids); return (String[]) IPC().recvObject(); } } public int[] getGroupIds() { synchronized (IPC.lock) { final IPC ipc = IPC(); ipc.send("getGroupIds"); ipc.send(0); return (int[]) ipc.recvObject(); } } private String[] getExperimentWarningsIPC() { String s = ""; IPC().send("getExpsProperty"); // IPC IPC().send("WARNINGS"); // IPC String[] msgs = (String[]) IPC().recvObject(); return msgs; } private String[] getExperimentErrorsIPC() { String s = ""; IPC().send("getExpsProperty"); // IPC IPC().send("ERRORS"); // IPC String[] msgs = (String[]) IPC().recvObject(); return msgs; } /** * Check Remote Connection * * @param s * @return s */ public String checkConnection(final String s) { synchronized (IPC.lock) { IPC().send("checkConnection"); IPC().send(s); return IPC().recvString(); } } } ���������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnListener.java����������������������������������������������������0000644�0001750�0001750�00000001452�14517772113�016646� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import java.util.EventListener; public interface AnListener extends EventListener { void valueChanged(AnEvent e); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/CalledByCallsFunctionsView.java������������������������������������0000644�0001750�0001750�00000001774�14517772113�021773� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; public final class CalledByCallsFunctionsView extends CalledByCallsDisp { public CalledByCallsFunctionsView() { super( AnWindow.getInstance(), AnDisplay.DSP_Callers, AnVariable.HELP_TabsFunctions, AnDisplay.DSP_Functions); setAccessibility(AnLocale.getString("Called By Calls")); } } ����gprofng-gui-1.0/org/gprofng/mpmt/timeline2/���������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�015722� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TL2DataFetcher.java��������������������������������������0000644�0001750�0001750�00000051750�14517772113�021174� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCContext; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCListener; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.timeline.events.DetailsIPC; import org.gprofng.mpmt.timeline2.data.GenericEvent; import org.gprofng.mpmt.timeline2.data.SampleEvent; import org.gprofng.mpmt.timeline2.data.StackEvent; import org.gprofng.mpmt.util.gui.AnUtility; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Queue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; // Fetches requested rows (RowDataRequestParams) from gp-display-text and places // row data in TL2DataSnapshot. Data fetch is asynchronous to the awt thread. public final class TL2DataFetcher { // passed in on contstruction public final AnWindow anWindow; // for IPC //YXXX make private private final TimelineView timelineView; // for doRepaint() // storage for timeline data private boolean needsFetchAllStackStates; private final HashMap<Long, long[]> stack_htable; // unique stacks; key=stack_id, value=array of function IDs private final HashSet<Long> stacks_pending; // unique stacks; key=stack_id private final BlockingQueue<Boolean> stackFetcherQ; // use the following lock with members below private final Object dataRequestLock; private RowDataRequestParams dataRequestOnDeck; // on deck private RowDataRequestParams dataRequestHead; // in progress // use the following lock with members below private final Object snapshotLock; private TL2DataSnapshot tl2DataSnapshot; // info for all rows private final ArrayList<TL2DataFetchListener> fetchTLRowDataListeners; private final IPCContext ipcContext; public TL2DataFetcher(TimelineView tl2Disp, final AnWindow awindow) { this.anWindow = awindow; this.timelineView = tl2Disp; needsFetchAllStackStates = true; stack_htable = new HashMap(1024); stacks_pending = new HashSet(); stackFetcherQ = new LinkedBlockingQueue<>(); dataRequestLock = new Object(); dataRequestOnDeck = null; dataRequestHead = null; snapshotLock = new Object(); tl2DataSnapshot = null; fetchTLRowDataListeners = new ArrayList(); ipcContext = IPCContext.newDBEIPCContext( "TL2DataFetcher", IPCContext.Scope.SESSION, false, false /* true*/, IPCContext.Request.GROUP, anWindow); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { try { while (true) { stackFetcherQ.take(); if (needsFetchAllStackStates) { int numAdded = anWindow.getColorChooser().getColorMap().updateFullColorMapIPC(); needsFetchAllStackStates = false; } ipcAddStackIds(); } } catch (InterruptedException ex) { int ii = 1; } } }, "TL2StackFetcherThread"); } // ---- called from non-awt threads public void resetAll() { /* start over including colors, selection */ synchronized (stack_htable) { stack_htable.clear(); stacks_pending.clear(); } needsFetchAllStackStates = true; anWindow .getColorChooser() .getColorMap() .reset(); // YXXX should instead be called from AnWindow or something? resetSnapshot(); } public void resetSnapshot() { /* clear screen but keep selection, colors */ setTL2DataSnapshot(null); enqueueRequest(null); } public void setTL2DataSnapshot(TL2DataSnapshot snapshot) { boolean updated = false; synchronized (snapshotLock) { if (tl2DataSnapshot != snapshot) { updated = true; tl2DataSnapshot = snapshot; // YXXX cancel old IPC when that becomes possible } } if (updated) { notifyNewDataSnapshot(); } } public TL2DataSnapshot getTL2DataSnapshot() { synchronized (snapshotLock) { return tl2DataSnapshot; } } // ---- listeners public interface TL2DataFetchListener { public void not_edt_newDataSnapshot(); } public void addTL2DataFetchListener(TL2DataFetchListener listener) { fetchTLRowDataListeners.add(listener); // assumes single threaded init } private void notifyNewDataSnapshot() { for (TL2DataFetchListener listener : fetchTLRowDataListeners) { listener.not_edt_newDataSnapshot(); } } // ---- request queue (2 deep. If full, previous on-deck request discarded) private int enqueueRequest(RowDataRequestParams newReq) { final int newSize; synchronized (dataRequestLock) { if (dataRequestHead == null) { dataRequestHead = newReq; newSize = 1; } else { // replace any old request with new request (intentionally lossy) dataRequestOnDeck = newReq; dataRequestHead.cancel(); // aborts loop in fetchTLRows() newSize = 2; } } return newSize; } private RowDataRequestParams nextRequest() { synchronized (dataRequestLock) { dataRequestHead = dataRequestOnDeck; dataRequestOnDeck = null; return dataRequestHead; } } private RowDataRequestParams headRequest() { synchronized (dataRequestLock) { return dataRequestHead; } } // ---- called from AWT thread: public boolean edt_fetchTLRowDataInitiate(final RowDataRequestParams newReq) { if (newReq.snapshot == null) { return false; // probably waiting for experiment to load } synchronized (snapshotLock) { if (newReq.snapshot != tl2DataSnapshot) { return false; // request is out of date. } } int newSize = enqueueRequest(newReq); if (newSize > 1) { return true; // request is not first in queue, loop below will get to it eventually } AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { RowDataRequestParams currReq = headRequest(); while (currReq != null) { not_edt_fetchTLRows(currReq); currReq = nextRequest(); } } }, "TL2DataFetcherThread"); return true; } private boolean subsetOf(RowDataRequestParams master, RowDataRequestParams request) { if (master == null || request == null) { return false; } if (master.binTime == request.binTime && master.alignedTimeStart <= request.required_timeStart && master.timeEnd >= request.required_timeEnd && master.snapshot == request.snapshot) { return true; } return false; } private void invalidateRowData(TL2DataSnapshot tl2DataSnapshot) { List<RowData> rowDataArray = tl2DataSnapshot.getRowData(); for (RowData rowData : rowDataArray) { rowData.invalidateEventData(); // YXXX cancel old IPC? } } private void invalidateRowsWithChanges(RowDataRequestParams request) { // Causes row.getEvents() and row.getChartData() // to return null until data is refreshed. List<RowData> rowDataArray = request.snapshot.getRowData(); int nRows = rowDataArray.size(); // rowDataArray defines "all rows" at full zoom out for (int i = request.rowStart; i <= request.rowEnd; i++) { if (i >= nRows) { break; // weird } RowData row = rowDataArray.get(i); RowDataRequestParams oldParams = row.getParams(); // params mutated by not_edt_fetchTLRows() if (request.forceLoad || !subsetOf(oldParams, request)) { row.invalidateEventData(); } } } private synchronized void not_edt_fetchTLRows(final RowDataRequestParams request) { // note: above "synchronized" not needed if calls never overlap { if (request.snapshot != getTL2DataSnapshot()) { // request is no longer valid // ...change in [exp add/drop, filters, grouping, mode] invalidateRowData(request.snapshot); // YXXX do we need to free old IPC Context here? THOMAS? return; } invalidateRowsWithChanges(request); // doesn't need to be sync'd // start fetching new data. List<RowData> rowDataArray = request.snapshot.getRowData(); List<RowData> fetchRows = new ArrayList(); // add required rows for (int i = request.required_rowStart; i <= request.required_rowEnd; i++) { RowData row = rowDataArray.get(i); fetchRows.add(row); } // add prefetch rows, starting with those nearest required rows int lo = request.required_rowStart - 1; int hi = request.required_rowEnd + 1; while (lo >= request.rowStart || hi <= request.rowEnd) { if (lo >= request.rowStart) { RowData row = rowDataArray.get(lo); fetchRows.add(row); } if (hi <= request.rowEnd) { RowData row = rowDataArray.get(hi); fetchRows.add(row); } hi++; lo--; } Queue<IPCResult> ipcResultQ = new LinkedList<>(); Queue<RowData> rowQ = new LinkedList<>(); for (RowData row : fetchRows) { if (request.isCancelled()) { // fetchTLRowDataInitiate() called, new TLDataSnapshot not required (e.g. for pan, zoom) // ipcContext.cancel(); // YXXX IPC is not complete here. Should // probably cancel ipcContext? // THOMAS FIXME break; } if (row.eventDataIsValid()) { // old data is fine; skip fetch continue; } IPCResult ipcResult = ipcStart_getTLData(ipcContext, null, row, request); // non-blocking ipc start ipcResultQ.add(ipcResult); rowQ.add(row); if (ipcResultQ.size() > 5) { // because cancel isn't implemented right, need to cap this process_fetchTLRows(request, rowQ, ipcResultQ); } } // last rows process_fetchTLRows(request, rowQ, ipcResultQ); } } private void process_fetchTLRows( final RowDataRequestParams request, Queue<RowData> rows, Queue<IPCResult> ipcResults) { while (ipcResults.size() > 0) { IPCResult savedIpcResult = ipcResults.remove(); RowData savedRow = rows.remove(); Object[] data = (Object[]) savedIpcResult.getObject(); if (request.isCancelled()) { continue; } if (data != null) { ipcFinish_getTLData(data, savedRow, request); } } } // ---- from MetaExperiment.java public long[] getStackFuncArray(final long stackId) { // YXXX slow long[] stackFuncs; Long stackIdL = stackId; synchronized (stack_htable) { stackFuncs = stack_htable.get(stackIdL); } if (stackFuncs == null) { stackFuncs = new long[0]; // System.err.println("XXXmpview Experiment.java::getStackFuncArray("+stackId+") returning // null"); } return stackFuncs; } public void ipcSetStackFuncArray(final long stackId) { // IPC!! long stackIds[] = new long[1]; stackIds[0] = stackId; detectNewStackIds(stackIds); } // ---IPC--- (Native methods from liber_dbe.so) private IPCResult ipcStart_getTLData( final IPCContext ipcContext, final IPCListener ipcListener, final RowData rowData, final RowDataRequestParams request) { final RowDefinition rowDef = rowData.rowDefinition; long current_time_adjust = rowDef.getTimeOrigin(); long startt = request.alignedTimeStart + current_time_adjust; IPCResult ipcResult = ipcStart_getTLData( ipcContext, ipcListener, rowDef.getExpID(), rowDef.getDataDescriptor().getDataId(), rowDef.getEntity().getPropId(), rowDef.getEntity().getPropValue(), rowDef.getAux(), startt, request.binTime, request.nbins, true, rowDef.getChartPropNames()); return ipcResult; } private void ipcFinish_getTLData( Object data[], final RowData rowData, // IPC!! final RowDataRequestParams request) { Object representatives[] = (Object[]) data[0]; final GenericEvent[] events; if (representatives == null) { events = null; } else { // each of the following is the same length: int startbins[] = (int[]) representatives[0]; int eventbins[] = (int[]) representatives[1]; long event_ids[] = (long[]) representatives[2]; // DataView indexes long stack_ids[] = (long[]) representatives[3]; int mstate[] = (int[]) representatives[4]; long sampleVals[][] = (long[][]) representatives[5]; long timeStart[] = (long[]) representatives[6]; long timeEnd[] = (long[]) representatives[7]; long timeAdjust = rowData.rowDefinition.getTimeOrigin(); if (rowData.getRowDef().getTLDataType().equals(Settings.TLData_type.TL_GCEVENT)) { // CXXX Bug 20801848 - maybe create GCEvent instead of GenericEvent events = new GenericEvent[event_ids.length]; for (int k = 0; k < event_ids.length; k++) { events[k] = new GenericEvent( event_ids[k], startbins[k], eventbins[k], timeStart[k] - timeAdjust, timeEnd[k] - timeAdjust); } } else if (sampleVals != null) { // if (tltype == Presentation.TLData_type.TL_SAMPLE }) { events = new SampleEvent[event_ids.length]; for (int k = 0; k < event_ids.length; k++) { events[k] = new SampleEvent( event_ids[k], startbins[k], eventbins[k], timeStart[k] - timeAdjust, timeEnd[k] - timeAdjust, sampleVals[k]); } } else { events = new StackEvent[event_ids.length]; for (int k = 0; k < event_ids.length; k++) { final long stack_id; if (stack_ids == null) { stack_id = DetailsIPC.INVALID_STACK_ID; } else { stack_id = stack_ids[k]; } events[k] = new StackEvent( event_ids[k], startbins[k], eventbins[k], timeStart[k] - timeAdjust, timeEnd[k] - timeAdjust, stack_id, mstate != null ? mstate[k] : -1); } } detectNewStackIds(stack_ids); } final Object chartPropVals[] = (Object[]) data[1]; if (chartPropVals != null) { for (int propNum = 0; propNum < chartPropVals.length; propNum++) { Object thisProp = chartPropVals[propNum]; if (thisProp == null) { continue; } if (thisProp instanceof long[][]) { // thisProp represents multiple states; convert to Events long perBinStates[][] = (long[][]) thisProp; // sparsely populated; determine how many actual samples int nSamples = 0; for (Object binData : perBinStates) { if (binData != null) { nSamples++; } } SampleEvent sampleEvents[] = new SampleEvent[nSamples]; int sampleIdx = 0; // for now, charts binTimeStart/binTimeEnd not used; use request duration final long binTimeStart = 0; final long binTimeEnd = request.binTime - 1; for (int bin = 0; bin < perBinStates.length; bin++) { long stateVals[] = (long[]) perBinStates[bin]; if (stateVals == null) { continue; } sampleEvents[sampleIdx++] = new SampleEvent(-1, bin, 1, binTimeStart, binTimeEnd, stateVals); } chartPropVals[propNum] = sampleEvents; // replace w/ Events } } } { // IPC: if needed, code from here down could be done in separate thread rowData.setEventData(request, events, chartPropVals); timelineView.repaintTLDrawer(); } } public void detectNewStackIds(long stack_ids[]) { if (stack_ids == null || stack_ids.length == 0) { return; } boolean missing = false; synchronized (stack_htable) { for (long stack_id : stack_ids) { if (!stack_htable.containsKey(stack_id)) { stacks_pending.add(stack_id); missing = true; } } } if (missing) { try { stackFetcherQ.put(true); } catch (InterruptedException ex) { int ii = 1; } // send wakeup } } private void ipcAddStackIds() { // IPC!! final int sz; final long newStackIdsArray[]; synchronized (stack_htable) { if (stacks_pending == null || stacks_pending.isEmpty()) { return; } sz = stacks_pending.size(); newStackIdsArray = new long[sz]; int ii = 0; for (Long stackId : stacks_pending) { newStackIdsArray[ii++] = stackId.longValue(); } } Object[] stacks = anWindow.getStacksFunctions(newStackIdsArray); // IPC!! HashSet<Long> newFunctions = new HashSet(); synchronized (stack_htable) { for (int ii = 0; ii < sz; ii++) { long stack_id = newStackIdsArray[ii]; long[] stack = (long[]) stacks[ii]; long[] old = stack_htable.put(stack_id, stack); if (old == null) { // new stack detected boolean changed = stacks_pending.remove(stack_id); if (!changed) { int iii = 1; // weird } // store unique functions for (long function : stack) { newFunctions.add(new Long(function)); } } } if (stacks_pending.size() > 0) { int ii = 1; // for breakpoint. could happen } } anWindow.getColorChooser().getColorMap().addFunctionsIPC(newFunctions); timelineView.repaintTLDrawer(); } private IPCResult ipcStart_getTLData( IPCContext ipcContext, IPCListener ipcListener, int exp_id, int data_id, int entity_prop_id, int entity_prop_val, int hwctag, long start_ts, long delta, int ndelta, boolean getRepresentatives, final String[] chartProperties) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE, ipcContext); { ipcHandle.append("getTLData"); ipcHandle.append(0); ipcHandle.append(exp_id); ipcHandle.append(data_id); ipcHandle.append(entity_prop_id); ipcHandle.append(entity_prop_val); ipcHandle.append(hwctag); ipcHandle.append(start_ts); ipcHandle.append(delta); ipcHandle.append(ndelta); ipcHandle.append(getRepresentatives); ipcHandle.append(chartProperties); } if (ipcListener != null) { ipcHandle.addIPCListener(ipcListener); } IPCResult ipcResult = ipcHandle.sendRequest(); return ipcResult; } public IPCResult ipcStart_getTLEventCenterTime( IPCContext ipcContext, IPCListener ipcListener, int exp_id, int data_id, int entity_prop_id, int entity_prop_val, int hwctag, long event_idx, long move_count) { if (ipcContext == null) { ipcContext = this.ipcContext; } IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE, ipcContext); { ipcHandle.append("getTLEventCenterTime"); ipcHandle.append(0); ipcHandle.append(exp_id); ipcHandle.append(data_id); ipcHandle.append(entity_prop_id); ipcHandle.append(entity_prop_val); ipcHandle.append(hwctag); ipcHandle.append(event_idx); ipcHandle.append(move_count); } if (ipcListener != null) { ipcHandle.addIPCListener(ipcListener); } IPCResult ipcResult = ipcHandle.sendRequest(); return ipcResult; } public long ipcGetTLEventIdxNearTime( int exp_id, int data_id, int entity_prop_id, int entity_prop_val, int hwctag, int searchDirection, long ts) { synchronized (IPC.lock) { anWindow.IPC().send("getTLEventIdxNearTime"); anWindow.IPC().send(0); anWindow.IPC().send(exp_id); anWindow.IPC().send(data_id); anWindow.IPC().send(entity_prop_id); anWindow.IPC().send(entity_prop_val); anWindow.IPC().send(hwctag); anWindow.IPC().send(searchDirection); anWindow.IPC().send(ts); return anWindow.IPC().recvLong(); } } } ������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TL2Drawer.java�������������������������������������������0000644�0001750�0001750�00000117211�14517772113�020241� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.timeline.events.*; import org.gprofng.mpmt.timeline2.TL2DataSnapshot.*; import org.gprofng.mpmt.timeline2.cursorevent.*; import org.gprofng.mpmt.timeline_common.*; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.ruler.valuetypes.ValuesLong; import java.awt.Graphics; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import java.util.Vector; import java.util.concurrent.LinkedBlockingQueue; import javax.swing.SwingUtilities; // This class' public methods MUST only be accessed from AWT event thread public final class TL2Drawer implements TimelineDrawer { // params private TimelinePanel timelinePanel; private final TL2DataFetcher tl2DataFetcher; // image data private final CoordCalcTimeMaster timeAxisMaster; private final CoordCalcTimeReader timeAxisReader; private final CoordCalcDataMaster dataAxisMaster; private final CoordCalcDataReader dataAxisReader; public TimelineDraw event_drawer; // listeners private ArrayList<TimelineSelectionListener> selection_listeners; // cursor location (most recent location of user focus) private RowGeometry cursor_rowGeometry = null; private RowGeometry cursor_rowGeometry_alt = null; // cursor movement event queue private final LinkedBlockingQueue<CursorEvent> cursorEventQ; // Use queue because up/down/left/right need IPC private final Object cursorEventQLock = new Object(); // used for syncing peek/take combos // selection of row blocks (entities/samples for use in filters) private TreeSet<Integer> selected_row_blocks; // indices for selected_row_blocks_info private List<EntityDefinitions> selected_entity_info; private int selected_row_blocks_anchor = -1; // for shift-click multiselect // zoom private long old_time_range = 0; // components // private RangeRuler verticalRuler; private IconRuler verticalRuler; // fetching private long data_time_start; private long data_bin_time; private int data_time_nbins; private int data_row_start; private int data_row_end; // options public TL2Drawer( // Called even before TL tab is popped to top final TL2DataFetcher tl2DataFetcher) { this.tl2DataFetcher = tl2DataFetcher; // placeholder initialization; real init is later via TL2DataFetchListener timeAxisMaster = new CoordCalcTimeImpl(TimelineDraw.HMARGIN); timeAxisReader = timeAxisMaster; dataAxisMaster = new TL2CoordCalcData(0); dataAxisMaster.setExpandToFill(false); dataAxisReader = dataAxisMaster; verticalRuler = new IconRuler(new ValuesLong(0, 0)); selection_listeners = new ArrayList(); cursorEventQ = new LinkedBlockingQueue(); cursorEventQueueInit(); resetSelRowBlocks(); resetFetchHistory(); event_drawer = new TimelineDraw( tl2DataFetcher, tl2DataFetcher.anWindow.getColorChooser().getColorMap(), verticalRuler, timeAxisReader, dataAxisMaster); tl2DataFetcher.addTL2DataFetchListener( new TL2DataFetcher.TL2DataFetchListener() { public void not_edt_newDataSnapshot() { AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { TL2DataSnapshot tl2DataSnapshot = tl2DataFetcher.getTL2DataSnapshot(); event_drawer.edt_processDataSnapshot(tl2DataSnapshot, true, null); if (timelinePanel != null) { long new_range = event_drawer.getAbsoluteTimeEnd(); if (new_range != 0 && old_time_range != new_range) { // YXXX should we only do this once? old_time_range = new_range; timelinePanel.edt_resetTLRanges(); // timelinePanel.zoomHistoryAdd(); attemptToSelectVisibleStackEvent(); } else { // for example, filter set remapSelections(); } timelinePanel.edt_revalidateAll( true); // init timeAxisCalculator, dataAxisCalculator } } }); } }); } public void edt_resetAll() { old_time_range = 0; resetFetchHistory(); event_drawer.edt_resetAll(); cursorEventQueueClear(); edt_processTimelineSelectionEvent_internal( null, true); // sends TimelineSelectionEvent notifications } private void resetFetchHistory() { data_time_start = 0; data_bin_time = 0; data_time_nbins = 0; data_row_start = 0; data_row_end = 0; } public void setParent(TimelinePanel parent) { this.timelinePanel = parent; } public CoordCalcTimeMaster getTimeAxisMaster() { return timeAxisMaster; } public CoordCalcDataMaster getDataAxisMaster() { return dataAxisMaster; } public CoordCalcTimeReader getTimeAxisReader() { return timeAxisReader; } public CoordCalcDataReader getDataAxisReader() { return dataAxisReader; } public VerticalRowRuler getVerticalRuler() { return verticalRuler; } public boolean getEnableZoomVertical() { return false; // disable 2-d drag zoom and the overlay version of the zoom slider } public boolean getEnableZoomOverlays() { return false; // disable the overlay version of the zoom sliders } public boolean getEnableUnalignedRows() { return true; } public boolean getEnableTimeCaliper() { return true; } // ------ get X & Y max dimensions public long getAbsoluteTimeStart() { return event_drawer.getAbsoluteTimeStart(); } public long getAbsoluteTimeEnd() { return event_drawer.getAbsoluteTimeEnd(); } public long getAbsoluteTimeDuration() { return getAbsoluteTimeEnd() - getAbsoluteTimeStart() + 1; } public int getAbsoluteRowEnd() { return dataAxisReader.getAbsRowEnd(); // YXXX shouldn't we get this from event_drawer? } public int getAbsoluteRowCount() { return dataAxisReader.getAbsRowCount(); // YXXX shouldn't we get this from event_drawer? } public void zoomCenterSelection() { // no state to change } public boolean selectionActive() { return event_drawer.selectionActive(); } public long getSelectionTimeCenter() { long center = (event_drawer.getSelectionTimeEnd() + event_drawer.getSelectionTimeStart()) / 2; // YXXX perhaps not the same formula used for zoom or dbe return center; } public long getSelectionTimeStart() { return event_drawer.getSelectionTimeStart(); } public long getSelectionTimeEnd() { return event_drawer.getSelectionTimeEnd(); } public double getSelectionYCenter() { return event_drawer.getSelectionYCenter(); } // --- "state" selection via cursor public boolean getSelectionNavigationEnabled() { // if(event_drawer.getVisibleSelection()==null){ if (event_drawer.getSelection() == null) { return false; } return true; } // --- combined selection and selRowBlock ops private void remapSelections() { // AWT thread only TL2DataSnapshot tl2DataSnapshot = event_drawer.getDataSnapshot(); if (tl2DataSnapshot == null) { return; // refetch in progress; don't check or update old selections } remapSelRowBlocks(); TimelineSelectionEvent oldEvt = event_drawer.getRecentSelection(); if (oldEvt == null) { // no previous selection to remap edt_processTimelineSelectionEvent(null); // IPC not needed to clear selections, do it now return; } final RowGeometry newRow = remapRow(oldEvt.getRowGeometry()); final CursorSetEvent newEvent; if (newRow == null) { // row could not be remapped, select an event near that row if possible int rowNum = oldEvt.rowNum; if (rowNum > event_drawer.getRowGeometry().size() - 1) { rowNum = event_drawer.getRowGeometry().size() - 1; } if (rowNum < 0) { // don't even have a row to select edt_processTimelineSelectionEvent(null); // IPC not needed to clear selections, do it now return; } RowGeometry row = event_drawer.getRowGeometry().get(rowNum); row = row.getMasterRow(); newEvent = new CursorSetEvent(row, oldEvt.clickTime, false, false, false, false); } else { newEvent = new CursorSetEvent( newRow, oldEvt.clickTime, false, false, // oldEvt.eventIdx, // filters may have changed... -1, // ... so search by time oldEvt.eventTimeStart, oldEvt.eventTimeEnd, false, false, false); } cursorEventQueueSet(newEvent); // To avoid delayed Y scrolling while waiting for selection details... // ... we could generate a new kind of no-ipc Y selection event } public boolean attemptToSelectVisibleStackEvent() { TimelineSelectionEvent selection_event = event_drawer.getSelection(); if (selection_event != null) { return false; // selection already exists, don't undo it } // no row selected, try to find a row with a callstack. double pct_start = dataAxisReader.getVisibleStart(); int row_start = dataAxisReader.getRowNearPercent(pct_start); RowGeometry rowGeometry; rowGeometry = getNearbyRowForEventSelection(row_start, true); if (rowGeometry == null) { rowGeometry = getNearbyRowForEventSelection(row_start, false); } if (rowGeometry != null) { long start_time = timeAxisReader.getTimeStart(); long end_time = timeAxisReader.getTimeEnd(); long mid_time = (start_time + end_time) / 2; cursorEventQueueAdd(new CursorSetEvent(rowGeometry, mid_time, false, false, true, true)); return true; } // processTimelineSelectionEvent(null);// force unselect; call directly, no IPC needed return false; } // --- multi-selection of row blocks (i.e. entities + samples) private void resetSelRowBlocks() { selected_row_blocks = new TreeSet(); selected_row_blocks_anchor = -1; selected_entity_info = null; cursor_rowGeometry = null; cursor_rowGeometry_alt = null; } private void updateSelRowBlocks( TL2DataSnapshot dataSnapshot, int blockNum, boolean ctrl, boolean shift) { if (blockNum < 0) { int foo = 1; // when resetting blocks } else if ((!ctrl && !shift) || (shift && selected_row_blocks_anchor == -1)) { selected_row_blocks.clear(); selected_row_blocks.add(blockNum); selected_row_blocks_anchor = blockNum; } else if (ctrl) { if (!selected_row_blocks.remove(blockNum)) { selected_row_blocks.add(blockNum); selected_row_blocks_anchor = blockNum; } } else if (shift) { selected_row_blocks.clear(); final int lo, hi; if (selected_row_blocks_anchor < blockNum) { lo = selected_row_blocks_anchor; hi = blockNum; } else { lo = blockNum; hi = selected_row_blocks_anchor; } for (int ii = lo; ii <= hi; ii++) { selected_row_blocks.add(ii); } } // save the mapping of blocks final TimelineSelectionRowEvent rowEvent; if (dataSnapshot == null) { rowEvent = new TimelineSelectionRowEvent(false); } else { selected_entity_info = dataSnapshot.getEntityDefinitions(); rowEvent = new TimelineSelectionRowEvent(!selected_row_blocks.isEmpty()); } event_drawer.setSelectedRows(selected_row_blocks); // YXXX could we refactor this? genericNotifyTimelineSelectionListeners(rowEvent); } private void remapSelRowBlocks() { TL2DataSnapshot tl2DataSnapshot = event_drawer.getDataSnapshot(); if (tl2DataSnapshot == null) { return; // refetch in progress; don't check or update old selections } if (selected_entity_info == null) { selected_row_blocks = new TreeSet(); return; // no history } TreeSet<Integer> newBlockSelList = new TreeSet(); for (Integer oldBlockNum : selected_row_blocks) { if (oldBlockNum >= selected_entity_info.size()) { return; // weird } RowDefinition rowDef0 = selected_entity_info.get(oldBlockNum).entityRows.get(0); List<EntityDefinitions> newBlocks = tl2DataSnapshot.getEntityDefinitions(); int newBlockNum = 0; for (EntityDefinitions rowBlock : newBlocks) { RowDefinition tmpRowDef = rowBlock.entityRows.get(0); if (rowDef0.matches(-1, tmpRowDef, -1)) { newBlockSelList.add(newBlockNum); break; } newBlockNum++; } } selected_row_blocks = newBlockSelList; selected_entity_info = tl2DataSnapshot.getEntityDefinitions(); TimelineSelectionRowEvent rowEvent = new TimelineSelectionRowEvent(!selected_row_blocks.isEmpty()); event_drawer.setSelectedRows(selected_row_blocks); // YXXX could we refactor this? genericNotifyTimelineSelectionListeners(rowEvent); } private RowGeometry remapRow(RowGeometry oldGeometry) { if (oldGeometry == null) { return null; } List<RowGeometry> currentRows = event_drawer.getRowGeometry(); int oldChartPropIdx = oldGeometry.chartPropIdx; RowDefinition oldRowDef = oldGeometry.rowData.getRowDef(); for (RowGeometry curGeo : currentRows) { int curChartPropIdx = curGeo.chartPropIdx; RowDefinition currRowDef = curGeo.rowData.getRowDef(); if (currRowDef.matches(curChartPropIdx, oldRowDef, oldChartPropIdx)) { return curGeo; } } return null; } // --- event selection private RowGeometry getAdjacentRowGeo(int rowNum) { List<RowGeometry> tmpGeoList = event_drawer.getRowGeometry(); for (int kk = rowNum + 1, direction = 1; ; kk += direction) { if (kk >= tmpGeoList.size()) { // hit last row; start at middle and go backwards kk = rowNum - 1; direction = -1; } if (kk < 0 || kk >= tmpGeoList.size()) { break; } int blkNum = event_drawer.rowNum2EntityNum(kk); if (!selected_row_blocks.contains(blkNum)) { // row is not part of current block of rows return tmpGeoList.get(kk); } } return null; } private RowGeometry getNearbyRowForEventSelection(int rowNum, boolean onlyWithStacks) { List<RowGeometry> tmpGeoList = event_drawer.getRowGeometry(); for (int kk = rowNum, direction = 1; ; kk += direction) { if (kk >= tmpGeoList.size()) { // hit last row; start at middle and go backwards kk = rowNum - 1; direction = -1; } if (kk < 0 || kk >= tmpGeoList.size()) { break; } RowGeometry row = tmpGeoList.get(kk); if (row.isChartData()) { // this row is a data chart continue; } Settings.TLData_type tlData_type = row.rowData.rowDefinition.getDataDescriptor().getTLDataType(); if (onlyWithStacks && (tlData_type.equals(Settings.TLData_type.TL_SAMPLE) || tlData_type.equals(Settings.TLData_type.TL_HEAPSZ) || // YXXX add property for no stacks? tlData_type.equals(Settings.TLData_type.TL_GCEVENT))) { // CXXX Bug 20801848 // ignore samples and heapsz when searching for a good row for initial selection continue; } return row; } return null; } private TimelineSelectionEvent ipcNewSelectionEvent( // not AWT thread. Must only access final data. RowGeometry rowGeometry, // must be valid long clickTime, // must be valid boolean ctrlKey, boolean shiftKey, TimelineSelectionEvent.CursorAxis axis, long eventIdx, // may be -1 boolean requestCaliperRefresh, boolean updateRowSelections) { RowDefinition rowDef = rowGeometry.rowData.rowDefinition; final IPCResult leftResult, rightResult; if (eventIdx == TimelineSelectionEvent.EVT_IDX_INVALID) { leftResult = rightResult = null; } else { leftResult = ipcStart_getTLEventCenterTime(rowDef, eventIdx, -1); rightResult = ipcStart_getTLEventCenterTime(rowDef, eventIdx, 1); } int rowNum = rowGeometry.rowNum; final EventDetail details; if (eventIdx == TimelineSelectionEvent.EVT_IDX_INVALID) { details = null; } else { details = DetailsIPC.ipcGetTLDetails( this.tl2DataFetcher.anWindow, rowDef.getExpID(), rowDef.getExpName(), rowDef.getDataDescriptor().getDataId(), rowDef.getDataDescriptor().getTLDataType(), rowDef.getEntity().getPropId(), eventIdx, rowDef.getCpuFreq(), rowDef.getTimeOrigin()); } final Vector<StackState> stackFrames; if (details == null || details.getStackStates() == null) { stackFrames = null; } else { stackFrames = new Vector(details.getStackStates()); } final boolean left = (leftResult != null && ipcFinish_getTLEventCenterTime(leftResult, rowDef) != null); final boolean right = (rightResult != null && ipcFinish_getTLEventCenterTime(rightResult, rowDef) != null); final boolean up; final boolean down; { int lastIdx = rowGeometry.parent.size() - 1; int masterOfLastRow = rowGeometry.parent.get(lastIdx).getMasterRow().rowNum; int thisMaster = rowGeometry.getMasterRow().rowNum; up = (rowNum < 1) ? false : true; down = (masterOfLastRow == thisMaster) ? false : true; } final long eventStartTime, eventEndTime; if (details != null) { eventEndTime = details.getTimestamp(); if (details instanceof DurationEvent) { long duration = ((DurationEvent) details).getDuration(); eventStartTime = eventEndTime - duration; } else { eventStartTime = eventEndTime; } } else { eventStartTime = eventEndTime = clickTime; } TimelineSelectionEvent selEvent = new TimelineSelectionEvent( rowGeometry, clickTime, // must be valid ctrlKey, shiftKey, axis, details, stackFrames, left, right, up, down, eventIdx, eventStartTime, eventEndTime, requestCaliperRefresh, updateRowSelections); // make sure this stack is known by tl2DataFetcher if (details instanceof ExtendedEvent) { ExtendedEvent extEvent = (ExtendedEvent) details; tl2DataFetcher.ipcSetStackFuncArray(extEvent.getStack()); // IPC!! } return selEvent; } private void edt_processTimelineSelectionEvent(TimelineSelectionEvent selEvent) { edt_processTimelineSelectionEvent_internal(selEvent, false); } private void edt_processTimelineSelectionEvent_internal( TimelineSelectionEvent selEvent, boolean forceRows) { do { if (selEvent == null) { selEvent = new TimelineSelectionEvent(); } TL2DataSnapshot tl2DataSnapshot = event_drawer.getDataSnapshot(); if (selEvent.rowNum == -1) { // row number unknown if (selEvent.updateRowSelections || forceRows) { resetSelRowBlocks(); updateSelRowBlocks(tl2DataSnapshot, -1, false, false); } break; // go to notify } if (selEvent.updateRowSelections) { int tmpRowNum = limitRowRange(selEvent.rowNum); // is this needed? int blockNum = event_drawer.rowNum2EntityNum(tmpRowNum); // may be -1 updateSelRowBlocks(tl2DataSnapshot, blockNum, selEvent.ctrlKey, selEvent.shiftKey); } else { int ii = 0; // for breakpoint } // set global state // save definition of current row so we can find it after filter cursor_rowGeometry = selEvent.getRowGeometry(); // search for alternate cursor in case this one is filtered out cursor_rowGeometry_alt = getAdjacentRowGeo(selEvent.rowNum); } while (false); event_drawer.setSelection(selEvent); timelinePanel.repaint(); timelinePanel .requestFocus(); // YXXX steals focus from other applications, is there a better way? genericNotifyTimelineSelectionListeners(selEvent); } private void genericNotifyTimelineSelectionListeners(TimelineSelectionGenericEvent ev) { for (TimelineSelectionListener listener : selection_listeners) { listener.valueChanged(ev); } } // --- used by TL2ControlPanel public List<EntityDefinitions> getRowDefsByBlock() { TL2DataSnapshot tl2DataSnapshot = event_drawer.getDataSnapshot(); if (tl2DataSnapshot == null) { return null; } return tl2DataSnapshot.getEntityDefinitions(); } public List<Integer> getRowBlockSelectList() { // returns a sorted list of selected row blocks (i.e. threads,samples...). // The list consists of indices for use with getRowDefsByBlock() return new ArrayList(selected_row_blocks); } // utilities private int limitRowRange(int rowNum) { // dataAxisCalculator should be in sync with rowDefs int lastRow = dataAxisReader.getAbsRowEnd(); if (rowNum < 0) { return 0; } if (rowNum > lastRow) { return lastRow; } return rowNum; } private TimelineSelectionEvent ipcGetSelEvent( RowGeometry rowGeometry, long clickTime, // may be updated below final boolean ctrlKey, final boolean shiftKey, final TimelineSelectionEvent.CursorAxis axis, final long oldEventIdx, final long moveCount, final boolean requestCaliperUpdate, final boolean updateRowSelections) { if (rowGeometry == null) { return null; } RowDefinition rowDef = rowGeometry.rowData.rowDefinition; long eventIdx = oldEventIdx; if (eventIdx != TimelineSelectionEvent.EVT_IDX_INVALID) { long[] idx_and_time = ipcGetTLEventCenterTime(rowDef, oldEventIdx, moveCount); if (idx_and_time == null) { // event not found eventIdx = TimelineSelectionEvent.EVT_IDX_INVALID; // try again by time, below } else { // event found eventIdx = idx_and_time[0]; long event_ts = idx_and_time[1]; if (clickTime == TimelineDrawer.TIME_INVALID) { clickTime = event_ts; // update clickTime if not previously set } } } // note: eventIdx may be updated above if (eventIdx == TimelineSelectionEvent.EVT_IDX_INVALID && clickTime == TimelineDrawer.TIME_INVALID) { return null; // event cannot be found. } if (eventIdx == TimelineSelectionEvent.EVT_IDX_INVALID) { eventIdx = ipcGetTLEventIdxNearTime(rowDef, clickTime); } TimelineSelectionEvent selEvent = ipcNewSelectionEvent( rowGeometry, clickTime, ctrlKey, shiftKey, axis, eventIdx, requestCaliperUpdate, updateRowSelections); return selEvent; } // --- CursorEventQueue events (e.g. left/right/up/down) handled on worker thread private void cursorEventQueueInit() { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { while (true) { cursorEventQueueTake(); } } }, "TL2CursorEventHandler"); } private void cursorEventQueueTake() { // NOT on awt thread! try { final CursorEvent genericEvent = cursorEventQ.take(); if (genericEvent instanceof CursorSetEvent) { CursorSetEvent head = (CursorSetEvent) genericEvent; not_edt_processCursorSetEvent(head); } else if (genericEvent instanceof CursorMoveEvent) { CursorMoveEvent head = (CursorMoveEvent) genericEvent; // look ahead to consolidate like-events int count = head.count; do { CursorMoveEvent anotherMove = null; synchronized (cursorEventQLock) { // synchronized with clear so that peek/take grab same value try { CursorEvent tmp = cursorEventQ.peek(); if (tmp instanceof CursorMoveEvent && ((CursorMoveEvent) tmp).axis == head.axis) { anotherMove = (CursorMoveEvent) cursorEventQ.take(); } else { break; } } catch (InterruptedException ex) { ; // do nothing } } count += anotherMove.count; } while (true); if (count != head.count) { head = new CursorMoveEvent(head.axis, count, head.ctrlKey, head.shiftKey); } not_edt_processCursorMoveEvent(head); } } catch (InterruptedException ex) { ; // do nothing } } private void not_edt_processCursorSetEvent(CursorSetEvent event) { // NOT awt thread // do ipc (calls below should not access globals) final TimelineSelectionEvent selEvent; final long eventIdx; if (event.directHit) { eventIdx = event.eventIdx; } else { eventIdx = TimelineSelectionEvent.EVT_IDX_INVALID; } selEvent = ipcGetSelEvent( event.rowGeometry, event.clickTime, event.ctrlKey, event.shiftKey, TimelineSelectionEvent.CursorAxis.NA, eventIdx, 0, event.requestRefreshCaliper, event.updateRowSelections); if (selEvent == null) { return; } // update swing components try { SwingUtilities.invokeAndWait( new Runnable() { public void run() { edt_processTimelineSelectionEvent(selEvent); } }); } catch (Exception e) { ; // weird? // e.printStackTrace(); } } private void not_edt_processCursorMoveEvent(final CursorMoveEvent event) { // NOT awt thread final int n = event.count; if (n == 0) { return; } // compute new state on EDT class AWTStateCapture { public RowGeometry newRow; public long clickTime; public long oldEventIdx; public long moveCount; public boolean requestCaliperUpdate; public AWTStateCapture() { this.newRow = null; this.clickTime = TimelineDrawer.TIME_INVALID; this.oldEventIdx = TimelineSelectionEvent.EVT_IDX_INVALID; this.moveCount = 0; this.requestCaliperUpdate = false; } } ; final AWTStateCapture saved = new AWTStateCapture(); try { SwingUtilities.invokeAndWait( new Runnable() { public void run() { // Calculate the next location on EDT // Set newRow=null if next location can't be calculated. TimelineSelectionEvent prevEvent = event_drawer.getSelection(); if (prevEvent == null || prevEvent.getRowGeometry() == null || prevEvent.rowNum == -1) { return; } if (event.axis == TimelineSelectionEvent.CursorAxis.LEFT_RIGHT) { if (prevEvent.eventIdx == TimelineSelectionEvent.EVT_IDX_INVALID) { return; } saved.newRow = prevEvent.getRowGeometry(); // will not be null, see above saved.clickTime = TimelineDrawer.TIME_INVALID; // will be determined later saved.oldEventIdx = prevEvent.eventIdx; saved.moveCount = n; saved.requestCaliperUpdate = true; return; } if (event.axis == TimelineSelectionEvent.CursorAxis.UP_DOWN) { final int n_abs = Math.abs(n); RowGeometry newRow = event_drawer.rowNum2RowGeometry(prevEvent.rowNum); if (newRow == null) { return; } for (int ii = 0; ii < n_abs; ii++) { final int nn; if (n < 0) { nn = newRow.rowNum - newRow.subrowNum - 1; } else { nn = newRow.rowNum - newRow.subrowNum + newRow.nSubrows; } RowGeometry nextRow = event_drawer.rowNum2RowGeometry(nn); if (nextRow == null) { break; } newRow = nextRow; } newRow = newRow.getMasterRow(); saved.newRow = newRow; saved.clickTime = prevEvent.clickTime; saved.oldEventIdx = TimelineSelectionEvent.EVT_IDX_INVALID; saved.moveCount = 0; // not used saved.requestCaliperUpdate = false; return; } } }); } catch (Exception e) { ; // weird? // e.printStackTrace(); } // do ipc (calls below should not access globals) final TimelineSelectionEvent selEvent; if (saved.newRow == null) { return; } selEvent = ipcGetSelEvent( saved.newRow, saved.clickTime, event.ctrlKey, event.shiftKey, event.axis, saved.oldEventIdx, saved.moveCount, saved.requestCaliperUpdate, true); if (selEvent == null) { return; } // update swing components try { SwingUtilities.invokeAndWait( new Runnable() { public void run() { edt_processTimelineSelectionEvent(selEvent); } }); } catch (Exception e) { ; // weird? // e.printStackTrace(); } } private void cursorEventQueueClear() { synchronized (cursorEventQLock) { // synchronized to simplify peek cursorEventQ.clear(); } } private void cursorEventQueueAdd(CursorEvent event) { cursorEventQ.add(event); } private void cursorEventQueueSet(CursorEvent event) { // edt_processTimelineSelectionEvent(null);// clears queue, resets RHS cursorEventQueueClear(); cursorEventQueueAdd(event); } public void selectFirst() { int rowNum = dataAxisReader.getRowStart(); RowGeometry rowGeometry = event_drawer.rowNum2RowGeometry(rowNum); long time = timeAxisReader.getTimeStart(); cursorEventQueueSet(new CursorSetEvent(rowGeometry, time, false, false, true, true)); } @Override public void selectLeft() { selectLeft(false, false); } public void selectRight() { selectRight(false, false); } public void selectUp() { selectUp(false, false); } public void selectDown() { selectDown(false, false); } public void selectLeft(boolean ctrl, boolean shift) { cursorEventQueueAdd( new CursorMoveEvent(TimelineSelectionEvent.CursorAxis.LEFT_RIGHT, -1, ctrl, shift)); } public void selectRight(boolean ctrl, boolean shift) { cursorEventQueueAdd( new CursorMoveEvent(TimelineSelectionEvent.CursorAxis.LEFT_RIGHT, 1, ctrl, shift)); } public void selectUp(boolean ctrl, boolean shift) { cursorEventQueueAdd( new CursorMoveEvent(TimelineSelectionEvent.CursorAxis.UP_DOWN, -1, ctrl, shift)); } public void selectDown(boolean ctrl, boolean shift) { cursorEventQueueAdd( new CursorMoveEvent(TimelineSelectionEvent.CursorAxis.UP_DOWN, 1, ctrl, shift)); } public TimelineCaliper selectNearXY(int x, int y, boolean ctrl, boolean shift) { // System.out.println(event_drawer.dumpXY(event_drawer.findNearXY(x,y,false))); // DUMP // System.out.println(event_drawer.exportAsText(0)); // Returns time dimensions of event only if mouse directly over event. // Additionally, queues the selection event. TimelineDraw.FindNearXYResult result = event_drawer.findNearXY(x, y, true); if (result == null) { return null; } final CursorSetEvent event; if (result.event != null) { event = new CursorSetEvent( result.rowGeometry, result.clickTime, ctrl, shift, result.event.eventIdx, result.event.timeStart, result.event.timeEnd, result.directTimeHit, false, true); } else { event = new CursorSetEvent(result.rowGeometry, result.clickTime, ctrl, shift, false, true); } cursorEventQueueSet(event); if (!result.directTimeHit) { return null; } return new TimelineCaliper(result.event.timeStart, result.event.timeEnd); } public void notifyCaliperChange(TimelineCaliper caliper) { event_drawer.setCaliper(caliper); genericNotifyTimelineSelectionListeners( // Refactor? It may be bit odd doing this here // as the owner of calipers is TimelinePanel, not this class. new TimelineSelectionCaliperEvent(caliper)); timelinePanel.repaint(); } public void notifyZoomHistoryChange(TimelineSelectionHistoryEvent e) { genericNotifyTimelineSelectionListeners(e); } public void addSelectionListener(TimelineSelectionListener listener) { // AWT thread only selection_listeners.add(listener); } public boolean edt_fetchData(final boolean forceReload) { // AWT thread only! TL2DataSnapshot drawerSnapshot = event_drawer.getDataSnapshot(); // Note: event_drawer.getDataSnapshot() is only updated on the EDT; we know it won't change // while in this method if (drawerSnapshot != tl2DataFetcher.getTL2DataSnapshot()) { return false; // shortcut the process, the event_drawer is already obsolete } boolean refetchNeeded = false; if (forceReload) { // external entity (e.g. filter) is forcing refetch refetchNeeded = true; } // X: align according to bin size long tstart = timeAxisReader.getTimeStartAligned(); long binTime = timeAxisReader.getTimePerBin(); int binCount = timeAxisReader.getNumBins(); // Y int pstart = dataAxisReader.getRowStart(); int pend = dataAxisReader.getRowEnd(); // if(!initialImageReady){ // if(!initialImageReady){//TBR // // no image yet, we need to refetch // refetchNeeded = true; // }else{ { // check old data to see if we really need to refetch if (tstart != data_time_start || binTime != data_bin_time || binCount != data_time_nbins) { refetchNeeded = true; } if (pstart < data_row_start || pend > data_row_end) { refetchNeeded = true; } } if (!refetchNeeded && !forceReload) { return false; // not updated } final boolean loadingProcessed; if (event_drawer.getDataSnapshot() == null) { // no data to fetch, but still need to update the screen loadingProcessed = true; } else { RowGeometry rstart = event_drawer.rowNum2RowGeometry(pstart); RowGeometry rend = event_drawer.rowNum2RowGeometry(pend); if (null == rstart || null == rend) { loadingProcessed = false; // happens when null snapshot is pushed to clear screen } else { RowGeometry wide_rstart = event_drawer.rowNum2RowGeometry(0); RowGeometry wide_rend = event_drawer.rowNum2RowGeometry(dataAxisReader.getAbsRowEnd()); long overshoot = timeAxisReader.getTimeDuration(); // how much extra to buffer long estStart = timeAxisReader.getTimeStart() - overshoot; long wide_tstart = timeAxisReader.getTimeStartAligned(estStart); long estEnd = timeAxisReader.getTimeEnd() + overshoot; if (estEnd > event_drawer.getAbsoluteTimeEnd()) { estEnd = event_drawer.getAbsoluteTimeEnd(); } long duration = estEnd - wide_tstart; int wide_binCount = (int) (duration / binTime) + 1; RowDataRequestParams newReq = new RowDataRequestParams( drawerSnapshot, forceReload, binTime, wide_tstart, wide_binCount, // grab more width than requested wide_rstart.rowData.idx, wide_rend.rowData.idx, // ask for all rows timeAxisReader.getTimeStart(), timeAxisReader.getTimeEnd(), rstart.rowData.idx, rend.rowData.idx); loadingProcessed = tl2DataFetcher.edt_fetchTLRowDataInitiate(newReq); } } if (!loadingProcessed) { return false; // not updated (e.g. snapshot changed underneath us) } // initialImageReady = true; data_time_start = tstart; data_bin_time = binTime; data_time_nbins = binCount; data_row_start = pstart; data_row_end = pend; // if(forceReload){ // // for example, filter set // recenterVerticallyOnCursor(); // remapSelections(); // } return true; // updated } public boolean drawData(Graphics g) { // AWT thread only! final boolean painted; // if(initialImageReady){ if (event_drawer.getDataSnapshot() == tl2DataFetcher.getTL2DataSnapshot()) { event_drawer.drawIt(g); painted = true; } else { painted = false; } return painted; } private long ipcGetTLEventIdxNearTime(RowDefinition rowDef, long ts) { if (rowDef == null) { return TimelineSelectionEvent.EVT_IDX_INVALID; } int searchDirection = 0; // search forward and backwards for nearest event { Settings.TLData_type tlData_type = rowDef.getDataDescriptor().getTLDataType(); if (tlData_type.equals(Settings.TLData_type.TL_HEAPSZ)) { searchDirection = -1; // only search backwards in time } } long adjust = rowDef.getTimeOrigin(); long unadjusted_ts = ts + adjust; long eventIdx = tl2DataFetcher.ipcGetTLEventIdxNearTime( rowDef.getExpID(), rowDef.getDataDescriptor().getDataId(), rowDef.getEntity().getPropId(), rowDef.getEntity().getPropValue(), rowDef.getAux(), searchDirection, unadjusted_ts); return eventIdx; // SELECTION_IDX_INVALID if row has no events } private long[] ipcGetTLEventCenterTime(RowDefinition rowDef, long oldEventIdx, long moveCount) { if (rowDef == null) { return null; } IPCResult ipcResult = ipcStart_getTLEventCenterTime(rowDef, oldEventIdx, moveCount); return ipcFinish_getTLEventCenterTime(ipcResult, rowDef); } private IPCResult ipcStart_getTLEventCenterTime( RowDefinition rowDef, long oldEventIdx, long moveCount) { return tl2DataFetcher.ipcStart_getTLEventCenterTime( null, null, rowDef.getExpID(), rowDef.getDataDescriptor().getDataId(), rowDef.getEntity().getPropId(), rowDef.getEntity().getPropValue(), rowDef.getAux(), oldEventIdx, moveCount); } private long[] ipcFinish_getTLEventCenterTime(IPCResult ipcResult, RowDefinition rowDef) { if (ipcResult == null) { return null; } long[] idx_and_time = (long[]) ipcResult.getObject(); long ts = TimelineDrawer.TIME_INVALID; if (idx_and_time != null) { long unadjusted_ts = idx_and_time[1]; long adjust = rowDef.getTimeOrigin(); ts = unadjusted_ts - adjust; // should not be -1 if (ts < 0) { return null; // weird } idx_and_time[1] = ts; } return idx_and_time; // null if no such event } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/EventDetails.java����������������������������������������0000644�0001750�0001750�00000023662�14517772113�021070� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.AnInteger; import org.gprofng.mpmt.AnList; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.timeline.events.EventDetail; import org.gprofng.mpmt.timeline.events.ExtendedEvent; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.util.ArrayList; import java.util.Vector; import javax.accessibility.AccessibleContext; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.SwingConstants; // Initial version derived from timeline/TimelineDisp.java // YXXX Ideally, clean this up for TL2 public class EventDetails { private static final int NUM_EVT_SPC_LBL = 20; // YXXX yuck: max # of eventSpecLabels/Text // state private boolean extendedShowing; // show extended fields & stacks on RH tab private ExtendedEvent previousSelectedEvent; // previous user selection private String[] oldLabels; // previous selection's details // panel to hold details private JPanel tbPanel; private AnList anList; // container for event details // fixed fields private JTextField expTxt; private JTextField typeTxt; private JTextField functionTxt; private JTextField timeTxt; private JTextField lwpTxt; private JTextField thrTxt; private JTextField cpuTxt; // event-specific fields private JTextField[] eventSpecText; private JLabel[] eventSpecLabels; private ArrayList<JTextField> allFields; private ArrayList<JTextField> extendedFields; private ArrayList<JLabel> extendedLabels; // Constructor public EventDetails(final AnWindow awindow) { extendedShowing = true; doInit(); } // Initialize the event panel on right side public void doInit() { tbPanel = new JPanel(new BorderLayout()); // EventDetail Pane: Timeline selection allFields = new ArrayList<JTextField>(); extendedFields = new ArrayList<JTextField>(); extendedLabels = new ArrayList<JLabel>(); anList = new AnList(true); AccessibleContext context = anList.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Events")); context.setAccessibleDescription(AnLocale.getString("Events")); anList.setAlignmentY(); anList.setBorder(AnVariable.boxBorder); expTxt = createField(AnLocale.getString("Process:")); // , // AnLocale.getString('E', "MNEM_TIMELINE_EVENT_EXPERIMENT_NAME"), anList); typeTxt = createField(AnLocale.getString("Event Type:", "TIMELINE_EVENT_EVENT_TYPE")); // , // AnLocale.getString('p', "MNEM_TIMELINE_EVENT_EVENT_TYPE"), anList); functionTxt = createField(AnLocale.getString("Leaf Function:")); // , // AnLocale.getString('n', "MNEM_TIMELINE_EVENT_LEAF_FUNCTION"), anList); timeTxt = createField(AnLocale.getString("Timestamp (sec.):")); // , // AnLocale.getString('i', "MNEM_TIMELINE_EVENT_TIMESTAMP"), anList); lwpTxt = createField(AnLocale.getString("LWP:")); // , // AnLocale.getString('W', "MNEM_TIMELINE_EVENT_LWP"), anList); thrTxt = createField(AnLocale.getString("Thread:")); // , // AnLocale.getString('h', "MNEM_TIMELINE_EVENT_THREAD"), anList); cpuTxt = createField(AnLocale.getString("CPU:")); // , // AnLocale.getString('c', "MNEM_TIMELINE_EVENT_CPU"), anList); eventSpecLabels = new JLabel[NUM_EVT_SPC_LBL]; eventSpecText = new JTextField[NUM_EVT_SPC_LBL]; final String longest; { int len = 0, ind = 0, strlen; final int numNames = TimelineVariable.mstate_info.getNumNames(); for (int i = 0; i < numNames; i++) { String name = TimelineVariable.mstate_info.getNameByDisplayIdx(i); strlen = name.length(); if (strlen > len) { len = strlen; ind = i; } } longest = TimelineVariable.mstate_info.getNameByDisplayIdx( ind); // YXXX bogus, really depends on font } for (int i = 0; i < NUM_EVT_SPC_LBL; i++) { AnUtility.AnLabel label = new AnUtility.AnLabel( longest + " ", new ImageIcon(StackState.createIcon(Color.black)), JLabel.RIGHT, true); // label.setDisplayedMnemonic('z'); eventSpecLabels[i] = label; eventSpecText[i] = (JTextField) AnUtility.getText("", 0); eventSpecLabels[i].setVisible(false); eventSpecText[i].setVisible(false); eventSpecLabels[i].setLabelFor(eventSpecText[i]); anList.add(eventSpecLabels[i], eventSpecText[i]); allFields.add(eventSpecText[i]); } tbPanel.add(anList); } // Creates the label and textfield pairs for the event pane on right private JTextField createField(final String label) { // , final char mnemonic, // final AnList list) { final AnList list = anList; final JLabel lbl; final JTextField fld; lbl = (JLabel) AnUtility.getItem(label); fld = (JTextField) AnUtility.getText("", 0); // lbl.setDisplayedMnemonic(mnemonic); lbl.setLabelFor(fld); AccessibleContext context = lbl.getAccessibleContext(); context.setAccessibleName(label); context.setAccessibleDescription(label); context = fld.getAccessibleContext(); context.setAccessibleName(label); context.setAccessibleDescription(label); list.add(lbl, fld); allFields.add(fld); extendedFields.add(fld); extendedLabels.add(lbl); return fld; } private void clearTimeline() { oldLabels = null; for (int i = 0; i < NUM_EVT_SPC_LBL; i++) { eventSpecText[i].setVisible(false); eventSpecLabels[i].setVisible(false); } setExtendedFields(true); for (JTextField e : allFields) { e.setText(""); } } public JPanel setEvent(TimelineSelectionEvent evt) { EventDetail basicEvent = evt.eventDetail; RowDefinition rowDef = evt.getRowDefinition(); // may be null if (basicEvent == null) { oldLabels = null; for (int i = 0; i < NUM_EVT_SPC_LBL; i++) { eventSpecText[i].setVisible(false); eventSpecLabels[i].setVisible(false); } setExtendedFields(true); for (JTextField e : allFields) { e.setText(""); } return tbPanel; } final String[] labels, info; // final char[] mnemonics; final ImageIcon[] icons; labels = basicEvent.getEventSpecificLabels(); // mnemonics = basicEvent.getEventSpecificMnemonics(); icons = basicEvent.getEventSpecificIcons(); if (labels != oldLabels) { for (int i = 0; i < labels.length; i++) { eventSpecLabels[i].setText(labels[i]); // eventSpecLabels[i].setDisplayedMnemonic( // (i < mnemonics.length) ? mnemonics[i] : '\0'); if (i < icons.length) { eventSpecLabels[i].setIcon(icons[i]); eventSpecLabels[i].setHorizontalTextPosition(SwingConstants.LEADING); } else { eventSpecLabels[i].setIcon(null); } eventSpecLabels[i].setVisible(true); } for (int i = labels.length; i < NUM_EVT_SPC_LBL; i++) { eventSpecLabels[i].setVisible(false); } } oldLabels = labels; info = basicEvent.getEventSpecificInfo(); if (info == null) { return tbPanel; } for (int i = 0; i < info.length; i++) { eventSpecText[i].setText(info[i]); eventSpecText[i].setVisible(true); } for (int i = info.length; i < NUM_EVT_SPC_LBL; i++) { eventSpecText[i].setVisible(false); } if (!(basicEvent instanceof ExtendedEvent)) { if (extendedShowing) { setExtendedFields(false); } // YXXX update_event(evt); return tbPanel; } if (!extendedShowing) { setExtendedFields(true); } final ExtendedEvent event = (ExtendedEvent) basicEvent; if (event == previousSelectedEvent) { return tbPanel; } // Fill in text field values in the EventDetail pane based on the // current event selection final String fName; Vector<StackState> stackFrames = evt.getStackFrames(); if (stackFrames != null && !stackFrames.isEmpty()) { fName = stackFrames.get(0).getName(); } else { fName = ""; // weird } functionTxt.setText(fName); functionTxt.setCaretPosition(0); lwpTxt.setText(new AnInteger(event.getLWP()).toString()); thrTxt.setText(new AnInteger(event.getThread()).toString()); if (event.getCPU() == ExtendedEvent.NO_CPU_INFO) { cpuTxt.setText(AnLocale.getString("(unknown)")); } else { cpuTxt.setText(new AnInteger(event.getCPU()).toString()); } timeTxt.setText(TimelineVariable.strTimestamp(event.getTimestamp())); if (rowDef == null) { typeTxt.setText(""); expTxt.setText(""); } else { typeTxt.setText(rowDef.getDataDescUName()); String expName = rowDef.getExpName(); expTxt.setText(expName); } previousSelectedEvent = event; return tbPanel; } private void setExtendedFields(final boolean value) { for (JTextField e : extendedFields) { e.setVisible(value); } for (JLabel jl : extendedLabels) { jl.setVisible(value); } anList.setAlignmentX(); extendedShowing = value; } } ������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TL2DataSnapshot.java�������������������������������������0000644�0001750�0001750�00000014051�14517772113�021404� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.settings.TimelineSetting; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; // The class represents storage for the timeline data for a particular // set of "entities" and enabled charts. It should have a rowDefinition for // every row, including those that might not be visible on the screen. // The time range supplied should be for maximum zoom-out across all rows. // // The same instance of a snapshot can be reused for all levels // of scroll, as well as display options such as stack height and orientation. // // A new instance of this class is needed when options change the actual rows // that can be displayed: Add/Drop experiment, Presentation Data Type // selections, and Filters. // // Portions of this class are immutable: // // The row definitions are stored in: // rowDefinitions/timeStart/TimeEnd // The array for storing results, rowResults, is allocated only once and // has a fixed size and a fixed set of RowData objects. // Note, however, that components within RowData // are modified as data gets populated from gp-display-text. public class TL2DataSnapshot { public static class EntityData { public final List<RowData> entityRows; public EntityData(List<RowData> entityRows) { this.entityRows = Collections.unmodifiableList(entityRows); } } public static class EntityDefinitions { public final List<RowDefinition> entityRows; public EntityDefinitions(List<RowDefinition> entityRows) { this.entityRows = Collections.unmodifiableList(entityRows); } } public static class ExperimentData { public final List<EntityData> experimentEntities; public ExperimentData(List<EntityData> experimentEntities) { this.experimentEntities = Collections.unmodifiableList(experimentEntities); } } public static class ExperimentDefinitions { public final List<EntityDefinitions> experimentEntities; public ExperimentDefinitions(List<EntityDefinitions> experimentEntities) { this.experimentEntities = Collections.unmodifiableList(experimentEntities); } } private final TimelineSetting.EntityProp entityProp; private final List<RowData> allRowData; // data organized by row private final List<EntityData> allEntityData; // data organized by entity private final List<EntityDefinitions> allEntityDefs; // defs organized by entity private final List<ExperimentData> experimentData; // data organized by experiment private final List<ExperimentDefinitions> experimentDefs; // defs organized by experiment private final long absoluteTimeStart, absoluteTimeEnd; private final Map<Integer, ExperimentDefinitions> experimentDefsByExpid; // RowDefinition data is expected to be immutable public TL2DataSnapshot( TimelineSetting.EntityProp entityProp, List<ExperimentDefinitions> expList, long absoluteTimeStart, long absoluteTimeEnd) { this.entityProp = entityProp; this.absoluteTimeStart = absoluteTimeStart; this.absoluteTimeEnd = absoluteTimeEnd; this.experimentDefs = Collections.unmodifiableList(expList); experimentDefsByExpid = new HashMap(); int ii = 0; ArrayList<ExperimentData> newExpDataList = new ArrayList(); ArrayList<RowData> newAllRowData = new ArrayList(); ArrayList<EntityData> newAllEntityData = new ArrayList(); ArrayList<EntityDefinitions> newAllEntityDefs = new ArrayList(); for (ExperimentDefinitions expDef : expList) { ArrayList<EntityData> newEntityDataList = new ArrayList(); for (EntityDefinitions entityDef : expDef.experimentEntities) { // process entity ArrayList<RowData> newEntityData = new ArrayList(); for (RowDefinition rowDef : entityDef.entityRows) { int expid = rowDef.getUserExpID(); ExperimentDefinitions tmp = experimentDefsByExpid.put(expid, expDef); if (tmp != null && tmp != expDef) { int jj = 1; // weird~ } RowData newRow = new RowData(rowDef, ii); newAllRowData.add(newRow); newEntityData.add(newRow); ii++; } EntityData newEntity = new EntityData(newEntityData); newEntityDataList.add(newEntity); newAllEntityData.add(newEntity); newAllEntityDefs.add(entityDef); } newExpDataList.add(new ExperimentData(newEntityDataList)); } allRowData = Collections.unmodifiableList(newAllRowData); allEntityData = Collections.unmodifiableList(newAllEntityData); allEntityDefs = Collections.unmodifiableList(newAllEntityDefs); experimentData = Collections.unmodifiableList(newExpDataList); } public TimelineSetting.EntityProp getEntityProp() { return entityProp; } public long getAbsoluteTimeEnd() { return absoluteTimeEnd; } public long getAbsoluteTimeStart() { return absoluteTimeStart; } public List<RowData> getRowData() { return allRowData; } public List<EntityData> getEntityData() { return allEntityData; } public List<EntityDefinitions> getEntityDefinitions() { return allEntityDefs; } public List<ExperimentData> getExperimentData() { return experimentData; } public List<ExperimentDefinitions> getExperimentDefinitions() { return experimentDefs; } public ExperimentDefinitions getExperimentDefinitions(int expid) { return experimentDefsByExpid.get(expid); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/RowDefinition.java���������������������������������������0000644�0001750�0001750�00000023553�14517772113�021260� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.experiment_props.*; import org.gprofng.mpmt.settings.Settings; import java.util.List; // This class is intended to be immutable so that it can be accessed from // the AWT thread without worry that inner details may change. // (Changeable data should go into RowData.java w/ appropriate synchronization) // // Each Entity may correspond to several rows on timeline (RowDefinitions). // The number of rows on the timeline is determined by the number of // DataDescriptors specified for the particular experiment. public final class RowDefinition { // experiment private final int exp_id; private final int user_exp_id; // data_id within experiment private final DataDescriptor data_descriptor; // immutable private final int aux; // HWC value // entity within data_id private final Entity entity; // immutable // specification for additional chart properties private final List<PropDescriptor> chartProps; private final String chartPropNames[]; // descriptive strings private final String exp_name; private final int exp_group_id; private final boolean compare_on; private final long data_start_hrt; // hr time at data start private final long data_end_hrt; // hr time at data end private final long time_origin_hrt; // hr time at "0" point of timeline private final String longDescription; private final String shortLabel; private final int cpuFreq; public RowDefinition( final ExperimentProperties experiment, Entity entity, final DataDescriptor d_descriptor, final int aux, final List<PropDescriptor> chartProps, final long time_adjust, final boolean compare_on) { this.compare_on = compare_on; this.exp_id = experiment.getID(); this.user_exp_id = experiment.getUserID(); this.data_descriptor = d_descriptor; this.aux = aux; if (entity == null) { entity = new Entity( Settings.PROP_NONE, // ent_prop_id (experiment-wide) "", // don't care 0, // ent_prop_value (0 is value for any undefined prop) d_descriptor.getLongUName(aux), null, null); } this.entity = entity; this.exp_name = experiment.getName(); this.exp_group_id = experiment.getGroupId(); this.data_start_hrt = experiment.getStartTime(); this.data_end_hrt = experiment.getEndTime(); this.time_origin_hrt = time_adjust; this.chartProps = chartProps; if (chartProps == null) { this.chartPropNames = null; } else { this.chartPropNames = new String[chartProps.size()]; int ii = 0; for (PropDescriptor prop : chartProps) { String propName = prop.getName(); this.chartPropNames[ii++] = propName; } } // other fields must be set before creating labels: this.longDescription = createLongDescription(); this.shortLabel = createShortLable(); this.cpuFreq = experiment.getCpuFreq(); } public DataDescriptor getDataDescriptor() { return data_descriptor; } public Entity getEntity() { return entity; } public String getExpName() { return exp_name; } public int getExpID() { return exp_id; } public int getUserExpID() { return user_exp_id; } public int getExpGroupId() { return exp_group_id; } public int getAux() { return aux; } public Settings.TLData_type getTLDataType() { return data_descriptor.getTLDataType(); } public String getDataDescUName() { return data_descriptor.getLongUName(aux); } public long getTimeOrigin() { // hr time at timeline origin (nanoseconds) return time_origin_hrt; } public long getDataTimeStart() { return data_start_hrt; } public long getDataTimeEnd() { return data_end_hrt; } public String getLongDescription() { return longDescription; } public boolean getComparisonOn() { return compare_on; } public int getChartCount() { if (chartProps == null) { return 0; } else { return chartProps.size(); } } public List<PropDescriptor> getChartProperties() { return chartProps; } public String[] getChartPropNames() { return chartPropNames; } public boolean matches(int thisChartPropIdx, RowDefinition thatRowDef, int thatChartPropIdx) { // check the basics if (user_exp_id != thatRowDef.user_exp_id) { return false; } else if (aux != thatRowDef.aux) { return false; } else if (entity.getPropId() != thatRowDef.entity.getPropId()) { return false; } else if (entity.getPropValue() != thatRowDef.entity.getPropValue()) { return false; } // check for data vs chart boolean thisIsData = (thisChartPropIdx == -1); boolean thatIsData = (thatChartPropIdx == -1); if (thisIsData != thatIsData) { return false; // only one is data } else if (thisIsData && thatIsData) { return true; // both are data } // were dealing with two charts if (chartProps == null || thisChartPropIdx >= chartProps.size()) { return false; // weird } else if (thatRowDef.getChartProperties() == null || thatChartPropIdx >= thatRowDef.getChartProperties().size()) { return false; // weird } PropDescriptor thisPropDescriptor = chartProps.get(thisChartPropIdx); PropDescriptor thatPropDescriptor = thatRowDef.getChartProperties().get(thatChartPropIdx); if (thisPropDescriptor.getPropId() != thatPropDescriptor.getPropId()) { return false; } return true; } private String createLongDescription() { RowDefinition rowDefinition = this; String desc = "<HTML>"; String moreInfo = ""; Settings.TLData_type tltype = data_descriptor.getTLDataType(); if (!tltype.equals(Settings.TLData_type.TL_SAMPLE) && !tltype.equals(Settings.TLData_type.TL_HEAPSZ) && // YXXX where to decide when to show stacks? !tltype.equals(Settings.TLData_type.TL_GCEVENT)) { // CXXX Bug 20801848 moreInfo = AnLocale.getString(" Call Stacks"); } String experimentInfo = AnLocale.getString("<HR>Process: ") + "<B>" + user_exp_id + "</B>" + " (" + "<B>" + exp_name + "</B>" + ")"; if (Settings.PROP_NONE == rowDefinition.getEntity().getPropId()) desc += rowDefinition.getDataDescUName() + moreInfo + "<BR>" + experimentInfo; else { final String num, thr_name, thr_g_name, thr_p_name; final long entityNum; entityNum = rowDefinition.getEntity().getPropValue(); thr_name = rowDefinition.getEntity().getThreadName(); thr_g_name = rowDefinition.getEntity().getJThreadGroupName(); thr_p_name = rowDefinition.getEntity().getJThreadParentName(); // int tl_data_mode = rowDefinition.getEntity().getPropId(); String str; if (thr_g_name != null) { str = "<BR>" + AnLocale.getString("Thread name: ") + "<B>" + thr_name + "</B>" + "<BR>" + AnLocale.getString("Thread group: ") + "<B>" + thr_g_name + "</B>" + "<BR>" + AnLocale.getString("Thread parent: ") + "<B>" + thr_p_name + "</B>"; } else if (thr_name != null) { str = "<BR>" + AnLocale.getString("Thread name: ") // YXXX TBD + "<B>" + thr_name + "</B>"; } else { str = ""; } num = Long.toString(entityNum); String entMode = entity.getPropIdName(); desc += rowDefinition.getDataDescUName() + moreInfo + experimentInfo + "<BR>" + entMode + ": " + "<B>" + num + "</B>" + str; } if (this.compare_on) { final String group_name; if (exp_group_id <= 1) { group_name = "Baseline"; } else { group_name = "Comparison Group " + (exp_group_id - 1); } desc += "<BR>" + AnLocale.getString("Compare Group: ") + "<B>" + group_name + "</B>"; } return desc; } public String getShortLabel() { return shortLabel; } private String createShortLable() { RowDefinition rowDefinition = this; String userExpId = Integer.toString(rowDefinition.getUserExpID()); String rowLabel = new String(); long entityPropId = rowDefinition.getEntity().getPropId(); String entityPropName = rowDefinition.getEntity().getPropIdName(); rowLabel += userExpId; if (entityPropId != Settings.PROP_NONE) { // everything besides sample rows rowLabel += " " + entityPropName.toUpperCase().charAt(0) + ":" + Long.toString(rowDefinition.getEntity().getPropValue()); } else { if (compare_on) { if (exp_group_id <= 1) { rowLabel += " (Base)"; } else { // rowLabel += " (G" + (exp_group_id-1) + ")"; } } } return rowLabel; } public int getCpuFreq() { return cpuFreq; } } �����������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/data/����������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�016633� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/data/SampleEvent.java������������������������������������0000644�0001750�0001750�00000001755�14517772113�021634� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2.data; public class SampleEvent extends GenericEvent { public final long[] propValues; public SampleEvent( long eventId, int binStart, int binCount, long timeStart, long timeEnd, long[] propVals) { super(eventId, binStart, binCount, timeStart, timeEnd); this.propValues = propVals; } } �������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/data/GenericEvent.java�����������������������������������0000644�0001750�0001750�00000003112�14517772113�021754� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2.data; public class GenericEvent { public final long eventIdx; public final int binStart; public final int binCount; public final long timeStart, timeEnd; private final double NS_PER_SEC = 1000000000.0; public GenericEvent(long eventIdx, int binStart, int binCount, long timeStart, long timeEnd) { this.eventIdx = eventIdx; this.binStart = binStart; this.binCount = binCount; this.timeStart = timeStart; this.timeEnd = timeEnd; } @Override public String toString() { final GenericEvent event = this; StringBuilder buf = new StringBuilder(); // buf.append("eventIdx=" + event.eventIdx); // Not stable GUI testing? buf.append(" timeStart=" + event.timeStart / NS_PER_SEC); buf.append(" timeEnd=" + event.timeEnd / NS_PER_SEC); buf.append(" binStart=" + event.binStart); buf.append(" binCount=" + event.binCount); return buf.toString(); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/data/StackEvent.java�������������������������������������0000644�0001750�0001750�00000002610�14517772113�021447� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2.data; public class StackEvent extends GenericEvent { public final long stackId; public final int mState; // OS state at time public StackEvent( long eventId, int binStart, int binCount, long timeStart, long timeEnd, long stackId, int mstate) { super(eventId, binStart, binCount, timeStart, timeEnd); this.stackId = stackId; this.mState = mstate; } @Override public String toString() { final StackEvent event = this; StringBuilder buf = new StringBuilder(); buf.append(super.toString()); // buf.append(" stackId=" + event.stackId); // Not stable GUI testing buf.append(" mState=" + event.mState); return buf.toString(); } } ������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/Entity.java����������������������������������������������0000644�0001750�0001750�00000004373�14517772113�017753� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; // This class is intended to be immutable. // // Entity is populated by DBE and describes how the TL rows are organized. // It specifies one of [LWP, THREAD, CPU], // // Each Entity may correspond to several rows on timeline (RowDefinition). // The number of rows on the timeline is determined by the number of // DataDescriptors specified for the particular experiment. public final class Entity { // data from ipcGetEntities() private final int entity_prop_id; // property used to segregate data private final String entity_prop_id_name; private final int entity_prop_value; // if "force_java_threads == true", set these: private final String name; // jthread entname private final String g_name; // jthread group name private final String p_name; // jthread parent name public Entity( final int entity_prop_id, final String entity_prop_id_name, final int entity_prop_value, final String name, final String g_name, final String p_name) { this.entity_prop_id = entity_prop_id; this.entity_prop_id_name = entity_prop_id_name; this.entity_prop_value = entity_prop_value; this.name = name; this.g_name = g_name; this.p_name = p_name; } public int getPropValue() { return entity_prop_value; } public int getPropId() { return entity_prop_id; } public String getPropIdName() { return entity_prop_id_name; } public String getThreadName() { return name; } public String getJThreadGroupName() { return g_name; } public String getJThreadParentName() { return p_name; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TL2ControlPanel.java�������������������������������������0000644�0001750�0001750�00000226154�14517772113�021424� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnEvent; import org.gprofng.mpmt.AnListener; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.control_panel.CPDetailsScrollPane; import org.gprofng.mpmt.control_panel.CPToolbar; import org.gprofng.mpmt.control_panel.CPToolbarHandler; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.filter.CustomFilterAction; import org.gprofng.mpmt.filter.FilterClause; import org.gprofng.mpmt.filter.RedoFilterAction; import org.gprofng.mpmt.filter.RemoveAllFilterAction; import org.gprofng.mpmt.filter.UndoFilterAction; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.settings.TimelineSetting; import org.gprofng.mpmt.statecolors.AnColorChooser; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.statecolors.StackView; import org.gprofng.mpmt.statecolors.StackViewState; import org.gprofng.mpmt.statecolors.StateColorMap; import org.gprofng.mpmt.timeline.events.DetailsIPC; import org.gprofng.mpmt.timeline.events.ProfileEvent; import org.gprofng.mpmt.timeline2.TL2DataSnapshot.*; import org.gprofng.mpmt.timeline_common.TimelineCaliper; import org.gprofng.mpmt.timeline_common.TimelinePanel; import org.gprofng.mpmt.timeline_common.TimelineSelectionCaliperEvent; import org.gprofng.mpmt.timeline_common.TimelineSelectionGenericEvent; import org.gprofng.mpmt.timeline_common.TimelineSelectionHistoryEvent; import org.gprofng.mpmt.timeline_common.TimelineSelectionListener; import org.gprofng.mpmt.toolbar.ToolBarFiller; import org.gprofng.mpmt.toolbar.ToolBarSeparator; import org.gprofng.mpmt.util.gui.AnJPanel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.EventObject; import java.util.List; import java.util.Vector; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.ImageIcon; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSpinner; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; /** * The TL2ControlPanel provides the visual controls for the Chart as well as the code that allows * user interaction with the chart. * * <p>The Panel contains the details display, and a toolbar with color and navigation controls. * * <p>The top level code for zooming panning, selection, and detail display is in ChartControlPanel. */ public class TL2ControlPanel extends AnJPanel implements AnListener, MouseListener, ListSelectionListener, CPToolbarHandler, AnChangeListener { // provided by user private final AnWindow window; private final TimelinePanel timeline; private final AnColorChooser color_chooser; private final StateColorMap clmap; // components private final TL2Drawer tl2_drawer; private final JComponent customComponentsPanel; private final CPToolbar cpToolbar; private final JPanel detailsPanel; // Details Panel top private JPanel detailsTextPanel; private JPanel stackViewPane; // Details Panel private StackView stack_view; // Details Panel private final EventDetails eventDetails; // Details Panel text, layout private CaliperZoom caliperZoom; private SetFilterVisibleTimeRangeOnly setFilterVisibleTimeRangeOnly; private SetFilterSelectedTimeRangeOnly setFilterSelectedTimeRangeOnly; private SetFilterExcludeBefore setFilterExcludeBefore; private SetFilterExcludeAfter setFilterExcludeAfter; private SetFilterSelectedRowsOnly setFilterSelectedRowsOnly; private SetFilterUnselectedRowsOnly setFilterUnselectedRowsOnly; private SetFilterMicrostate setFilterMicrostate; private SetFilterNotMicrostate setFilterNotMicrostate; private RemoveAllFilterAction removeAllFilters; private CustomFilterAction customFilter; private UndoFilterAction undoFilter; private RedoFilterAction redoFilter; private UndoZoomAction undoZoomAction; private RedoZoomAction redoZoomAction; private SelectNextUp selectNextUpAction; private SelectNextDown selectNextDownAction; private SelectNextLeft selectNextLeftAction; private SelectNextRight selectNextRightAction; private SelectFind selectFindAction; private final JComboBox byComboBox; private final JSpinner spinner; // state private boolean stackViewEnabled; /** Creates a new instance of TL2ControlPanel */ public TL2ControlPanel( final AnWindow anWindow, final TimelinePanel timeline, final TL2Drawer tl2_drawer) { super(); cpToolbar = new CPToolbar(this, true, true, true); cpToolbar.add( new ToolBarSeparator(7, 6), null, 12); // FIXUP: hack to insert separator just before color chooser cpToolbar.add(AnWindow.getInstance().getSettingsAction().createActionButton()); // Group Data By drop-down; JLabel groupLabel = new JLabel(AnLocale.getString("Group Data by:")); groupLabel.setDisplayedMnemonic(AnLocale.getString('y', "MN_Timeline_GroupDataby")); groupLabel.setFont(groupLabel.getFont().deriveFont(Font.PLAIN)); groupLabel.setToolTipText(AnLocale.getString("Group data by...")); byComboBox = new JComboBox(); groupLabel.setLabelFor(byComboBox); byComboBox.setFont(byComboBox.getFont().deriveFont(Font.PLAIN)); TimelineSetting.EntityProp entProp; for (int ii = 0; null != (entProp = anWindow.getSettings().getTimelineSetting().getTl_entity_prop(ii)); ii++) { byComboBox.addItem(entProp.prop_uname); } byComboBox.setToolTipText(groupLabel.getToolTipText()); AnUtility.setAccessibleContext(byComboBox.getAccessibleContext(), byComboBox.getToolTipText()); byComboBox.setPreferredSize(new Dimension(byComboBox.getPreferredSize().width, 19)); byComboBox.setMaximumSize(byComboBox.getPreferredSize()); byComboBox.setSelectedIndex( anWindow.getSettings().getTimelineSetting().getTl_entity_selected_btn()); byComboBox.addPopupMenuListener( new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { int index = byComboBox.getSelectedIndex(); window .getSettings() .getTimelineSetting() .setTLGroupDataBySelectedButtonIndex(TL2ControlPanel.this, index); } @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); cpToolbar.add(new ToolBarSeparator(8, 10)); cpToolbar.add(groupLabel); cpToolbar.add(new ToolBarFiller(2)); cpToolbar.add(byComboBox); // Stack Depth if (true) { // YXXXX TBR stuff spinner = null; } else { JLabel spinnerLabel = new JLabel(AnLocale.getString("Stack Depth:")); spinnerLabel.setFont(spinnerLabel.getFont().deriveFont(Font.PLAIN)); spinnerLabel.setToolTipText(AnLocale.getString("Maximum stack depth")); cpToolbar.add(new ToolBarFiller(7)); cpToolbar.add(spinnerLabel); spinner = new JSpinner(); spinner.setBorder(BorderFactory.createLineBorder(new Color(122, 138, 153))); spinner.setToolTipText(AnLocale.getString("Maximum stack depth")); spinner.setValue(anWindow.getSettings().getTimelineSetting().getTLStackDepth()); spinner.addChangeListener( new ChangeListener() { final TL2Drawer drawer = tl2_drawer; @Override public void stateChanged(ChangeEvent e) { Object value = spinner.getValue(); if (value instanceof Integer) { int sd = ((Integer) value).intValue(); if (sd >= 0) { window .getSettings() .getTimelineSetting() .setTLStackDepth(TL2ControlPanel.this, sd); } else { sd = window.getSettings().getTimelineSetting().getTLStackDepth(); spinner.setValue(sd); } } } }); JComponent editor = ((JSpinner.DefaultEditor) spinner.getEditor()); Dimension size = editor.getPreferredSize(); editor.setPreferredSize(new Dimension(20, size.height)); spinner.setPreferredSize(new Dimension(spinner.getPreferredSize().width, 19)); spinner.setMaximumSize(spinner.getPreferredSize()); cpToolbar.add(new ToolBarFiller(2)); cpToolbar.add(spinner); } // this.cpFilterPanel = null; this.timeline = timeline; this.tl2_drawer = tl2_drawer; this.color_chooser = anWindow.getColorChooser(); this.clmap = color_chooser.getColorMap(); this.window = anWindow; this.customComponentsPanel = initializeCustomComponents(); this.detailsPanel = initializeDetailComponents(); // overlaycursor = new Cursor(Cursor.HAND_CURSOR); initializeListeners(timeline); clmap.addAnListener(this); // YXXX leaks this in constructor eventDetails = new EventDetails(anWindow); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("TimelineView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_NEW: case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADED_FAILED: case EXPERIMENTS_LOADED: case FILTER_CHANGED: case FILTER_CHANGING: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SETTING_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGING: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.TIMELINE) { // System.out.println("TL2ControlPanel getOriginalSource: " + // anSettingChangeEvent.getOriginalSource()); if (anSettingChangeEvent.getOriginalSource() == TL2ControlPanel.this) { break; } // System.out.println("TL2ControlPanel getOriginalSource: // doIt..............."); // Update states of Group Data and Stack Depth in control panel List new_tm = (List) anSettingChangeEvent.getNewValue(); int new_entity_button_num = ((Integer) new_tm.get(1)).intValue(); int new_stack_depth = ((Integer) new_tm.get(3)).intValue(); // int new_stack_frame_pixels = ((Integer) new_tm.get(10)).intValue(); updateDataGrouping(new_entity_button_num); updateStackDepth(new_stack_depth); // updateStackFramePixels(new_stack_frame_pixels); } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } private void debug() {} public void edt_resetAll() { resetStackView(); int sd = window.getSettings().getTimelineSetting().getTLStackDepth(); if (spinner != null) { spinner.setValue(sd); // 18294015 workaround; TBR } if (cpToolbar != null) { cpToolbar.setVNumberOfLevels(TimelineDraw.TIMELINE_MAX_VZOOM_LEVEL); cpToolbar.setVZoomLevel(sd); } } // --- allow CP layout to access components public void updateStackDepth(int value) { if (spinner != null) { if (((Integer) spinner.getValue()) != value) { ChangeListener ch = spinner.getChangeListeners()[0]; spinner.removeChangeListener(ch); spinner.setValue(value); spinner.addChangeListener(ch); } } if (cpToolbar != null) { cpToolbar.setVZoomLevel(value); } } public void updateDataGrouping(int index) { if (byComboBox != null) { if (byComboBox.getSelectedIndex() != index) { PopupMenuListener ch = byComboBox.getPopupMenuListeners()[0]; byComboBox.removePopupMenuListener(ch); byComboBox.setSelectedIndex(index); byComboBox.addPopupMenuListener(ch); } } } public JPopupMenu getFilterPopup() { return createPopupMenu(true); } public JComponent getToolbar() { return cpToolbar; } public JComponent getCustomPanel() { return customComponentsPanel; } public JComponent getDetailsPanel() { return detailsPanel; } public JComponent getDetailsTextPanel() { if (detailsTextPanel == null) { detailsTextPanel = new AnJPanel(); } return detailsTextPanel; } public JComponent getStackViewPane() { return stackViewPane; } /** Initialize visual components */ private void initializeListeners(final TimelinePanel timeline) { timeline.addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { // YXXX overkill, nonspecific // book-keeping for zoom revert // cpToolbar.enableRevertButton(true); int tmp; tmp = timeline.getZoomTimeLevelMax(); cpToolbar.setNumberOfLevels(tmp); tmp = timeline.getZoomTimeLevel(); cpToolbar.setZoomLevel(tmp); tmp = TimelineDraw.TIMELINE_MAX_VZOOM_LEVEL; cpToolbar.setVNumberOfLevels(tmp); tmp = window.getSettings().getTimelineSetting().getTLStackDepth(); cpToolbar.setVZoomLevel(tmp); } }); tl2_drawer.addSelectionListener( new TimelineSelectionListener() { @Override public void valueChanged(TimelineSelectionGenericEvent ge) { if (ge instanceof TimelineSelectionHistoryEvent) { TimelineSelectionHistoryEvent e = (TimelineSelectionHistoryEvent) ge; cpToolbar.enableZoomUndoButton(!e.atMin); cpToolbar.enableZoomRedoButton(!e.atMax); undoZoomAction.enableMenuItem(!e.atMin); redoZoomAction.enableMenuItem(!e.atMax); } else if (ge instanceof TimelineSelectionEvent) { TimelineSelectionEvent e = (TimelineSelectionEvent) ge; cpToolbar.enableNavigationButtons(e.left, e.right, e.up, e.down, e.find); setFilterMicrostate.enableMenuItem(e); setFilterNotMicrostate.enableMenuItem(e); enableNavigationMenuItems(e.left, e.right, e.up, e.down, e.find); showStack(e); setDetailText(e); } else if (ge instanceof TimelineSelectionCaliperEvent) { TimelineSelectionCaliperEvent e = (TimelineSelectionCaliperEvent) ge; cpToolbar.enableZoomToCaliperButton(!e.caliper.isSingleEvent()); boolean enableRange = (e.caliper != null && !e.caliper.isSingleEvent()); setFilterSelectedTimeRangeOnly.enableMenuItem(e.caliper != null); setFilterExcludeBefore.enableMenuItem(enableRange); setFilterExcludeAfter.enableMenuItem(enableRange); caliperZoom.enableMenuItem(enableRange); } else if (ge instanceof TimelineSelectionRowEvent) { TimelineSelectionRowEvent event = (TimelineSelectionRowEvent) ge; setFilterSelectedRowsOnly.enableMenuItem(event.rowsSelected); setFilterUnselectedRowsOnly.enableMenuItem(event.rowsSelected); } } }); // mouse modes timeline.setRubberbandIs2D(false); // Init... initNavigationMenuItems(); initFilterMenuItems(); popupListener = new PopupListener(); stackViewPopupListener = stack_view.new StackViewPopupListener(window); timeline.addMouseListener(popupListener); } // --- CPToolbarHandler API --- @Override public void selectFind() { timeline.zoomCenterSelection(); } @Override public void selectFirst() { tl2_drawer.selectFirst(); } @Override public void selectLeft() { tl2_drawer.selectLeft(); } @Override public void selectRight() { tl2_drawer.selectRight(); } @Override public void selectDown() { tl2_drawer.selectDown(); } @Override public void selectUp() { tl2_drawer.selectUp(); } public void selectLeft(boolean ctrl, boolean shift) { tl2_drawer.selectLeft(ctrl, shift); } public void selectRight(boolean ctrl, boolean shift) { tl2_drawer.selectRight(ctrl, shift); } public void selectDown(boolean ctrl, boolean shift) { tl2_drawer.selectDown(ctrl, shift); } public void selectUp(boolean ctrl, boolean shift) { tl2_drawer.selectUp(ctrl, shift); } @Override public void toggleMouseMode() { if (timeline.getMouseMode() == TimelinePanel.MouseDragMode.MOUSE_RUBBERBANDING_MODE) { timeline.setMouseMode(TimelinePanel.MouseDragMode.MOUSE_GRABBING_MODE); } else { timeline.setMouseMode(TimelinePanel.MouseDragMode.MOUSE_RUBBERBANDING_MODE); } } @Override public void zoomToCaliper() { timeline.zoomToCaliper(); } @Override public void genericZoomToLevel(int n) { timeline.zoomTimeToLevel(n); } @Override public void genericZoomIn() { timeline.zoomTimeIn(); } @Override public void genericZoomOut() { timeline.zoomTimeOut(); } @Override public int getZoomLevelMax() { return 20; // YXXX prototype // return timeline.getZoomTimeLevelMax(); } @Override public void genericVZoomToLevel(int n) { // YXXX implement this? timeline.zoomHistoryAdd(); // needed because timeline isn't the owner of these settings window.getSettings().getTimelineSetting().setTLStackDepth(TL2ControlPanel.this, n); cpToolbar.setVZoomLevel(n); // YXXX fixup } @Override public void genericVZoomIn() { timeline.zoomHistoryAdd(); // needed because timeline isn't the owner of these settings int zl = window.getSettings().getTimelineSetting().getTLStackDepth(); zl++; window.getSettings().getTimelineSetting().setTLStackDepth(TL2ControlPanel.this, zl); cpToolbar.setVZoomLevel(zl); // YXXX fixup } @Override public void genericVZoomOut() { timeline.zoomHistoryAdd(); // needed because timeline isn't the owner of these settings int zl = window.getSettings().getTimelineSetting().getTLStackDepth(); zl--; if (zl < 0) { zl = 0; // YXXX fixup } window.getSettings().getTimelineSetting().setTLStackDepth(TL2ControlPanel.this, zl); cpToolbar.setVZoomLevel(zl); // YXXX fixup } @Override public void resetZoom() { timeline.resetZoom(); // updateZoomSliders(); //YXXX remove this let widget update do it } @Override public void undoZoom() { timeline.undoZoom(); } @Override public void redoZoom() { timeline.redoZoom(); } @Override public void chooseColors() { color_chooser.setVisible(true); } /** * Shows Context Menu (reaction on Shift-F10) * * @param ev */ @Override public void showContextMenu(ActionEvent ev) { int id = KeyEvent.VK_F10; long when = 0; // System.currentTimeMillis(); int modifiers = InputEvent.SHIFT_MASK; int x = 120; int y = 40; int clickCount = 1; boolean popupTrigger = true; int button = MouseEvent.BUTTON1; MouseEvent me = null; me = new MouseEvent(timeline, id, when, modifiers, x, y, clickCount, popupTrigger, button); try { popupListener.maybeShowPopup(me); } catch (java.awt.IllegalComponentStateException icse) { // System.out.println("showContextMenu(): " + icse); } } /** Opens "Set Data Presentation" dialog */ public void editProperties(String tabname) { window.getSettings().showDialog(window.getSettings().settingsTimelineIndex); } // --- used by menus --- // Changes timeline time zoom initiated by this class private void zoomTimeToLevel(int level) { timeline.zoomTimeToLevel(level); } // Change timeline process zoom initiated by this class private void zoomProcessToLevel(int level) { timeline.zoomProcessToLevel(level); } /** Initialize timeline specific components */ // called by parent's initializeComponents() private JComponent initializeCustomComponents() { // YXXX uh, supposed to ovverride parent or not? // the component we're going to return JPanel customBoxesPanel = new AnJPanel(); customBoxesPanel.setLayout(new BoxLayout(customBoxesPanel, BoxLayout.Y_AXIS)); // --- YXXX.... // customBoxesPanel.add(limiterPanel); // limiterPanel.revalidate(); customBoxesPanel.revalidate(); // return customBoxesPanel; return null; } /** Initialize component to show details */ private JPanel initializeDetailComponents() { // the component we're going to return: JPanel tmpDetailsPanel = new AnJPanel(); tmpDetailsPanel.setLayout(new BorderLayout()); // tmpDetailsPanel.setBorder( // new TitledBorder(AnLocale.getString("Details"))); // panel for text details detailsTextPanel = (JPanel) getDetailsTextPanel(); detailsTextPanel.registerKeyboardAction( new Analyzer.HelpAction(AnVariable.HELP_TabsSummary), "help", KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); detailsTextPanel.setLayout(new BoxLayout(detailsTextPanel, BoxLayout.Y_AXIS)); // horizontally-constrained scroll pane for detailsTextPanel CPDetailsScrollPane detailsScrollPane = new CPDetailsScrollPane(detailsTextPanel); detailsScrollPane.setBorder(BorderFactory.createEmptyBorder()); // tmpDetailsPanel.add(detailsScrollPane,BorderLayout.NORTH); // ---- call stack // panel for stack_view and stackEnableButton stackViewPane = new FocusPanel(); stackViewPane.setBackground(Color.WHITE); stackViewPane.setVisible(false); // stack component stack_view = new StackView(clmap); stack_view.addMouseListener(this); stack_view.addListSelectionListener(this); // XXXmpview, why is this needed? stackViewEnabled = false; // YXXX selState=null; stackViewPane.revalidate(); tmpDetailsPanel.add(stackViewPane, BorderLayout.CENTER); tmpDetailsPanel.revalidate(); return tmpDetailsPanel; } class FocusPanel extends JPanel { @Override public void requestFocus() { if (stack_view != null) { stack_view.requestFocus(); } } } /** Set the detail text */ void setDetailText(TimelineSelectionEvent evt) { JPanel tmpPanel; JLabel lbl; final String title; if (evt == null) { title = AnLocale.getString("Nothing Selected"); lbl = new JLabel(AnLocale.getString("Nothing selected")); tmpPanel = new AnJPanel(); tmpPanel.add(lbl); } else { title = AnLocale.getString("Timelinexx"); tmpPanel = eventDetails.setEvent(evt); } tmpPanel.revalidate(); detailsTextPanel.removeAll(); detailsTextPanel.add(tmpPanel); detailsTextPanel.revalidate(); detailsTextPanel.repaint(); } private void loadStacks() { // mpi_drawer.getProvider().loadStacks(); // FunctionDetail fdet = new FunctionDetail(selState); // long stackId=fdet.getStackId(); // YXXX showStack(stackId); } private void enableStackView() { // hide stackViewPane until data is ready stackViewPane.setVisible(false); stackViewPane.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(2, 2, 2, 2); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weighty = 1.0; gridBagConstraints.weightx = 1.0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; stackViewPane.add(stack_view, gridBagConstraints); stackViewPane.revalidate(); stackViewPane.repaint(); stackViewEnabled = true; } private void showStack(TimelineSelectionEvent e) { final long stack_id = (e == null) ? DetailsIPC.INVALID_STACK_ID : e.stackId; if (stack_id == DetailsIPC.INVALID_STACK_ID) { // hide stackview panel stackViewPane.setVisible(false); } else if (e.eventDetail == null) { // hide stackview panel stackViewPane.setVisible(false); } else if (stack_id == 0) { // we would show stacks, but stack ID is not known if (!stackViewEnabled) { // show user button that loads stack data stackViewPane.setVisible(true); } else { // no stack for this function stackViewPane.setVisible(false); } } else { // valid stack_id if (!stackViewEnabled) { // some other tab must have loaded stacks for us enableStackView(); } updateStackView(e); stackViewPane.setVisible(true); } stackViewPane.revalidate(); } public void resetStackView() { if (stack_view != null) { stack_view.reset(); } } private static int desiredDistFromRoot = -1; private void updateStackView(final TimelineSelectionEvent e) { Vector<StackState> state_vec = (e == null) ? null : e.getStackFrames(); if (state_vec == null || state_vec.isEmpty()) { stack_view.reset(); return; } // stack_view(0) is leaf frame int prevSelIdx = stack_view.getLeadSelectionIndex(); if (stack_view.isSelectionEmpty()) { prevSelIdx = -1; } else { prevSelIdx = stack_view.getLeadSelectionIndex(); } final int prevMax = stack_view.getModel().getSize() - 1; // try to determine whether or not to change savedDistFromRoot if (prevSelIdx == -1) { // do nothing } else { int prevDistFromRoot = prevMax - prevSelIdx; if (prevDistFromRoot != desiredDistFromRoot) { // user probably made a selection if (prevSelIdx == 0) { desiredDistFromRoot = -1; // assume they want leaf to show } else { desiredDistFromRoot = prevDistFromRoot; // set new desired distance } } } // try to apply new desired to current stack final int selIndex; do { if (desiredDistFromRoot == -1) { selIndex = -1; // deselect and show leaf break; } final int newMax = state_vec.size() - 1; if (desiredDistFromRoot > newMax) { selIndex = -1; // deselect and show leaf break; } selIndex = newMax - desiredDistFromRoot; } while (false); clmap.addStates(state_vec); stack_view.setStates(state_vec, selIndex); // update stack in right-hand tab stack_view.setStackId(e.stackId); AnWindow.getInstance().setSubviewReadyToShow("timelineCallStackSubview", true); } // color change(s) @Override public void valueChanged(AnEvent e) { stack_view.repaint(); timeline.repaint(); } // Set selected function private void updateSummary(final StackState tmpstate) { final long sel_func; final long sel_pc; if (!(tmpstate instanceof StackViewState)) { System.err.println("XXXmpview timelistdisp: not StackViewState"); return; } StackViewState state = (StackViewState) tmpstate; sel_func = state.getNumber(); sel_pc = state.getPC(); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { long sel_obj = window.getSelectedObject().getObject(sel_func, sel_pc); // IPC! if (sel_obj != 0L) { window.getSelectedObject().setSelObj(sel_obj, AnDisplay.DSP_Timeline, 0); // window.getSelectionManager().updateSelection(sel_obj, // AnDisplay.DSP_TIMELINE, 0, 1); AnWindow.getInstance() .getViews() .getCurrentViewDisplay() .computeOnAWorkerThread(); // Update selection. FIXUP: Views that react on // selections should change selction on // SELECTION_CHANGED or SELECTED_OBJECT_CHANGED events // if not from own view } } }, "Timelinecontrol update summary"); } // The function selected has changed either by clicking inside the callstack // on the right or by clicking on an event in timeline // (MUST BE CALLED ON AWT THREAD) private void funcSelChanged(EventObject event) { final JList list; StackState state = null; // window.setSelectedInfoTab(eventPane); // TimelineDisp's eventPane if (event instanceof MouseEvent) { if (color_chooser.isVisible()) { color_chooser.setVisible(true); } if (((MouseEvent) event).getClickCount() > 1) { window.setSelectedView(AnDisplay.DSP_Source); } } else { if (color_chooser.isVisible()) { color_chooser.setVisible(true); } } // StackView or ChooserStateList if (event.getSource() instanceof StackView) { list = stack_view; state = (StackState) list.getSelectedValue(); } else { // XXXmpview, figure this out... // System.err.println("XXXmpview MPItimelistdisp: eventsource unknown"); return; } if (state == null) { return; } stack_view.setSelectedFunction(state.getNumber()); // XXXmpview may be redundant color_chooser.setSelectedFunction(state.getNumber()); updateSummary(state); } @Override public void mouseClicked(final MouseEvent event) { if (SwingUtilities.isLeftMouseButton(event)) { funcSelChanged(event); } if (SwingUtilities.isRightMouseButton(event)) { stackViewPopupListener.maybeShowPopup(event); } return; } @Override public void mouseEntered(final MouseEvent event) {} @Override public void mouseExited(final MouseEvent event) {} @Override public void mousePressed(final MouseEvent event) {} @Override public void mouseReleased(final MouseEvent event) {} @Override public void valueChanged(final ListSelectionEvent event) { // Handles selection changes to RHS Callstack made via keyboard funcSelChanged( event); // YXXX unfortunately also picks up new stack selections and causes selected object // to change } // ---------- Context menu ---------- // // private JPopupMenu popup; private JMenuItem menuItemZoomHD; private JMenuItem menuItemScrollHL, menuItemScrollHR, menuItemScrollHPL, menuItemScrollHPR; private JMenuItem menuItemScrollVU, menuItemScorllVD; private PopupListener popupListener; private StackView.StackViewPopupListener stackViewPopupListener; // ------- Private classes and methods to implement popup menu items ------- // private void enableNavigationMenuItems( boolean left, boolean right, boolean up, boolean down, boolean center) { selectNextLeftAction.enableMenuItem(left); selectNextRightAction.enableMenuItem(right); selectNextUpAction.enableMenuItem(up); selectNextDownAction.enableMenuItem(down); selectFindAction.enableMenuItem(center); } private void enableZoomMenuItems(boolean hasHZoom, boolean hasVZoom) { if (menuItemZoomHD == null) { return; } menuItemZoomHD.setEnabled(hasHZoom); menuItemScrollHL.setEnabled(hasHZoom); menuItemScrollHR.setEnabled(hasHZoom); menuItemScrollHPL.setEnabled(hasHZoom); menuItemScrollHPR.setEnabled(hasHZoom); menuItemScrollVU.setEnabled(hasVZoom); menuItemScorllVD.setEnabled(hasVZoom); } private class PopupListener extends MouseAdapter implements ActionListener, PopupMenuListener { PopupListener() {} @Override public void mousePressed(MouseEvent e) { maybeShowPopup(e); } // public void mouseReleased(MouseEvent e) { // maybeShowPopup(e); // } /** * Shows context menu * * @param MouseEvent e */ private void maybeShowPopup(MouseEvent e) { // On Windows e.isPopupTrigger() returns false, so we have to apply a workaround if (e.isPopupTrigger() || ((System.getProperty("os.name").contains("Windows")) && (e.getButton() == 3))) { boolean hasHZoom = (tl2_drawer.getAbsoluteTimeDuration() != tl2_drawer.getTimeAxisReader().getTimeDuration()); boolean hasVZoom = (tl2_drawer.getAbsoluteRowCount() != tl2_drawer.getDataAxisReader().getRowCount()); enableZoomMenuItems(hasHZoom, hasVZoom); JPopupMenu popup = createPopupMenu(false); popup.show(e.getComponent(), e.getX(), e.getY()); } } @Override public void actionPerformed(ActionEvent ev) {} @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuCanceled(PopupMenuEvent e) {} } /** * Creates popup menu Menu items: ---------------- Change Colors ---------------- Select Event -> * -> Select First -> Right -> Left -> Up -> Down -> Center Selection ---------------- Zoom -> -> * Increase -> Decrease -> Reset -> Previous (Back) ---------------- Scroll -> -> Center Selection * -> Right -> Left -> Up -> Down -> Page Right -> Page Left -> Previous (Back) ---------------- * Add Filter: Include only events from visible time range Add Filter: Include only events from * selected time to end Add Filter: Include only events from beginning to selected time Add * Filter: Include only selected rows Add Filter: Include only unselected rows Remove All Filters * Manage Filters... ---------------- Properties ---------------- * * <p>Returns PopupListener */ private final int menuModifier = 0; // was ActionEvent.ALT_MASK; private JMenu newEventSelectSubMenu() { JMenu submenu1; JMenuItem menuItem; { // Add Select Next submenu submenu1 = new JMenu(AnLocale.getString("Select Event")); menuItem = selectNextUpAction.jmi; menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_KP_UP, menuModifier)); submenu1.add(menuItem); menuItem = selectNextDownAction.jmi; menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, menuModifier)); submenu1.add(menuItem); menuItem = selectNextLeftAction.jmi; menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, menuModifier)); submenu1.add(menuItem); menuItem = selectNextRightAction.jmi; menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_KP_RIGHT, menuModifier)); submenu1.add(menuItem); menuItem = new JMenuItem(new SelectFirst()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_HOME, menuModifier)); submenu1.add(menuItem); } return submenu1; } private JMenu newZoomSubMenu() { JMenu submenu1; JMenuItem menuItem; { // Add Zoom submenu submenu1 = new JMenu(AnLocale.getString("Zoom")); // Add Horizontal Zoom submenu submenu1.add(caliperZoom.jmi); // enabled dynamically // Zoom Undo/Redo/Reset menuItem = undoZoomAction.jmi; menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, menuModifier)); submenu1.add(menuItem); menuItem = redoZoomAction.jmi; menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, ActionEvent.SHIFT_MASK)); submenu1.add(menuItem); menuItem = new JMenuItem(new ResetHorizontalZoom()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_0, menuModifier)); submenu1.add(menuItem); // Zoom Increase/Descrease menuItem = new JMenuItem(new IncreaseHorizontalZoom()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, menuModifier)); submenu1.add(menuItem); menuItem = menuItemZoomHD = new JMenuItem(new DecreaseHorizontalZoom()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, menuModifier)); submenu1.add(menuItem); menuItem = new JMenuItem(new IncreaseVerticalZoom()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_PLUS, ActionEvent.CTRL_MASK)); submenu1.add(menuItem); menuItem = menuItemZoomHD = new JMenuItem(new DecreaseVerticalZoom()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, ActionEvent.CTRL_MASK)); submenu1.add(menuItem); } return submenu1; } private JMenu newFindSubMenu() { JMenu submenu1; JMenuItem menuItem; { // Add Scroll submenu submenu1 = new JMenu(AnLocale.getString("Find")); menuItem = selectFindAction.jmi; menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, menuModifier)); submenu1.add(menuItem); menuItem = new JMenuItem(new findTimeMarker()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.SHIFT_MASK)); submenu1.add(menuItem); } return submenu1; } private JMenu newScrollSubMenu() { JMenu submenu1; JMenuItem menuItem; { // Add Scroll submenu submenu1 = new JMenu(AnLocale.getString("Scroll")); menuItem = menuItemScrollVU = new JMenuItem(new ScrollVerticalUp()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_MASK)); submenu1.add(menuItem); menuItem = menuItemScorllVD = new JMenuItem(new ScrollVerticalDown()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_MASK)); submenu1.add(menuItem); menuItem = menuItemScrollHL = new JMenuItem(new ScrollHorizontalLeft()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.CTRL_MASK)); submenu1.add(menuItem); menuItem = menuItemScrollHR = new JMenuItem(new ScrollHorizontalRight()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.CTRL_MASK)); submenu1.add(menuItem); menuItem = menuItemScrollHPL = new JMenuItem(new ScrollHorizontalPageLeft()); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK)); submenu1.add(menuItem); menuItem = menuItemScrollHPR = new JMenuItem(new ScrollHorizontalPageRight()); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK)); submenu1.add(menuItem); } return submenu1; } private JMenu newTimeRangeSubMenu() { JMenu submenu1; JMenuItem menuItem; { // add select tiime range items submenu1 = new JMenu(AnLocale.getString("Select Time Range")); menuItem = new JMenuItem(new SetTimeMarker()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SLASH, menuModifier)); submenu1.add(menuItem); menuItem = new JMenuItem(new MoveTimeMarkerLeft()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, menuModifier)); submenu1.add(menuItem); menuItem = new JMenuItem(new MoveTimeMarkerRight()); menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_CLOSE_BRACKET, menuModifier)); submenu1.add(menuItem); menuItem = new JMenuItem(new MoveTimeMarkerRangeLeft()); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_MASK)); submenu1.add(menuItem); menuItem = new JMenuItem(new MoveTimeMarkerRangeRight()); menuItem.setAccelerator( KeyStroke.getKeyStroke(KeyEvent.VK_CLOSE_BRACKET, InputEvent.SHIFT_MASK)); submenu1.add(menuItem); } return submenu1; } private JPopupMenu createPopupMenu(boolean filterOnly) { JMenu submenu1; JMenuItem menuItem; JPopupMenu popup = new JPopupMenu(); if (!filterOnly) { // popup.add(caliperZoom.jmi); // enabled dynamically popup.add(newZoomSubMenu()); popup.addSeparator(); } popup.add(setFilterSelectedTimeRangeOnly.jmi); popup.add(setFilterExcludeBefore.jmi); popup.add(setFilterExcludeAfter.jmi); popup.add(setFilterVisibleTimeRangeOnly.jmi); popup.add(setFilterSelectedRowsOnly.jmi); popup.add(setFilterUnselectedRowsOnly.jmi); submenu1 = new JMenu(AnLocale.getString("Additional Filters")); submenu1.add(setFilterMicrostate.jmi); submenu1.add(setFilterNotMicrostate.jmi); submenu1.add(customFilter.jmi); popup.add(submenu1); if (filterOnly) { popup.addSeparator(); } undoFilter.jmi.setEnabled(window.getFilters().canUndoLastFilter()); popup.add(undoFilter.jmi); redoFilter.jmi.setEnabled(window.getFilters().canRedoLastFilter()); popup.add(redoFilter.jmi); removeAllFilters.jmi.setEnabled(window.getFilters().canRemoveAllFilters()); popup.add(removeAllFilters.jmi); // Add "Remove Filter" action if (window.getFilters().anyFilters()) { popup.add(window.getFilters().removeFilterMenuItem()); } if (!filterOnly) { popup.addSeparator(); { menuItem = new JMenuItem(new ChangeColors()); menuItem.setAccelerator(KeyboardShortcuts.functionColorsActionShortcut); JMenuItem colorSubmenu = menuItem; popup.add(colorSubmenu); } popup.addSeparator(); popup.add(newFindSubMenu()); popup.add(newEventSelectSubMenu()); popup.add(newTimeRangeSubMenu()); popup.add(newScrollSubMenu()); popup.addSeparator(); // Add menu it em Properties menuItem = new JMenuItem(new ChangeDataPresentation()); menuItem.setAccelerator(KeyboardShortcuts.settingsActionShortcut); popup.add(menuItem); // popup.addSeparator(); } return popup; } private void initNavigationMenuItems() { JMenuItem menuItem; undoZoomAction = new UndoZoomAction(); menuItem = new JMenuItem(undoZoomAction); undoZoomAction.jmi = menuItem; menuItem.setEnabled(false); redoZoomAction = new RedoZoomAction(); menuItem = new JMenuItem(redoZoomAction); redoZoomAction.jmi = menuItem; menuItem.setEnabled(false); selectNextUpAction = new SelectNextUp(); menuItem = new JMenuItem(selectNextUpAction); selectNextUpAction.jmi = menuItem; menuItem.setEnabled(false); selectNextDownAction = new SelectNextDown(); menuItem = new JMenuItem(selectNextDownAction); selectNextDownAction.jmi = menuItem; menuItem.setEnabled(false); selectNextLeftAction = new SelectNextLeft(); menuItem = new JMenuItem(selectNextLeftAction); selectNextLeftAction.jmi = menuItem; menuItem.setEnabled(false); selectNextRightAction = new SelectNextRight(); menuItem = new JMenuItem(selectNextRightAction); selectNextRightAction.jmi = menuItem; menuItem.setEnabled(false); selectFindAction = new SelectFind(); menuItem = new JMenuItem(selectFindAction); selectFindAction.jmi = menuItem; menuItem.setEnabled(false); enableNavigationMenuItems(false, false, false, false, false); } private void initFilterMenuItems() { JMenuItem menuItem; TimelineCaliper caliper = timeline.getCaliperClone(); final boolean enableSelFilters = (caliper != null); caliperZoom = new CaliperZoom(); menuItem = new JMenuItem(caliperZoom); caliperZoom.jmi = menuItem; menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0)); menuItem.setEnabled(enableSelFilters && !caliper.isSingleEvent()); setFilterVisibleTimeRangeOnly = new SetFilterVisibleTimeRangeOnly(); menuItem = new JMenuItem(setFilterVisibleTimeRangeOnly); setFilterVisibleTimeRangeOnly.jmi = menuItem; menuItem.setEnabled(true); setFilterSelectedTimeRangeOnly = new SetFilterSelectedTimeRangeOnly(); menuItem = new JMenuItem(setFilterSelectedTimeRangeOnly); setFilterSelectedTimeRangeOnly.jmi = menuItem; menuItem.setEnabled(enableSelFilters && !caliper.isSingleEvent()); setFilterExcludeAfter = new SetFilterExcludeAfter(); menuItem = new JMenuItem(setFilterExcludeAfter); setFilterExcludeAfter.jmi = menuItem; menuItem.setEnabled(enableSelFilters); setFilterExcludeBefore = new SetFilterExcludeBefore(); menuItem = new JMenuItem(setFilterExcludeBefore); setFilterExcludeBefore.jmi = menuItem; menuItem.setEnabled(enableSelFilters); final boolean hasRowSelections = (tl2_drawer.getRowBlockSelectList() != null && !tl2_drawer.getRowBlockSelectList().isEmpty()); setFilterSelectedRowsOnly = new SetFilterSelectedRowsOnly(); menuItem = new JMenuItem(setFilterSelectedRowsOnly); setFilterSelectedRowsOnly.jmi = menuItem; menuItem.setEnabled(hasRowSelections); setFilterUnselectedRowsOnly = new SetFilterUnselectedRowsOnly(); menuItem = new JMenuItem(setFilterUnselectedRowsOnly); setFilterUnselectedRowsOnly.jmi = menuItem; menuItem.setEnabled(hasRowSelections); setFilterMicrostate = new SetFilterMicrostate(); menuItem = new JMenuItem(setFilterMicrostate); setFilterMicrostate.jmi = menuItem; menuItem.setEnabled(false); setFilterNotMicrostate = new SetFilterNotMicrostate(); menuItem = new JMenuItem(setFilterNotMicrostate); setFilterNotMicrostate.jmi = menuItem; menuItem.setEnabled(false); customFilter = new CustomFilterAction("Advanced Custom Filter..."); menuItem = new JMenuItem(customFilter); customFilter.jmi = menuItem; menuItem.setEnabled(true); undoFilter = new UndoFilterAction(); menuItem = new JMenuItem(undoFilter); undoFilter.jmi = menuItem; menuItem.setEnabled(window.getFilters().canUndoLastFilter()); redoFilter = new RedoFilterAction(); menuItem = new JMenuItem(redoFilter); redoFilter.jmi = menuItem; menuItem.setEnabled(window.getFilters().canRedoLastFilter()); removeAllFilters = new RemoveAllFilterAction(); menuItem = new JMenuItem(removeAllFilters); removeAllFilters.jmi = menuItem; menuItem.setEnabled(window.getFilters().canRemoveAllFilters()); } class ContextMenuAction extends AbstractAction { final String name = AnLocale.getString("Context Menu"); int id = KeyEvent.VK_F10; long when = 0; // System.currentTimeMillis(); int modifiers = InputEvent.SHIFT_MASK; int x = 40; int y = 40; int clickCount = 1; boolean popupTrigger = true; int button = MouseEvent.BUTTON1; MouseEvent me = null; public ContextMenuAction() { super(AnLocale.getString("Context Menu"), null /* new ImageIcon("refresh.jpg") */); // A11YXXX : this is a hack, but I don't see a better way for now me = new MouseEvent(timeline, id, when, modifiers, x, y, clickCount, popupTrigger, button); } @Override public void actionPerformed(ActionEvent ev) { try { popupListener.maybeShowPopup(me); } catch (java.awt.IllegalComponentStateException icse) { // System.out.println("ContextMenuAction.ActionPerformed(): " + icse); } } } /** Implements menu item: Zoom -> -> Horizontal -> -> Increase */ class CaliperZoom extends AbstractAction { public JMenuItem jmi = null; public CaliperZoom() { super(AnLocale.getString("Zoom to Selected Time Range"), AnUtility.mtall_icon); } public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { zoomToCaliper(); } } class IncreaseHorizontalZoom extends AbstractAction { public IncreaseHorizontalZoom() { super(AnLocale.getString("Increase Time Zoom"), null); } @Override public void actionPerformed(ActionEvent ev) { genericZoomIn(); } } class DecreaseHorizontalZoom extends AbstractAction { public DecreaseHorizontalZoom() { super(AnLocale.getString("Decrease Time Zoom"), null); } @Override public void actionPerformed(ActionEvent ev) { genericZoomOut(); } } class IncreaseVerticalZoom extends AbstractAction { public IncreaseVerticalZoom() { super(AnLocale.getString("Increase Vertical Zoom"), null); } @Override public void actionPerformed(ActionEvent ev) { genericVZoomIn(); } } class DecreaseVerticalZoom extends AbstractAction { public DecreaseVerticalZoom() { super(AnLocale.getString("Decrease Vertical Zoom"), null); } @Override public void actionPerformed(ActionEvent ev) { genericVZoomOut(); } } /** Implements menu item: Zoom -> -> Horizontal -> -> Reset */ class ResetHorizontalZoom extends AbstractAction { public ResetHorizontalZoom() { super(AnLocale.getString("Reset Time Zoom"), null); } @Override public void actionPerformed(ActionEvent ev) { zoomTimeToLevel(0); } } /** Implements menu item: Zoom -> -> Previous (Back) */ class UndoZoomAction extends AbstractAction { public UndoZoomAction() { super(AnLocale.getString("Undo Zoom Action"), AnUtility.undo_icon); } public JMenuItem jmi = null; public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { undoZoom(); } } class RedoZoomAction extends AbstractAction { public RedoZoomAction() { super(AnLocale.getString("Redo Zoom Action"), AnUtility.redo_icon); } public JMenuItem jmi = null; public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { redoZoom(); } } // -------------- Change Colors ---------------- // /** Implements menu item: Change Colors */ class ChangeColors extends AbstractAction { public ChangeColors() { super(AnLocale.getString("Function Colors..."), AnUtility.colr_icon); } @Override public void actionPerformed(ActionEvent ev) { chooseColors(); } } // -------------- Properties ---------------- // /** Implements menu item: Properties */ class ChangeDataPresentation extends AbstractAction { public ChangeDataPresentation() { super(AnLocale.getString("Timeline Settings"), AnUtility.gear_icon); } @Override public void actionPerformed(ActionEvent ev) { editProperties(AnLocale.getString("Timeline")); } } private static final String ADD_FILTER = AnLocale.getString("Add Filter: "); private static final String VISIBLE_RANGE_SHORT_NAME = AnLocale.getString("Visible Range"); private static final String VISIBLE_RANGE_LONG_NAME = AnLocale.getString("Include only events intersecting visible time range"); private static final String SELECTED_RANGE_SHORT_NAME = AnLocale.getString("Intersecting Time Range"); private static final String SELECTED_RANGE_LONG_NAME = AnLocale.getString("Include only events intersecting selected time range"); private static final String EXCLUDE_BEFORE_SHORT_NAME = AnLocale.getString("Starting in Range"); private static final String EXCLUDE_BEFORE_LONG_NAME = AnLocale.getString("Include only events starting in selected time range"); private static final String EXCLUDE_AFTER_SHORT_NAME = AnLocale.getString("Ending in Range"); private static final String EXCLUDE_AFTER_LONG_NAME = AnLocale.getString("Include only events ending in selected time range"); private static final String SELECTED_ROWS_SHORT_NAME = AnLocale.getString("Selected Rows"); private static final String SELECTED_ROWS_LONG_NAME = AnLocale.getString("Include only selected rows"); private static final String UNSELECTED_ROWS_SHORT_NAME = AnLocale.getString("Unselected Rows"); private static final String UNSELECTED_ROWS_LONG_NAME = AnLocale.getString("Include only unselected rows"); private static final String WITH_MSTATE_SHORT_NAME = AnLocale.getString("Thread State"); private static final String WITH_MSTATE_LONG_NAME = AnLocale.getString("Include only events having the selected event's thread state"); private static final String NOT_MSTATE_SHORT_NAME = AnLocale.getString("Not Thread State"); private static final String NOT_MSTATE_LONG_NAME = AnLocale.getString("Include only events not having the selected event's thread state"); private String getSelectedViewDisplayName() { String ret = "Timeline"; // fallback if (window != null) { ret = window.getSelectedView().getDisplayName(); } return ret; } private void setClause(String shortName, String longName, String clause) { window .getFilters() .addClause( getSelectedViewDisplayName() + ": " + shortName, longName, clause, FilterClause.Kind.STANDARD); } // -------------- visible time range ---------------- // /** Implements menu item: Set Filter: visible time range */ class SetFilterVisibleTimeRangeOnly extends AbstractAction { public JMenuItem jmi = null; public SetFilterVisibleTimeRangeOnly() { super(ADD_FILTER + VISIBLE_RANGE_LONG_NAME /*, AnUtility.filtclause_icon*/); } @Override public void actionPerformed(ActionEvent ev) { long start = tl2_drawer.getTimeAxisReader().getTimeStart(); long end = tl2_drawer.getTimeAxisReader().getTimeEnd(); String clause = "!( (TSTAMP_HI < " + start + ") || (TSTAMP_LO > " + end + ") )"; // window.filter.showDialog(); // Show "Set Filter" dialog // window.filter.setSelectedTab(1); // Select advanced filter tab setClause( VISIBLE_RANGE_SHORT_NAME, VISIBLE_RANGE_LONG_NAME, clause); // Put the string in the text field } } /** Implements menu item: Set Filter: selected time range */ class SetFilterSelectedTimeRangeOnly extends AbstractAction { public JMenuItem jmi = null; public SetFilterSelectedTimeRangeOnly() { super(ADD_FILTER + SELECTED_RANGE_LONG_NAME /*, AnUtility.filtclause_icon*/); } public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { TimelineCaliper caliper = timeline.getCaliperClone(); if (caliper == null) { return; } final long start = caliper.getLowTime(); final long end = caliper.getHighTime(); String clause = "!( (TSTAMP_HI < " + start + ") || (TSTAMP_LO > " + end + ") )"; // window.filter.showDialog(); // Show "Set Filter" dialog // window.filter.setSelectedTab(1); // Select advanced filter tab setClause( SELECTED_RANGE_SHORT_NAME, SELECTED_RANGE_LONG_NAME, clause); // Put the string in the text field } } // -------------- exclude before ---------------- // /** Implements menu item: Set Filter: exclude before */ class SetFilterExcludeBefore extends AbstractAction { public JMenuItem jmi = null; public SetFilterExcludeBefore() { super(ADD_FILTER + EXCLUDE_BEFORE_LONG_NAME /*, AnUtility.filtclause_icon*/); } public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { TimelineCaliper caliper = timeline.getCaliperClone(); if (caliper == null) { return; } final long start = caliper.getLowTime(); final long end = caliper.getHighTime(); String clause = "( (TSTAMP_LO >= " + start + ") && (TSTAMP_LO <= " + end + ") )"; // window.filter.showDialog(); // Show "Set Filter" dialog // window.filter.setSelectedTab(1); // Select advanced filter tab setClause( EXCLUDE_BEFORE_SHORT_NAME, EXCLUDE_BEFORE_LONG_NAME, clause); // Put the string in the text field } } // -------------- exclude after ---------------- // /** Implements menu item: Set Filter: exclude after */ class SetFilterExcludeAfter extends AbstractAction { public JMenuItem jmi = null; public SetFilterExcludeAfter() { super(ADD_FILTER + EXCLUDE_AFTER_LONG_NAME /*, AnUtility.filtclause_icon*/); } public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { TimelineCaliper caliper = timeline.getCaliperClone(); if (caliper == null) { return; } final long start = caliper.getLowTime(); final long end = caliper.getHighTime(); String clause = "( (TSTAMP_HI >= " + start + ") && (TSTAMP_HI <= " + end + ") )"; // window.filter.showDialog(); // Show "Set Filter" dialog // window.filter.setSelectedTab(1); // Select advanced filter tab setClause( EXCLUDE_AFTER_SHORT_NAME, EXCLUDE_AFTER_LONG_NAME, clause); // Put the string in the text field } } // -------------- only selected rows ---------------- // /** Implements menu item: Set Filter: only selected rows */ class SetFilterSelectedRowsOnly extends AbstractAction { public JMenuItem jmi = null; public SetFilterSelectedRowsOnly() { super(ADD_FILTER + SELECTED_ROWS_LONG_NAME /*, AnUtility.filtclause_icon*/); } public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { String clause = getSelRowsFilterClause(false); if (clause.length() != 0) { setClause(SELECTED_ROWS_SHORT_NAME, SELECTED_ROWS_LONG_NAME, clause); } // Put the string in the text field } } // -------------- only unselected rows ---------------- // /** Implements menu item: Set Filter: only unselected rows */ class SetFilterUnselectedRowsOnly extends AbstractAction { public JMenuItem jmi = null; public SetFilterUnselectedRowsOnly() { super(ADD_FILTER + UNSELECTED_ROWS_LONG_NAME /*, AnUtility.filtclause_icon*/); } public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { String clause = getSelRowsFilterClause(true); if (clause.length() != 0) { setClause(UNSELECTED_ROWS_SHORT_NAME, UNSELECTED_ROWS_LONG_NAME, clause); } // Put the string in the text field } } private String getSelRowsFilterClause(boolean invert) { // Rules for generating row filter string: // if "group-by" is experiments // filter by expid // else if (experiment master row selected) // if (no subrows or all subrows selected) // filter by expid // else // filter by selected subrows // else // filter by selected subrows // // This has special implications for Java: // Example 1: // filter by experiment two's master row and all user-mode threads // Result: "EXPID==2" // Switching to Machine Mode will show User and JVM threads // // Example 2: // filter by experiment two's user-mode threads *without* master row // Result: "EXPID==2 && THRID IN (...)" // Switching to Machine Mode will show only User Mode threads // // // Note: this function does not look at EXPGRID // It also assumes that a given EXPID's blocks are contiguous // (rows from one EXPID won't be interleaved with rows from some other EXPID) // List<Integer> blockSelList = tl2_drawer.getRowBlockSelectList(); int nSelBlocks = blockSelList.size(); if (nSelBlocks == 0) { return ""; } List<EntityDefinitions> rowBlocks = tl2_drawer.getRowDefsByBlock(); if (rowBlocks == null) { return ""; // data is in transition } int prevUserExpId = -1; // invalid value final String clauseInit = "( "; String clause = clauseInit; boolean experimentMasterRowSelected = false; boolean entIsExpid = false; String entPropIdName = null; final List<Integer> entityIds = new ArrayList(); final List<Integer> expIdList = new ArrayList(); for (int jj = 0; jj <= nSelBlocks /*one extra!*/; jj++) { final RowDefinition rowDef0; final int userExpId; if (jj < nSelBlocks) { int blockNum = blockSelList.get(jj); if (blockNum < 0 || blockNum >= rowBlocks.size()) { return ""; // weird } EntityDefinitions rowDefs = rowBlocks.get(blockNum); rowDef0 = rowDefs.entityRows.get(0); userExpId = rowDef0.getUserExpID(); } else { rowDef0 = null; userExpId = -2; } if (jj == nSelBlocks || (jj > 0 && prevUserExpId != userExpId)) { // wrap up previous block boolean filterExclusivelyByExpid = false; if (entIsExpid) { // Group By Experiment filterExclusivelyByExpid = true; } else if (experimentMasterRowSelected) { if (entityIds.isEmpty()) { // Only Experiment master row selected filterExclusivelyByExpid = true; } else { ExperimentDefinitions tmp = tl2_drawer.event_drawer.getDataSnapshot().getExperimentDefinitions(prevUserExpId); if (tmp != null) { int numEntities = tmp.experimentEntities.size(); if (numEntities - 1 == entityIds.size()) { // Master and all subrows selected filterExclusivelyByExpid = true; } } else { int kk = -1; // weird } } } if (filterExclusivelyByExpid) { // Only Experiment master row selected: filter exclusively by EXPID expIdList.add(prevUserExpId); } else { // generate a filter for selected entities (e.g. THRID) if (!clause.equals(clauseInit)) { clause += " || "; } clause += "( EXPID==" + prevUserExpId + " && "; if (invert) { clause += "!"; expIdList.add(prevUserExpId); } boolean propListStarted = false; for (Integer entId : entityIds) { if (!propListStarted) { clause += "( " + entPropIdName + " IN ("; } else { clause += ","; } clause += entId; propListStarted = true; } clause += ") ) )"; } experimentMasterRowSelected = false; entIsExpid = false; entPropIdName = null; entityIds.clear(); } if (rowDef0 != null) { prevUserExpId = userExpId; Entity ent0 = rowDef0.getEntity(); String tmpEntPropIdName = ent0.getPropIdName(); if (tmpEntPropIdName.equalsIgnoreCase("EXPID")) { // no properties are needed for Experiment grouping entIsExpid = true; } else if (ent0.getPropId() == Settings.PROP_NONE) { // for rows that don't have an entity, like samples experimentMasterRowSelected = true; } else { int entId = ent0.getPropValue(); if (entPropIdName == null) { entPropIdName = tmpEntPropIdName; } else if (!entPropIdName.equalsIgnoreCase(tmpEntPropIdName)) { int kk = 0; // weird! } entityIds.add(entId); } } } if (!expIdList.isEmpty()) { // now generate the 'simple' EXPID filters if (!clause.equals(clauseInit)) { clause += " || "; } if (invert) { clause += " !"; } boolean firstTime = true; for (Integer tmpExpId : expIdList) { if (firstTime) { clause += "( EXPID in (" + tmpExpId; firstTime = false; } else { clause += "," + tmpExpId; } } clause += ") )"; } clause += " )"; return clause; } // -------------- from beginning to selected time ---------------- // /** Implements menu item: Set Filter: from beginning to selected time */ class SetFilterMicrostate extends AbstractAction { public JMenuItem jmi = null; private int stateValue = -1; public SetFilterMicrostate() { super(/*ADD_FILTER +*/ WITH_MSTATE_LONG_NAME /*, AnUtility.filtclause_icon*/); } public void enableMenuItem(TimelineSelectionEvent selEvent) { boolean enabled; if (selEvent != null && selEvent.eventDetail != null && selEvent.eventDetail instanceof ProfileEvent) { enabled = true; ProfileEvent pEvent = (ProfileEvent) selEvent.eventDetail; stateValue = pEvent.getState(); } else { enabled = false; stateValue = -1; } if (null != jmi) { jmi.setEnabled(enabled); } } @Override public void actionPerformed(ActionEvent ev) { String clause = "(MSTATE == " + stateValue + ")"; setClause( WITH_MSTATE_SHORT_NAME, WITH_MSTATE_LONG_NAME, clause); // Put the string in the text field } } // -------------- from beginning to selected time ---------------- // /** Implements menu item: Set Filter: from beginning to selected time */ class SetFilterNotMicrostate extends AbstractAction { public JMenuItem jmi = null; private int stateValue = -1; public SetFilterNotMicrostate() { super(/*ADD_FILTER +*/ NOT_MSTATE_LONG_NAME /*, AnUtility.filtclause_icon*/); } public void enableMenuItem(TimelineSelectionEvent selEvent) { boolean enabled; if (selEvent != null && selEvent.eventDetail != null && selEvent.eventDetail instanceof ProfileEvent) { enabled = true; ProfileEvent pEvent = (ProfileEvent) selEvent.eventDetail; stateValue = pEvent.getState(); } else { enabled = false; stateValue = -1; } if (null != jmi) { jmi.setEnabled(enabled); } } @Override public void actionPerformed(ActionEvent ev) { String clause = "(MSTATE != " + stateValue + ")"; setClause( NOT_MSTATE_SHORT_NAME, NOT_MSTATE_LONG_NAME, clause); // Put the string in the text field } } // -------------- Select Event ---------------- // /** Implements menu item: -> Select First */ class SelectFirst extends AbstractAction { public SelectFirst() { super(AnLocale.getString("Select a Visible Event"), new ImageIcon("sf.jpg")); } @Override public void actionPerformed(ActionEvent ev) { selectFirst(); } } /** Implements menu item: -> Center Selection */ class SelectFind extends AbstractAction { public SelectFind() { super(AnLocale.getString("Find (Recenter) Event Selection")); } public JMenuItem jmi = null; public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { selectFind(); } } /** Implements menu item: -> Right */ class SelectNextRight extends AbstractAction { public SelectNextRight() { super(AnLocale.getString("Right"), AnUtility.forw_icon); } public JMenuItem jmi = null; public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { selectRight(); } } /** Implements menu item: -> Left */ class SelectNextLeft extends AbstractAction { public SelectNextLeft() { super(AnLocale.getString("Left"), AnUtility.back_icon); } public JMenuItem jmi = null; public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { selectLeft(); } } /** Implements menu item: -> Up */ class SelectNextUp extends AbstractAction { public SelectNextUp() { super(AnLocale.getString("Up"), AnUtility.up_icon); } public JMenuItem jmi = null; public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { selectUp(); } } /** Implements menu item: -> Down */ class SelectNextDown extends AbstractAction { public SelectNextDown() { super(AnLocale.getString("Down"), AnUtility.down_icon); } public JMenuItem jmi = null; public void enableMenuItem(boolean val) { if (null != jmi) { jmi.setEnabled(val); } } @Override public void actionPerformed(ActionEvent ev) { selectDown(); } } // -------------- Scroll ---------------- // /** Implements menu item: Scroll -> -> Right */ class ScrollHorizontalRight extends AbstractAction { public ScrollHorizontalRight() { super(AnLocale.getString("Right"), new ImageIcon("shr.jpg")); } @Override public void actionPerformed(ActionEvent ev) { timeline.panRight(); } } /** Implements menu item: Scroll -> -> Left */ class ScrollHorizontalLeft extends AbstractAction { public ScrollHorizontalLeft() { super(AnLocale.getString("Left"), new ImageIcon("shl.jpg")); } @Override public void actionPerformed(ActionEvent ev) { timeline.panLeft(); } } /** Implements menu item: Scroll -> -> Page Right */ class ScrollHorizontalPageRight extends AbstractAction { public ScrollHorizontalPageRight() { super(AnLocale.getString("Page Right"), new ImageIcon("shpr.jpg")); } @Override public void actionPerformed(ActionEvent ev) { timeline.pageRight(); } } /** Implements menu item: Scroll -> -> Page Left */ class ScrollHorizontalPageLeft extends AbstractAction { public ScrollHorizontalPageLeft() { super(AnLocale.getString("Page Left"), new ImageIcon("shpl.jpg")); } @Override public void actionPerformed(ActionEvent ev) { timeline.pageLeft(); } } /** Implements menu item: Scroll -> -> Up */ class ScrollVerticalUp extends AbstractAction { public ScrollVerticalUp() { super(AnLocale.getString("Up"), new ImageIcon("svu.jpg")); } @Override public void actionPerformed(ActionEvent ev) { timeline.panUp(); } } /** Implements menu item: Scroll -> -> Down */ class ScrollVerticalDown extends AbstractAction { public ScrollVerticalDown() { super(AnLocale.getString("Down"), new ImageIcon("svd.jpg")); } @Override public void actionPerformed(ActionEvent ev) { timeline.panDown(); } } /** Implements menu item: Scroll -> -> Page Up */ class ScrollVerticalPageUp extends AbstractAction { public ScrollVerticalPageUp() { super(AnLocale.getString("Page Up"), new ImageIcon("svpu.jpg")); } @Override public void actionPerformed(ActionEvent ev) { timeline.pageUp(); } } /** Implements menu item: Scroll -> -> Page Down */ class ScrollVerticalPageDown extends AbstractAction { public ScrollVerticalPageDown() { super(AnLocale.getString("Page Down"), new ImageIcon("svpd.jpg")); } @Override public void actionPerformed(ActionEvent ev) { timeline.pageDown(); } } // -------------- Select Time Range ---------------- // class findTimeMarker extends AbstractAction { public findTimeMarker() { super(AnLocale.getString("Find Time Markers")); } @Override public void actionPerformed(ActionEvent ev) { timeline.findTimeMarker(); } } /** Implements menu item: Select Time Range -> -> Set Time Marker at Center */ class SetTimeMarker extends AbstractAction { public SetTimeMarker() { super(AnLocale.getString("Set Time Marker at Center")); } @Override public void actionPerformed(ActionEvent ev) { timeline.setTimeMarker(); } } /** Implements menu item: Select Time Range -> -> Move Time Marker Left */ class MoveTimeMarkerLeft extends AbstractAction { public MoveTimeMarkerLeft() { super(AnLocale.getString("Move Time Marker Left")); } @Override public void actionPerformed(ActionEvent ev) { timeline.moveTimeMarkerLeft(); } } /** Implements menu item: Select Time Range -> -> Move Time Marker Right */ class MoveTimeMarkerRight extends AbstractAction { public MoveTimeMarkerRight() { super(AnLocale.getString("Move Time Marker Right")); } @Override public void actionPerformed(ActionEvent ev) { timeline.moveTimeMarkerRight(); } } /** Implements menu item: Select Time Range -> -> Adjust Selection Range Left */ class MoveTimeMarkerRangeLeft extends AbstractAction { public MoveTimeMarkerRangeLeft() { super(AnLocale.getString("Adjust Time Range to the Left")); } @Override public void actionPerformed(ActionEvent ev) { timeline.moveTimeRangeToLeft(); } } /** Implements menu item: Select Time Range -> -> Adjust Selection Range Right */ class MoveTimeMarkerRangeRight extends AbstractAction { public MoveTimeMarkerRangeRight() { super(AnLocale.getString("Adjust Time Range to the Right")); } @Override public void actionPerformed(ActionEvent ev) { timeline.moveTimeRangeToRight(); } } class ShowDynamicHelpPageAction extends AbstractAction { public ShowDynamicHelpPageAction() { super(AnLocale.getString("More Info"), new ImageIcon("help.gif")); } @Override public void actionPerformed(ActionEvent ev) { ShowDynamicHelpPage(); } } private void ShowDynamicHelpPage() { // HelpManager.getDefault().showDynaHelp("MPITimeline"); } public TimelinePanel getTimelinePanel() { return timeline; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/cursorevent/���������������������������������������������0000755�0001750�0001750�00000000000�14517775726�020301� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/cursorevent/CursorSetEvent.java��������������������������0000644�0001750�0001750�00000005137�14517772113�024010� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2.cursorevent; import org.gprofng.mpmt.timeline2.RowGeometry; import org.gprofng.mpmt.timeline2.TimelineSelectionEvent; public class CursorSetEvent extends CursorEvent { public final RowGeometry rowGeometry; public final long clickTime; public final boolean ctrlKey; public final boolean shiftKey; public final long eventIdx; // may be TimelineSelectionEvent.EVT_IDX_INVALID public final long eventTimeStart; // only set if eventIdx is valid public final long eventTimeEnd; // only set if eventIdx is valid public final boolean directHit; // click was on event public final boolean requestRefreshCaliper; // update of calipers requested public final boolean updateRowSelections; // update row selections public CursorSetEvent( RowGeometry row, long clickTime, boolean ctrlKey, boolean shiftKey, long eventIdx, long eventTimeStart, long eventTimeEnd, boolean directHit, boolean requestRefreshCaliper, boolean updateRowSelections) { this.rowGeometry = row; this.clickTime = clickTime; this.ctrlKey = ctrlKey; this.shiftKey = shiftKey; this.eventIdx = eventIdx; this.eventTimeStart = eventTimeStart; this.eventTimeEnd = eventTimeEnd; this.directHit = directHit; this.requestRefreshCaliper = requestRefreshCaliper; this.updateRowSelections = updateRowSelections; } public CursorSetEvent( RowGeometry row, long clickTime, boolean ctrlKey, boolean shiftKey, boolean requestRefreshCaliper, boolean updateRowSelections) { this.rowGeometry = row; this.clickTime = clickTime; this.ctrlKey = ctrlKey; this.shiftKey = shiftKey; this.eventIdx = TimelineSelectionEvent.EVT_IDX_INVALID; this.eventTimeStart = -1; this.eventTimeEnd = -1; this.directHit = false; this.requestRefreshCaliper = requestRefreshCaliper; this.updateRowSelections = updateRowSelections; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/cursorevent/CursorEvent.java�����������������������������0000644�0001750�0001750�00000001344�14517772113�023330� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2.cursorevent; public class CursorEvent {} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/cursorevent/CursorMoveEvent.java�������������������������0000644�0001750�0001750�00000002257�14517772113�024163� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2.cursorevent; import org.gprofng.mpmt.timeline2.TimelineSelectionEvent; public class CursorMoveEvent extends CursorEvent { public final TimelineSelectionEvent.CursorAxis axis; public final int count; public final boolean ctrlKey; public final boolean shiftKey; public CursorMoveEvent( TimelineSelectionEvent.CursorAxis axis, int count, boolean ctrlKey, boolean shiftKey) { this.axis = axis; this.count = count; this.ctrlKey = ctrlKey; this.shiftKey = shiftKey; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TimelineVariable.java������������������������������������0000644�0001750�0001750�00000022127�14517772113�021710� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.metrics.MetricColors; import java.awt.Color; import java.text.DecimalFormat; import java.text.NumberFormat; public final class TimelineVariable { public static final Color SELECT_COLOR = new Color(98, 98, 98); private static final double TIMESTAMP_MULT = .000000001; private static final NumberFormat TIMESTAMP_FMT; private static final Object syncFormat = new Object(); private static final Color unknownColor = Color.BLACK; static { TIMESTAMP_FMT = new DecimalFormat(); TIMESTAMP_FMT.setMaximumFractionDigits(6); TIMESTAMP_FMT.setMinimumFractionDigits(6); TIMESTAMP_FMT.setGroupingUsed(false); } public static String strTimestamp(final long time) { String t; synchronized (syncFormat) { // begin critical section: format is not thread safe t = TIMESTAMP_FMT.format(time * TIMESTAMP_MULT); } // end of critical section return t; } // ----- mapping states to colors and names ----- public static class StatesDisplayInfo { public final String statePropName; private final String[] displayNames; private final Color[] displayColors; private final int[] raw2displayIdxTable; public StatesDisplayInfo( String statePropName, String[] displayNames, Color[] displayColors, int[] raw2displayIdxTable) { this.statePropName = statePropName; this.displayNames = displayNames; this.displayColors = displayColors; this.raw2displayIdxTable = raw2displayIdxTable; } public final long[] raw2displayValues(final long[] rawValues) { if (raw2displayIdxTable == null) { return rawValues; } final long displayValues[] = new long[raw2displayIdxTable.length]; for (int i = 0; i < rawValues.length; i++) { int idx = getDisplayIdx(i); displayValues[idx] += rawValues[i]; } return displayValues; } public final int getDisplayIdx(int rawIdx) { if (raw2displayIdxTable == null) { return rawIdx; } if (rawIdx < 0 || rawIdx >= raw2displayIdxTable.length) { return raw2displayIdxTable.length - 1; // <unknown> bucket } return raw2displayIdxTable[rawIdx]; } public final String getNameByRawIdx(int rawIdx) { int idx = getDisplayIdx(rawIdx); if (displayNames == null || idx < 0 || idx >= displayNames.length) { return Integer.toString(rawIdx); } return displayNames[idx]; } public final String getNameByDisplayIdx(int dispIdx) { if (displayNames == null || dispIdx < 0 || dispIdx >= displayNames.length) { return Integer.toString(dispIdx) + "?"; // weird } return displayNames[dispIdx]; } public final Color getColorByRawIdx(int rawIdx) { int idx = getDisplayIdx(rawIdx); if (displayColors == null || idx < 0 || idx >= displayColors.length) { return unknownColor; } return displayColors[idx]; } public final Color getColorByDisplayIdx(int dispIdx) { if (displayColors == null || dispIdx < 0 || dispIdx >= displayColors.length) { return unknownColor; // weird } return displayColors[dispIdx]; } public final int getNumNames() { if (displayNames == null) { return 0; } return displayNames.length; } } // Remap the microstates to display categories and order. // Note: use same display order of LMS_* in: er.rc, TimelineVariable.java, // Ovw_data.h, BaseMetricTreeNode.cc and Experiment.cc metric registration public static final int NUM_SOLARIS_MSTATES = 10; // Solaris Microstates are 0-9 private static final int[ /*lms*/] MSTATE_TO_OVERVIEW_IDX = { // supply LMS value as index, returns display idx 0, // 0 LMS_USER 1, // 1 LMS_SYSTEM 2, // 2 LMS_TRAP 4, // 3 LMS_TFAULT 3, // 4 LMS_DFAULT 5, // 5 LMS_KFAULT 9, // 6 LMS_USER_LOCK 8, // 7 LMS_SLEEP 7, // 8 LMS_WAIT_CPU 6, // 9 LMS_STOPPED 10, // 10 LMS_LINUX_CPU 11, // 11 LMS_KERNEL_CPU 12, // 12 <unknown> }; // Names sorted by display order (not LMS_* order) private static final String[] MSTATE_DESC = { // YXXX should come from property names AnLocale.getString("User CPU"), AnLocale.getString("System CPU"), AnLocale.getString("Trap CPU"), AnLocale.getString("Data Page Fault"), AnLocale.getString("Text Page Fault"), AnLocale.getString("Kernel Page Fault"), AnLocale.getString("Stopped"), AnLocale.getString("Wait CPU"), AnLocale.getString("Sleep"), AnLocale.getString("User Lock"), AnLocale.getString("User+System CPU"), // NOT a Solaris microstate AnLocale.getString("Kernel CPU"), // NOT a Solaris microstate AnLocale.getString("<Unknown>"), // NOT a Solaris microstate }; // Colors sorted by display order (not LMS_* order) private static final Color[ /*ovw idx*/] MSTATE_COLORS = { MetricColors.getColor("user"), // 0: 0 LMS_USER MetricColors.getColor("system"), // 1: 1 LMS_SYSTEM MetricColors.getColor("trap"), // 2: 2 LMS_TRAP MetricColors.getColor("datapfault"), // 3: 4 LMS_DFAULT MetricColors.getColor("textpfault"), // 4: 3 LMS_TFAULT MetricColors.getColor("kernelpfault"), // 5: 5 LMS_KFAULT MetricColors.getColor("stop"), // 6: 9 LMS_STOPPED MetricColors.getColor("wait"), // 7: 8 LMS_WAIT_CPU MetricColors.getColor("sleep"), // 8: 7 LMS_SLEEP MetricColors.getColor("lock"), // 9: 6 LMS_USER_LOCK MetricColors.getColor("user"), // 10:10 LMS_LINUX_CPU MetricColors.getColor("user"), // 11:11 LMS_KERNEL_CPU Color.black, // 12:12 <unknown> }; public static final StatesDisplayInfo mstate_info = new StatesDisplayInfo("MSTATE", MSTATE_DESC, MSTATE_COLORS, MSTATE_TO_OVERVIEW_IDX); // YXXX maybe we should get these from properties private static final String[] TL_HEAP_HTYPE_DESCS = { AnLocale.getString("Allocation"), AnLocale.getString("Free"), AnLocale.getString("Reallocation"), AnLocale.getString("MemoryMap"), AnLocale.getString("MemoryUnmap"), }; private static final Color[] TL_HEAP_HTYPE_COLOR_TABLE = { MetricColors.BLUE_VIOLET, // malloc MetricColors.CYAN, // free MetricColors.ORANGE, // realloc MetricColors.RED, // mmap MetricColors.DARK_GREY, // munmap }; public static final StatesDisplayInfo htype_info = new StatesDisplayInfo("HTYPE", TL_HEAP_HTYPE_DESCS, TL_HEAP_HTYPE_COLOR_TABLE, null); // YXXX maybe we should get these from properties private static final String[] TL_IOTRACE_IOTYPE_DESCS = { AnLocale.getString("Read"), AnLocale.getString("Write"), AnLocale.getString("Open"), AnLocale.getString("Close"), AnLocale.getString("Other I/O"), AnLocale.getString("Read error"), AnLocale.getString("Write error"), AnLocale.getString("Open error"), AnLocale.getString("Close error"), AnLocale.getString("Other I/O error"), }; private static final Color[] TL_IOTRACE_IOTYPE_COLOR_TABLE = { // read, write, open, close, otherio, readerror, writeerror, openerror, closeerror, otherioerror MetricColors.RED, // read MetricColors.ORANGE, // write MetricColors.CYAN, // open MetricColors.DARK_GREY, // close MetricColors.BLUE_VIOLET, // otherio MetricColors.BLACK, // read error MetricColors.BLACK, // write error MetricColors.BLACK, // open error MetricColors.BLACK, // close error MetricColors.BLACK, // other io error }; public static final StatesDisplayInfo iotype_info = new StatesDisplayInfo("IOTYPE", TL_IOTRACE_IOTYPE_DESCS, TL_IOTRACE_IOTYPE_COLOR_TABLE, null); private static final Color[] TL_UNKNOWN_GENERIC_COLOR_TABLE = { MetricColors.BLUE_VIOLET, MetricColors.GOLDEN_YELLOW, MetricColors.COBALT, MetricColors.LIGHT_GREEN, MetricColors.FUSCHIA, MetricColors.GREEN, MetricColors.ORANGE, MetricColors.DARK_GREY, MetricColors.RED, MetricColors.CYAN, MetricColors.GRAY, MetricColors.BLUE, MetricColors.BLACK, }; private static final StatesDisplayInfo generic_info = new StatesDisplayInfo("", null, TL_UNKNOWN_GENERIC_COLOR_TABLE, null); private static final StatesDisplayInfo[] info_list = {mstate_info, htype_info, iotype_info}; public static final StatesDisplayInfo getStateInfo(final String propName) { for (int ii = 0; ii < info_list.length; ii++) { if (propName.equals(info_list[ii].statePropName)) { return info_list[ii]; } } return generic_info; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/RowDataRequestParams.java��������������������������������0000644�0001750�0001750�00000004214�14517772113�022547� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; public class RowDataRequestParams { // final public final TL2DataSnapshot snapshot; public final boolean forceLoad; public final long binTime; public final long alignedTimeStart; public final long timeEnd; public final int nbins; public final int rowStart; public final int rowEnd; public final long required_timeStart; public final long required_timeEnd; public final int required_rowStart; public final int required_rowEnd; // dynamic private boolean cancel; public RowDataRequestParams( final TL2DataSnapshot snapshot, final boolean forceLoad, final long bin_time, final long alignedStart, final int nbins, final int rowStart, final int rowEnd, final long required_timeStart, final long required_timeEnd, final int required_rowStart, final int required_rowEnd) { this.snapshot = snapshot; this.forceLoad = forceLoad; this.binTime = bin_time; this.alignedTimeStart = alignedStart; this.timeEnd = alignedStart + (nbins * bin_time - 1); this.nbins = nbins; this.rowStart = rowStart; this.rowEnd = rowEnd; this.cancel = false; this.required_timeStart = required_timeStart; this.required_timeEnd = required_timeEnd; this.required_rowStart = required_rowStart; this.required_rowEnd = required_rowEnd; } public synchronized void cancel() { cancel = true; } public synchronized boolean isCancelled() { return cancel; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TimelineSelectionRowEvent.java���������������������������0000644�0001750�0001750�00000002027�14517772113�023577� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.timeline_common.TimelineSelectionGenericEvent; /** Holds information about timeline row selections */ public class TimelineSelectionRowEvent extends TimelineSelectionGenericEvent { public final boolean rowsSelected; public TimelineSelectionRowEvent(boolean rowsSelected) { this.rowsSelected = rowsSelected; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TimelineDraw.java����������������������������������������0000644�0001750�0001750�00000256131�14517772113�021064� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.experiment_props.PropDescriptor; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.statecolors.StateColorMap; import org.gprofng.mpmt.timeline.events.*; import org.gprofng.mpmt.timeline2.TL2DataSnapshot.*; import org.gprofng.mpmt.timeline2.data.*; import org.gprofng.mpmt.timeline_common.CoordCalcDataMaster; import org.gprofng.mpmt.timeline_common.CoordCalcDataReader; import org.gprofng.mpmt.timeline_common.CoordCalcTimeReader; import org.gprofng.mpmt.timeline_common.TimelineCaliper; import java.awt.*; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import javax.swing.*; public final class TimelineDraw { public static final int STANDARD_WHITESPACE_PIXELS = 6; public static final int HMARGIN = STANDARD_WHITESPACE_PIXELS + 2; // +2 for border // set via constructor args private final TL2DataFetcher tl2DataFetcher; // for getStackFuncArray() private final IconRuler iconRuler; private final CoordCalcTimeReader timeAxisCalculator; private final CoordCalcDataReader dataAxisCalculator; private final CoordCalcDataMaster dataAxisMaster; private final StateColorMap colorMap; private StateColorMap.ColorMapSnapshot stateColorSnapshot; // settings private static final int FATTENED_EVENT_WIDTH = 5; // maximum pixel width for zero-duration events public static final int CLICK_PIXEL_TOLERANCE = FATTENED_EVENT_WIDTH / 2 + 4; private final int MIN_SAMPLE_3D_WIDTH = 3; // min width of sample before divider will show private final int DEFAULT_SAMPLE_HEIGHT = 20; private final int MAX_SAMPLE_HEIGHT = 50; private final int DEFAULT_HEAPSZ_HEIGHT = 60; private final int MAX_HEAPSZ_HEIGHT = 180; // vertical pixels for showing sample data private final int MIN_CHART_HEIGHT = 9; private final int MAX_CHART_HEIGHT = 9; // vertical pixels for showing chart data private final int EVENT_TICK_HEIGHT = 4; // pixel height of stack event tick marks public static final Color TICK_ONE_PIXEL_WIDE_COLOR = new Color(84, 83, 84); public static final Color TICK_WITH_STACK_COLOR = new Color(84, 83, 84); public static final Color TICK_STANDALONE_COLOR = new Color(87, 86, 87); private final int SAMPLE_BORDER_HEIGHT = 0; // 0 is allowed // height of border above/below samples public static final Color STANDARD_DIVIDER_COLOR = Color.LIGHT_GRAY; // entity dividers and subdividers public static final Color EXPERIMENT_DIVIDER_COLOR = STANDARD_DIVIDER_COLOR; // between experiments public static final Color COMPARE_GRP_DIVIDER_COLOR = EXPERIMENT_DIVIDER_COLOR; // between compare groups public static final Color GENERIC_SELECTION_COLOR = new Color(189, 207, 231); private final Color CROSSHAIR_COLOR = Color.DARK_GRAY; private final Color CROSSHAIR_FILL_BORDER_COLOR = Color.DARK_GRAY; public static final Color SELECTION_BACKGROUND_COLOR = new Color(209, 229, 255); // light GENERIC_SELECTION_COLOR private final Color CROSSHAIR_FILL_COLOR = SELECTION_BACKGROUND_COLOR; private final Color SAMPLE_BORDER_COLOR = Color.LIGHT_GRAY; private final Color SAMPLE_VDIVIDER_COLOR = Color.GRAY; private final Color CHART_BORDER_COLOR = Color.LIGHT_GRAY; private final Color CHART_BACKGROUND_COLOR = new Color(238, 238, 238); private final Color CHART_BACKGROUND_SEL_COLOR = GENERIC_SELECTION_COLOR; private final Color CHART_GRAPH_COLOR = Color.BLUE; private final Color CHART_GRAPH_COLOR_MAX = Color.RED; private final Color CHART_NUMERIC_TEXT_COLOR = new Color(0x33, 0x33, 0x33); private final double NS_PER_SEC = 1000000000.0; private class FontInfo { final int ascent; final int descent; final int height; final Font font; public FontInfo(Graphics g, Font font) { this.font = font; FontMetrics fm = g.getFontMetrics(font); if (fm != null) { ascent = fm.getAscent() - 1; // YXXX bogus adjust for looks descent = fm.getDescent() - 2; // YXXX bogus adjust for looks height = ascent + descent; } else { ascent = 0; descent = 0; height = 0; } } } private static final Font standard_font = (new JLabel()).getFont(); private FontInfo fontInfoSmallBold = null; private FontInfo fontInfoSmallNormal = null; // presentation options private Settings.TLStack_align stack_align; // stack settings private int vzoom_level; // stack settings private int stack_frame_pixels = 3; // stack settings private int stackRowHeight; private int nominalSampleHeight; private int nominalHeapszHeight; private static final int NUM_VZOOM_MACRO_LEVELS = 4; // vzoom_level = [0, NUM_VZOOM_MACRO_LEVELS] for zoom public static final int TIMELINE_MAX_VZOOM_LEVEL = 56 + NUM_VZOOM_MACRO_LEVELS; public static final int TIMELINE_DEFAULT_VZOOM_LEVEL = 8; private static final int MAX_STACK_PIXELS = 900; private final int VZOOM_BASE_PIXEL_STEP = 5; // initial pixel step for vzoom>NUM_VZOOM_MACRO_LEVELS // user options and events private boolean idle_color_set; // use a special color for idle cpu private Color idle_color; // color for idle cpu // selected item private TimelineCaliper caliper; private int caliper_x1, caliper_x2; private TimelineSelectionEvent selection_event = null; // if non-null, rowNum must be valid private TimelineSelectionEvent recent_selection = null; // if non-null, rowNum must be valid // selected item's boundaries (x,y,h,w) private int sel_x, sel_y, sel_w, sel_h; private boolean sel_set = false; // selected rows private TreeSet<Integer> multiselect_rows; private List<Integer> rowNumToEntityNum; // map from rowNum to entityNum // geometry private int usedHeight; // virtual vertical pixels that // would be required to draw all rows // row data snapshot private List<RowGeometry> rowGeometry; private List<List<RowGeometry>> rowGeometryByEntity; private TL2DataSnapshot recentDataSnapshot; private List<Integer> rowOffsets; // Notes: there is a 1-1 mapping between rowGeometry and subrows // visible on timeline. // "rowNum" is the typical name for an index into rowGeometry. // "rowNum" also is used by dataAxisCalculator. // // Do NOT use rowNum to index into rowData or rowDefinition arrays! // This is because a single rowDefinition defines both the event data row // and any charts rows generated for that event data. In other words, // a single rowDefinition may map to several rowGeometry elements. // screen state snapshot private int currRowFirst; // first visible row private int currRowLast; // first non-visible row private int currScrollY; private int currVisibleHeight; private boolean forceFullRepaint; // all rows must be redrawn private boolean forceRowGeometry; // row geometry has changed private final int INVALID_BIN = Integer.MIN_VALUE; public TimelineDraw( TL2DataFetcher tl2DataFetcher, StateColorMap colorMap, IconRuler iconRuler, CoordCalcTimeReader ccx, CoordCalcDataMaster ccy) { this.tl2DataFetcher = tl2DataFetcher; this.iconRuler = iconRuler; this.timeAxisCalculator = ccx; this.dataAxisCalculator = ccy; this.dataAxisMaster = ccy; this.colorMap = colorMap; stateColorSnapshot = null; rowGeometry = new ArrayList(); rowGeometryByEntity = new ArrayList(); multiselect_rows = new TreeSet(); rowNumToEntityNum = new ArrayList(); // options setVZoomLevel(13); // YXXX default, should be set somewhere else? this.stack_align = Settings.TLStack_align.TLSTACK_ALIGN_ROOT; // colors idle_color_set = false; idle_color = null; // screen info currRowFirst = currRowLast = 0; currScrollY = 0; currVisibleHeight = 0; forceFullRepaint = forceRowGeometry = false; // if x2 < x1, caliper is not visible: caliper_x1 = Integer.MAX_VALUE; caliper_x2 = Integer.MIN_VALUE; } private FontInfo getSmallFont(final Graphics g) { if (fontInfoSmallNormal != null) { return fontInfoSmallNormal; } if (g == null) { return null; // yuck } Font font = new Font("SansSerif", Font.PLAIN, standard_font.getSize() - 1); fontInfoSmallNormal = new FontInfo(g, font); return fontInfoSmallNormal; } private FontInfo getSmallBoldFont(final Graphics g) { if (fontInfoSmallBold != null) { return fontInfoSmallBold; } if (g == null) { return null; // yuck } Font font = new Font("SansSerif", Font.BOLD, standard_font.getSize() - 1); fontInfoSmallBold = new FontInfo(g, font); return fontInfoSmallBold; } public void setCPUIdleColor(final boolean set, final Color color) { if (idle_color_set != set || idle_color != color) { idle_color_set = set; idle_color = color; forceFullRepaint = true; } } public void setCaliper(TimelineCaliper newCaliper) { caliper = newCaliper; // this is a frozen snapshot } public void setSelection(TimelineSelectionEvent selEvent) { if (selEvent == null || selEvent.rowNum == -1 || selEvent.getRowGeometry() == null) { selection_event = null; } else { selection_event = selEvent; recent_selection = selEvent; } } public TimelineSelectionEvent getSelection() { return selection_event; } public void edt_resetAll() { // edt only recent_selection = null; // setSelection() & notification performed in other places } public TimelineSelectionEvent getRecentSelection() { if (selection_event != null) { return selection_event; } return recent_selection; } public void setSelectedRows(TreeSet<Integer> selected_entities) { multiselect_rows = new TreeSet(); if (recentDataSnapshot == null) { // with current design shouldn't happen. If needed, we could save a copy of selected_entities return; // experiment load in progress } int numBlks = rowGeometryByEntity.size(); for (Integer blkIdx : selected_entities) { if (blkIdx < 0 || blkIdx >= numBlks) { continue; // weird } List<RowGeometry> entityGeos = rowGeometryByEntity.get(blkIdx); for (RowGeometry rowGeo : entityGeos) { multiselect_rows.add(rowGeo.rowNum); } } } public List<RowGeometry> getEntityRows(int entityNum) { if (entityNum < 0 || entityNum >= rowGeometryByEntity.size()) { return null; } return rowGeometryByEntity.get(entityNum); } public void setVZoomLevel(int new_vzoom_level) { if (new_vzoom_level < 0) { new_vzoom_level = 0; } else if (new_vzoom_level >= TIMELINE_MAX_VZOOM_LEVEL) { new_vzoom_level = TIMELINE_MAX_VZOOM_LEVEL; } if (this.vzoom_level != new_vzoom_level) { this.vzoom_level = new_vzoom_level; forceRowGeometry = true; } } public void setStackFramePixels(int stack_frame_pixels) { if (stack_frame_pixels < 1) { stack_frame_pixels = 1; // weird } else if (stack_frame_pixels > Settings.TIMELINE_MAX_STACK_FRAME_PIXELS) { stack_frame_pixels = Settings.TIMELINE_MAX_STACK_FRAME_PIXELS; // weird } if (this.stack_frame_pixels != stack_frame_pixels) { this.stack_frame_pixels = stack_frame_pixels; forceFullRepaint = true; } } public void setStackAlign(final Settings.TLStack_align stack_align) { if (this.stack_align != stack_align) { this.stack_align = stack_align; forceFullRepaint = true; } } public void edt_recalcRowOffsets() { // must be called from awt event thread edt_processDataSnapshot(recentDataSnapshot, true, null); } public TL2DataSnapshot getDataSnapshot() { return recentDataSnapshot; } // Main drawing routine for timeline public void drawIt(final Graphics g) { drawData(g); drawSelection(g); drawBorder(g); } private void drawData(final Graphics g) { TL2DataSnapshot dataSnapshot = recentDataSnapshot; boolean forceRedraw = false; if (fontInfoSmallBold == null || fontInfoSmallNormal == null) { // yuck getSmallFont(g); getSmallBoldFont(g); forceRedraw = true; } edt_processDataSnapshot(dataSnapshot, forceRedraw, g); final int visibleHeight = dataAxisCalculator.getCanvasPixels(); final int visibleWidth = timeAxisCalculator.getCanvasPixels(); // erase everything { Graphics2D g2 = (Graphics2D) g; Rectangle drawHere = g.getClipBounds(); g.setColor(Color.white); g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height); } if (dataSnapshot == null || dataSnapshot.getRowData().isEmpty()) { final String message; if (dataSnapshot == null) { message = AnLocale.getString("Experiment load in progress..."); } else { message = AnLocale.getString("Data not available for this filter selection"); } drawCenteredMessage(g, message, visibleWidth / 2, visibleHeight / 2); rowGeometry = new ArrayList(); rowGeometryByEntity = new ArrayList(); rowNumToEntityNum = new ArrayList(); iconRuler.setRowGeometry(rowGeometry, 0, -1, -1, -1, multiselect_rows); return; } stateColorSnapshot = colorMap.checkForColorUpdates(stateColorSnapshot); final int scrollY = calcScrollY(); setScrollY(rowGeometry, scrollY, visibleHeight); // might be optimized... forceFullRepaint = false; // YXXX all rows updated for now, optimize later // in theory, could repaint only rows that have been updated or damaged // draw selection crosshair final long maxVisTime = timeAxisCalculator.getTimeEnd(); final long minVisTime = timeAxisCalculator.getTimeStart(); final int x1; final int x2; final long c_high, c_low; if (caliper != null && (c_high = caliper.getHighTime()) >= minVisTime && (c_low = caliper.getLowTime()) <= maxVisTime) { // caliper is visible if (c_low >= minVisTime) { int binStart = timeAxisCalculator.getBinAtTime(c_low); x1 = timeAxisCalculator.getLowCoordForBin(binStart); } else { x1 = Integer.MIN_VALUE; } if (c_high <= maxVisTime) { int binEnd = timeAxisCalculator.getBinAtTime(c_high); x2 = timeAxisCalculator.getLowCoordForBin(binEnd + 1) - 1; } else { x2 = Integer.MAX_VALUE; } } else { // caliper is not visible x1 = Integer.MAX_VALUE; x2 = Integer.MIN_VALUE; } caliper_x1 = x1; caliper_x2 = x2; drawCaliper(g, 0, visibleHeight - 1, CROSSHAIR_FILL_COLOR); // caliper fill drawVisibleDividers(g, rowGeometry, visibleWidth); drawVisibleRows(g, rowGeometry, visibleWidth); // sets stackColorMap drawCaliper(g, 0, visibleHeight - 1, null); // caliper border // YXXX could/should validate that event is still current int selectedRow = (selection_event == null) ? -1 : selection_event.rowNum; iconRuler.setRowGeometry( rowGeometry, scrollY, currRowFirst, currRowLast, selectedRow, multiselect_rows); // YXXX canvas.setRepainting(false); } // Selected object highlighting private GenericEvent getVisibleSelection() { if (selection_event == null || selection_event.eventIdx == -1) { return null; } if (selection_event.eventDetail == null) { return null; // weird? } // check if row is visible final int selection_row = selection_event.rowNum; if (selection_row < currRowFirst || selection_row >= currRowLast) { return null; } if (selection_row >= rowGeometry.size()) { return null; // typically, when rows are cleared pending new data } final EventDetail details = selection_event.eventDetail; long sel_time_start = details.getTimestamp(); long sel_time_end = sel_time_start; if (details instanceof DurationEvent) { DurationEvent devent = (DurationEvent) details; sel_time_start -= devent.getDuration(); } final GenericEvent evt; evt = eventDetail2GenericEvent(details, sel_time_start, sel_time_end, selection_event.eventIdx); return evt; } private GenericEvent eventDetail2GenericEvent( EventDetail details, long sel_time_start, long sel_time_end, long evtIdx) { final GenericEvent genEvent; final long delta = timeAxisCalculator.getTimeDuration(); final long timeWindowLow = timeAxisCalculator.getTimeStart() - delta; final long timeWindowHigh = timeAxisCalculator.getTimeEnd() + delta; // wider window used: the event highlight may be visible even if event is off screen if (sel_time_end < timeWindowLow || sel_time_start > timeWindowHigh) { // it's way off the screen return null; } long drawTimeStart = sel_time_start; long drawTimeEnd = sel_time_end; // limit draw range so that long calculations don't overflow: if (drawTimeStart < timeWindowLow) { drawTimeStart = timeWindowLow; } if (drawTimeEnd > timeWindowHigh) { drawTimeEnd = timeWindowHigh; } final int binStart = timeAxisCalculator.getBinAtTime(drawTimeStart); final int binEnd = timeAxisCalculator.getBinAtTime(drawTimeEnd); final int binCount = binEnd - binStart + 1; if (details instanceof ExtendedEvent) { int state = -1; if (details instanceof StateEvent) { state = ((StateEvent) details).getState(); } genEvent = new StackEvent( evtIdx, binStart, binCount, sel_time_start, sel_time_end, details.getStack(), state); } else if (details instanceof Sample) { Sample sample = (Sample) details; genEvent = new SampleEvent( evtIdx, binStart, binCount, sel_time_start, sel_time_end, sample.getMStates()); } else { genEvent = null; // weird } return genEvent; } private void setSelectionBounds(int x, int y, int w, int h) { sel_x = x; sel_y = y; sel_w = w; sel_h = h; sel_set = true; } private void drawSelection(Graphics g) { GenericEvent event = getVisibleSelection(); if (event == null) { return; } sel_set = false; // may be set to true by drawVisibleRows() if (selection_event == null) { return; } int selRowNum = selection_event.rowNum; if (selRowNum >= rowGeometry.size()) { return; // weird? } RowGeometry selRow = rowGeometry.get(selRowNum); drawSelection(g, selRow, event); if (!(event instanceof StackEvent)) { return; } // identify rows that display event's state RowGeometry statesRow = null; for (int ii = 0; ii < selRow.nSubrows; ii++) { int row_idx = ii - selRow.subrowNum; if (row_idx == 0) { continue; } row_idx += selRowNum; RowGeometry tmpRow = rowGeometry.get(row_idx); // YXXX there must be a better way to accurately determine if a row is for states final RowData dataCopy = tmpRow.rowData.grabEventData(); // row.rowData is volatile, get snapshot final Object vals = dataCopy.getChartData(tmpRow.chartPropIdx); if (vals instanceof SampleEvent[]) { statesRow = tmpRow; StackEvent stackEvt = (StackEvent) event; int state = stackEvt.mState; if (state < 0) { continue; // weird } long[] propVals = new long[state + 1]; propVals[state] = 1; SampleEvent sampleEvt = new SampleEvent( event.eventIdx, event.binStart, event.binCount, event.timeStart, event.timeEnd, propVals); drawSelection(g, statesRow, sampleEvt); } } } private void drawSelection(Graphics g, RowGeometry row, GenericEvent event) { GenericEvent[] events = new GenericEvent[1]; events[0] = event; drawRowEvents(g, row, events, 0, 0, true, false); if (!sel_set) { return; // off screen } drawHighlight(g, sel_x, sel_y, sel_w, sel_h); } private void drawHighlight(Graphics g, int x, int y, int w, int h) { Color c[] = {Color.YELLOW, Color.YELLOW, Color.RED}; for (int i = 0; i < c.length; i++) { g.setColor(c[i]); g.drawRect(x - i - 1, y - i - 1, w + 2 * i + 1, h + 2 * i + 1); } } private void drawBorder(final Graphics g) { final int surface_width = timeAxisCalculator.getCanvasPixels(); final int surface_height = dataAxisCalculator.getCanvasPixels(); final int xMargin = timeAxisCalculator.getMargin(); final int yMargin = dataAxisCalculator.getMargin(); final Graphics2D g2 = (Graphics2D) g; if (yMargin > 1 || xMargin > 1) { g2.setColor(STANDARD_DIVIDER_COLOR); g2.drawLine(0, 0, 0, surface_height - 1); // vertical, to right of ruler g2.setColor(Color.BLACK); g2.drawRect(-1, 0, surface_width + 1, surface_height - 1); } else { g2.setColor(Color.BLACK); g2.drawRect(0, 0, surface_width, surface_height - 1); } } private void drawRowVBorders( final Graphics g, final int rowStartY, final int rowEndY, final int dataStartY, final int dataEndY) { final int xMargin = timeAxisCalculator.getMargin(); if (xMargin <= 1) { return; } // erase vertical margins final int surface_width = timeAxisCalculator.getCanvasPixels(); Graphics2D g2 = (Graphics2D) g; g2.setColor(Color.WHITE); final int h = rowEndY - rowStartY + 1; g2.fillRect(0, rowStartY, xMargin, h); g2.fillRect(surface_width - xMargin, rowStartY, xMargin, h); if (dataEndY != -1) { // add vertical border g2.setColor(STANDARD_DIVIDER_COLOR); int xx = xMargin - 1; g2.drawLine(xx, dataStartY, xx, dataEndY); xx = surface_width - xMargin; g2.drawLine(xx, dataStartY, xx, dataEndY); } } private int calcScrollY() { double startPercent = dataAxisCalculator.getVisibleStart(); int scrollY = (int) (usedHeight * startPercent) - dataAxisCalculator.getMargin(); return scrollY; } private void drawCenteredMessage(Graphics g, String msg, int screenX, int screenY) { final FontMetrics fm = g.getFontMetrics(); g.setFont(standard_font); g.setColor(Color.LIGHT_GRAY); g.drawString(msg, screenX - fm.stringWidth(msg) / 2, screenY + fm.getHeight() / 2); } private void drawCaliper(final Graphics g, final int y1, final int y2, final Color doFill) { final int x1_orig = caliper_x1; final int x2_orig = caliper_x2; if (x2_orig < x1_orig || y2 < y1) { return; // not visible } final int visibleWidth = timeAxisCalculator.getCanvasPixels(); final int xMargin = timeAxisCalculator.getMargin(); final int x1 = x1_orig < xMargin ? xMargin : x1_orig; final int x2 = x2_orig > visibleWidth - xMargin ? visibleWidth - xMargin : x2_orig; final int w = x2 - x1; if (doFill != null) { if (w > 1) { g.setColor(doFill); g.fillRect(x1, y1, w, y2 - y1 + 1); } return; } if (w > 1) { g.setColor(CROSSHAIR_FILL_BORDER_COLOR); } else { g.setColor(CROSSHAIR_COLOR); } if (x1 == x1_orig) { g.drawLine(x1, y1, x1, y2); } if (x2 == x2_orig && x2 != x1) { g.drawLine(x2, y1, x2, y2); } // if (x1_orig == x2_orig) { // // fatten caliper if original was only 1 pixel wide // g.drawLine(x1 + 1, y1, x1 + 1, y2); // } } private int calcRowUpperPadding( Graphics g, final RowDefinition rowDef, final int chartIdx, final int subrowNum, final int numCharts) { Settings.TLData_type dataType = rowDef.getTLDataType(); if (chartIdx == -1 && (dataType.equals(Settings.TLData_type.TL_SAMPLE) || dataType.equals(Settings.TLData_type.TL_GCEVENT))) { // sample event data // GC event data return chart_padding(); } if (dataType.equals(Settings.TLData_type.TL_HEAPSZ)) { // heapsize event data and chart if (chartIdx == -1) { // event data int padding = chart_padding(); if (padding < STANDARD_WHITESPACE_PIXELS) { padding++; } return padding; } // chart data if (rowDef.getChartProperties().get(chartIdx).getName().equals("HTYPE")) { return 1; // state color chart } final FontInfo fi = getSmallBoldFont(g); // warning: see hack to init this at the top of drawData() if (fi != null) { return fi.height + chart_padding(); } return chart_padding(); } return 0; } private int calcRowLowerPadding( final Graphics g, final RowDefinition rowDef, final int chartIdx, final int subrowNum, final int numCharts) { Settings.TLData_type dataType = rowDef.getTLDataType(); if (chartIdx == -1 && dataType.equals(Settings.TLData_type.TL_HEAPSZ)) { // heapsz event data return 0; } if (chartIdx == -1 && !dataType.equals(Settings.TLData_type.TL_SAMPLE) && !dataType.equals(Settings.TLData_type.TL_GCEVENT)) { // callstack event data if (numCharts == 0) { // standalone event if (vzoom_level <= 2) { return 0; } if (vzoom_level <= 4) { return 1; } return 2; } else { // a chart follows int padding = chart_padding(); if (padding <= 1) { return padding; } if (subrowNum == numCharts) { // last row return 1; } return padding - 1; // -1 because stacks typically show "short" tick-marks } } // chart data return chart_padding(); } private int chart_padding() { // whitespace between charts if (vzoom_level <= 1) { return 0; } if (vzoom_level <= 4) { return 1; } { int pixels = 4 * stackRowHeight / STANDARD_WHITESPACE_PIXELS / 3; if (pixels < STANDARD_WHITESPACE_PIXELS) { return pixels; } } return STANDARD_WHITESPACE_PIXELS; } private int calcRowHeight( final Graphics g, final RowDefinition rowDef, final int chartIdx, final int subrowNum, final int nCharts) { final int stackBaseline = 18; Settings.TLData_type dataType = rowDef.getTLDataType(); if (chartIdx == -1 && dataType.equals(Settings.TLData_type.TL_SAMPLE)) { // sample event data if (vzoom_level <= NUM_VZOOM_MACRO_LEVELS) { int sz = DEFAULT_SAMPLE_HEIGHT * (vzoom_level + 1) / (NUM_VZOOM_MACRO_LEVELS + 2); return sz; } return nominalSampleHeight; } if (chartIdx == -1 && dataType.equals(Settings.TLData_type.TL_GCEVENT)) { // CXXX Bug 20801848 // gc event data if (vzoom_level <= NUM_VZOOM_MACRO_LEVELS) { int sz = DEFAULT_SAMPLE_HEIGHT * (vzoom_level + 1) / (NUM_VZOOM_MACRO_LEVELS + 2); return sz; } return nominalSampleHeight; } if (dataType.equals(Settings.TLData_type.TL_HEAPSZ)) { // heapsize event data and chart if (chartIdx == -1) { // event data if (vzoom_level <= 1) { return 2; } return EVENT_TICK_HEIGHT; } // chart data if (rowDef.getChartProperties().get(chartIdx).getName().equals("HTYPE")) { return MIN_CHART_HEIGHT; } if (vzoom_level <= NUM_VZOOM_MACRO_LEVELS) { int sz = DEFAULT_HEAPSZ_HEIGHT * (vzoom_level + 1) / (NUM_VZOOM_MACRO_LEVELS + 2); return sz; } return nominalHeapszHeight; } if (chartIdx == -1) { // event data if (nCharts == 0) { // standalone event if (vzoom_level <= 0) { return 1; } if (vzoom_level <= 1) { return 2; } if (vzoom_level <= 2) { return 3; } if (vzoom_level <= 3) { return 4; } // if (vzoom_level<=4) { // return EVENT_TICK_HEIGHT; // } return stackRowHeight; } else { // charts follow this event row if (vzoom_level <= 1) { return 0; } if (vzoom_level <= 2) { return 2; } if (vzoom_level <= 3) { return 3; } // if (vzoom_level<=4) { // return EVENT_TICK_HEIGHT; // } return stackRowHeight; } } // chart data if (stackRowHeight > stackBaseline) { int chartHeight = MIN_CHART_HEIGHT; chartHeight += (stackRowHeight - stackBaseline) / 15; if (chartHeight > MAX_CHART_HEIGHT) { chartHeight = MAX_CHART_HEIGHT; } return chartHeight; } if (vzoom_level <= 0) { return 1; } if (vzoom_level <= 1) { return 2; } if (vzoom_level <= 2) { return 3; } if (vzoom_level <= 3) { return 5; } return MIN_CHART_HEIGHT; } public int rowNum2EntityNum(int rowNum) { if (rowNum < 0 || rowNum >= rowNumToEntityNum.size()) { return -1; // weird } int entityNum = rowNumToEntityNum.get(rowNum); return entityNum; } public RowGeometry rowNum2RowGeometry(int rowNum) { if (rowNum < 0 || rowNum >= rowGeometry.size()) { return null; // weird; } RowGeometry rowGeo = rowGeometry.get(rowNum); // YXXX sync rowGeometry? return rowGeo; } public List<RowGeometry> getRowGeometry() { return rowGeometry; } public void edt_processDataSnapshot( TL2DataSnapshot dataSnapshot, boolean forceRecalc, Graphics g /* may be null */) { if (!forceRecalc && recentDataSnapshot == dataSnapshot && !forceRowGeometry) { return; } recentDataSnapshot = dataSnapshot; rowGeometry = new ArrayList(); rowGeometryByEntity = new ArrayList(); rowNumToEntityNum = new ArrayList(); usedHeight = 0; // # of pixels used on virtual vertical axis { // set globals used in selecting spacing int zero_based_zoom = vzoom_level - NUM_VZOOM_MACRO_LEVELS; if (zero_based_zoom < 0) { zero_based_zoom = 0; } int stepFactor = MAX_STACK_PIXELS / (TIMELINE_MAX_VZOOM_LEVEL - NUM_VZOOM_MACRO_LEVELS) - VZOOM_BASE_PIXEL_STEP; double zoomPixelStep = VZOOM_BASE_PIXEL_STEP + (double) stepFactor * zero_based_zoom / (TIMELINE_MAX_VZOOM_LEVEL - NUM_VZOOM_MACRO_LEVELS); int pixelsForCallstacks = (int) (zoomPixelStep * zero_based_zoom); stackRowHeight = pixelsForCallstacks + EVENT_TICK_HEIGHT; nominalSampleHeight = DEFAULT_SAMPLE_HEIGHT + pixelsForCallstacks / 6; if (nominalSampleHeight > MAX_SAMPLE_HEIGHT) { nominalSampleHeight = MAX_SAMPLE_HEIGHT; } nominalHeapszHeight = DEFAULT_HEAPSZ_HEIGHT + pixelsForCallstacks / 2; if (nominalHeapszHeight > MAX_HEAPSZ_HEIGHT) { nominalHeapszHeight = MAX_HEAPSZ_HEIGHT; } } List<ExperimentData> expList; final int overallEntityCount; if (dataSnapshot == null) { expList = new ArrayList(); overallEntityCount = 0; } else { expList = dataSnapshot.getExperimentData(); overallEntityCount = dataSnapshot.getEntityData().size(); } int currentY = 1; // upper border is 1 pixel wide int rowGeometryNum = 0; // First scan rows to determine where dividers are needed: List<Boolean> entityNeedsSubDividers = new ArrayList(overallEntityCount); List<Boolean> entityNeedsDividers = new ArrayList(overallEntityCount); boolean someEntityHasSubDividers = false; boolean someEntityHasDividers = false; boolean someEntityIsSampleOrHeapsz = false; int maxEntities = 0; for (ExperimentData expData : expList) { final int numEntities = expData.experimentEntities.size(); if (maxEntities < numEntities) { maxEntities = numEntities; } for (int kk = 0; kk < numEntities; kk++) { EntityData entityData = expData.experimentEntities.get(kk); // determine if sub-divider lines are needed within this entity boolean needsSubDividers = false; boolean needsDivider = false; boolean hasSampleOrHeapsz = false; // see if we need subDividers: int numEntityDataTypes = entityData.entityRows.size(); for (RowData rowData : entityData.entityRows) { RowDefinition rowDef = rowData.rowDefinition; final int numCharts = rowDef.getChartCount(); Settings.TLData_type dataType = rowDef.getTLDataType(); if (dataType.equals(Settings.TLData_type.TL_HEAPSZ) || dataType.equals(Settings.TLData_type.TL_SAMPLE)) { hasSampleOrHeapsz = true; if (numEntityDataTypes > 1) { needsSubDividers = true; } } if (numCharts > 0 && numEntityDataTypes > 1) { // has multiple events and charts if (stackRowHeight > 8) { needsSubDividers = true; } if (vzoom_level >= 3) { needsSubDividers = true; } } } final boolean isExperimentEnd = (kk == numEntities - 1); // see if we need dividers: if (!isExperimentEnd) { if (needsSubDividers) { needsDivider = true; } if (vzoom_level >= 2) { needsDivider = true; } if (hasSampleOrHeapsz) { needsDivider = true; } } entityNeedsDividers.add(needsDivider); entityNeedsSubDividers.add(needsSubDividers); if (needsSubDividers) { someEntityHasSubDividers = true; } if (needsDivider) { someEntityHasDividers = true; } if (hasSampleOrHeapsz) { someEntityIsSampleOrHeapsz = true; } } } if (entityNeedsDividers.size() != overallEntityCount) { int xx = 1; // weird! } final boolean procDividersNeeded; if (someEntityHasSubDividers || someEntityHasDividers || someEntityIsSampleOrHeapsz || vzoom_level >= 3 || maxEntities > 1) { procDividersNeeded = true; } else { procDividersNeeded = false; } final int subDividerThickness = someEntityHasSubDividers ? 1 : 0; final int entityDividerThickness = someEntityHasDividers ? subDividerThickness + 1 : subDividerThickness; final int procDividerThickness = procDividersNeeded ? entityDividerThickness + 1 : 0; final int expGroupDividerThickness = 5; final int numExperiments = expList.size(); for (int kk = 0; kk < numExperiments; kk++) { ExperimentData expData = expList.get(kk); final int numEntities = expData.experimentEntities.size(); for (int jj = 0; jj < numEntities; jj++) { int overallEntityNum = rowGeometryByEntity.size(); EntityData entityData = expData.experimentEntities.get(jj); boolean isEntityStart = true; boolean isEntityEnd = false; int numEntityDataTypes = entityData.entityRows.size(); List<RowGeometry> entityGeos = new ArrayList(); boolean needsSubDividers = entityNeedsSubDividers.get(overallEntityNum); for (int ii = 0; ii < numEntityDataTypes; ii++) { // row within entity (entity's DATA* type) RowData rowData = entityData.entityRows.get(ii); // For each rowData element, there is one row of data events and N charts RowDefinition rowDef = rowData.rowDefinition; final int numCharts = rowDef.getChartCount(); int postRowDividerHeight = 0; RowGeometry masterRow = null; final int startSubrow = rowGeometryNum; for (int subrowNum = 0; subrowNum <= numCharts; subrowNum++) { final int chartIdx = subrowNum - 1; // -1 is for "events" final int startY = currentY; currentY += calcRowUpperPadding(g, rowDef, chartIdx, subrowNum, numCharts); final int dataStartY = currentY; currentY += calcRowHeight(g, rowDef, chartIdx, subrowNum, numCharts); final int dataEndY = currentY - 1; boolean isExperimentEnd = false; boolean isCompareGroupEnd = false; if (subrowNum == numCharts) { // last row for metric if (ii == numEntityDataTypes - 1) { // last row of entity isEntityEnd = true; isExperimentEnd = (jj == numEntities - 1); if (isExperimentEnd) { // determine if isCompareGroupEnd: if (kk == numExperiments - 1 && rowDef.getComparisonOn()) { isCompareGroupEnd = true; } else if (kk < numExperiments - 1) { ExperimentData nextExpData = expList.get(kk + 1); int nextGroupId = nextExpData .experimentEntities .get(0) .entityRows .get(0) .getRowDef() .getExpGroupId(); int groupId = rowDef.getExpGroupId(); if (groupId != nextGroupId) { isCompareGroupEnd = true; } } if (isCompareGroupEnd) { postRowDividerHeight = expGroupDividerThickness; } else { postRowDividerHeight = procDividerThickness; } } else if (entityNeedsDividers.get(overallEntityNum)) { postRowDividerHeight = entityDividerThickness; } } else { // not last row of entity if (needsSubDividers) { postRowDividerHeight = subDividerThickness; } } } currentY += calcRowLowerPadding(g, rowDef, chartIdx, subrowNum, numCharts); final int endY = currentY - 1; final String propName, propUName; if (chartIdx == -1) { propName = "MSTATE"; // YXXX actually, only needed for samples propUName = "Process Microstates"; } else { List<PropDescriptor> chartProps = rowDef.getChartProperties(); propName = chartProps.get(chartIdx).getName(); propUName = chartProps.get(chartIdx).getDescription(); } RowGeometry subRow = new RowGeometry( rowGeometryNum, rowGeometry, numCharts + 1, subrowNum, rowData, // note: rowData is not fully populated yet chartIdx, propName, propUName, startY, endY, dataStartY, dataEndY, isEntityStart, isEntityEnd, isExperimentEnd, isCompareGroupEnd, postRowDividerHeight); if (chartIdx == -1) { masterRow = subRow; } rowGeometryNum++; rowNumToEntityNum.add(overallEntityNum); rowGeometry.add(subRow); entityGeos.add(subRow); isEntityStart = false; } // numCharts int tmpRowNum = startSubrow; for (int subrowNum = 0; subrowNum <= numCharts; subrowNum++) { RowGeometry tmp = rowGeometry.get(tmpRowNum); tmp.setMasterRow(masterRow); tmpRowNum++; } currentY += postRowDividerHeight; } // data types rowGeometryByEntity.add(entityGeos); } // entities } // experiments usedHeight = currentY; if (rowGeometryByEntity.size() != overallEntityCount) { int xx = 1; // weird! } // used by coord calculator ArrayList<Integer> tmpOffsets = new ArrayList(); int ypos = 0; for (RowGeometry row : rowGeometry) { int delta = row.endY - ypos; tmpOffsets.add(delta); ypos = row.endY; } rowOffsets = tmpOffsets; forceRowGeometry = false; forceFullRepaint = true; dataAxisMaster.setAbsRowMinHeights(tmpOffsets); // YXXX check above call to see if it can cause feedback loop } private int getBinStartOffset(RowData dataCopy) { // Inputs: dataCopy is stable snapshot returned from RowData.grabEventData() // Returns: the # of bins from start of data in dataCopy to first bin visible on screen // or INVALID_BIN if no data is available for visible portion of screen. // Example: Suppose the TL view is 1000 pixels wide, and dataCopy has 2000 pixels // of valid data with 300 pixels off screen on the left and 700 off screen on the right. // The return value for this function would be 300, the first visible data bin. int offset = 0; if (!dataCopy.eventDataIsValid()) { return INVALID_BIN; } RowDataRequestParams params = dataCopy.getParams(); if (params == null) { return INVALID_BIN; // weird } long binTime = timeAxisCalculator.getTimePerBin(); if (binTime != params.binTime) { return INVALID_BIN; // zooming, data is stale } long fetchStart = params.alignedTimeStart; long visibleStart = timeAxisCalculator.getTimeStartAligned(); long delta = visibleStart - fetchStart; offset = (int) (delta / binTime); if (binTime * offset != delta) { return INVALID_BIN; // weird, not aligned } if (offset < 0) { // data is shifted so far right, there's a hole int ii = 0; // for breakpoint } return offset; } private void setScrollY(List<RowGeometry> rowGeometry, int scrollY, int visibleHeight) { if (currScrollY != scrollY || currVisibleHeight != visibleHeight) { currScrollY = scrollY; currVisibleHeight = visibleHeight; forceFullRepaint = true; } int rowCount = rowGeometry.size(); int newRowFirst = rowCount; int newRowLast = rowCount; for (int ii = 0; ii < rowCount; ii++) { // YXXX slow... RowGeometry row = rowGeometry.get(ii); int virtualY = row.endY - scrollY; if (newRowFirst == rowCount && virtualY > 0) { newRowFirst = ii; } virtualY = row.startY - scrollY; if (virtualY > visibleHeight) { newRowLast = ii; break; } } if (currRowFirst != newRowFirst || currRowLast != newRowLast) { currRowFirst = newRowFirst; currRowLast = newRowLast; forceFullRepaint = true; } } private void drawVisibleRows( final Graphics g, final List<RowGeometry> rowGeometry, final int visibleWidth) { for (int ii = currRowFirst; ii < currRowLast; ii++) { final RowGeometry row = rowGeometry.get(ii); final RowData dataCopy = row.rowData.grabEventData(); // row.rowData is volatile, get snapshot final int binStartOffset = getBinStartOffset(dataCopy); if (binStartOffset == INVALID_BIN) { // offset could not be determined int rowCenter = (row.dataEndY + row.dataStartY) / 2 - currScrollY; drawCenteredMessage(g, AnLocale.getString("Fetching Data..."), visibleWidth / 2, rowCenter); continue; } if (!row.isChartData()) { // specifies the events themselves GenericEvent[] events = dataCopy.getEvents(); drawRowEvents(g, row, events, binStartOffset, visibleWidth, false, true); continue; } // specifies a chart final Object vals = dataCopy.getChartData(row.chartPropIdx); if (vals instanceof long[]) { long longVals[] = (long[]) vals; Settings.TLData_type dataType = row.rowData.rowDefinition.getTLDataType(); final boolean preferZeroYOrigin = dataType.equals(Settings.TLData_type.TL_HEAPSZ) ? false : true; // final boolean preferZeroYOrigin = true; drawRowChartValues( g, row, dataCopy, longVals, binStartOffset, visibleWidth, preferZeroYOrigin); } else if (vals instanceof SampleEvent[]) { SampleEvent sampleEvents[] = (SampleEvent[]) vals; drawRowEvents(g, row, sampleEvents, binStartOffset, visibleWidth, false, false); } else { continue; // weird, vals is unexpected type } } } private void drawVisibleDividers( final Graphics g, final List<RowGeometry> rowGeometry, final int visibleWidth) { int x1 = 0; int x2 = visibleWidth; if (currScrollY == 0) { drawSolidDivider(g, STANDARD_DIVIDER_COLOR, x1, x2, 0, 1); } for (int ii = currRowFirst; ii < currRowLast; ii++) { RowGeometry row = rowGeometry.get(ii); if (row.rowDividerHeight > 0) { // divider below this row int y = row.endY - currScrollY + 1; if (row.isCompareGroupEnd) { drawDashedDivider(g, COMPARE_GRP_DIVIDER_COLOR, x1, x2, y, row.rowDividerHeight); } else if (row.isExperimentEnd) { drawSolidDivider(g, EXPERIMENT_DIVIDER_COLOR, x1, x2, y, row.rowDividerHeight); } else if (row.isEntityEnd) { drawSolidDivider(g, STANDARD_DIVIDER_COLOR, x1, x2, y, row.rowDividerHeight); } else { drawSolidDivider(g, STANDARD_DIVIDER_COLOR, x1, x2, y, row.rowDividerHeight); } } } } public static void drawSolidDivider( Graphics g, Color color, final int x1, final int x2, final int y, final int thickness) { g.setColor(color); for (int ii = 0; ii < thickness; ii++) { g.drawLine(x1, y + ii, x2, y + ii); } } public static void drawDashedDivider( Graphics g, Color color, final int x1, final int x2, int y, int thickness) { g.setColor(color); if (thickness > 2) { int ii = 0; g.drawLine(x1, y + ii, x2, y + ii); ii += thickness - 1; g.drawLine(x1, y + ii, x2, y + ii); thickness -= 2; y += 1; } for (int ii = 0; ii < thickness; ii++) { int x = x1 - (2 * ii); int step = 3; final int space = (thickness > 1) ? 6 : 2; while (x < x2) { if (step > x2 - x) { step = x2 - x; } g.drawLine(x, y + ii, x + step - 1, y + ii); x += step + space; } } } private void drawRowEvents( Graphics g, final RowGeometry row, final GenericEvent[] events, final int binStartOffset, final int visibleWidth, final boolean drawingSelectedItem, final boolean showDivisions) { if (events == null) { return; } if (events.length == 0) { return; } final int rowStartY = row.startY - currScrollY; final int rowEndY = row.endY - currScrollY; final int dataStartY = row.dataStartY - currScrollY; final int dataEndY = row.dataEndY - currScrollY; final TimelineVariable.StatesDisplayInfo stateInfo; if (events[0] instanceof SampleEvent) { // see TLExperiment.getChartProps() stateInfo = TimelineVariable.getStateInfo(row.propName); } else { stateInfo = null; } boolean forceToSingleBin = false; RowDefinition rowDef = row.rowData.rowDefinition; if (!row.isChartData() && rowDef.getTLDataType().equals(Settings.TLData_type.TL_CLOCK)) { // Hack to show clock profiling callstacks as a point in time // ... but show microstate bar for the full duration forceToSingleBin = true; } // repaint row int prev_event_x = 0; // remember where previous event ended int prev_event_x_tick = -2; // remember previous event tick end for (int ii = 0; ii < events.length; ii++) { final GenericEvent event = events[ii]; final int eventbinStart = event.binStart - binStartOffset; final int nbins = timeAxisCalculator.getNumBins(); final int binStart, binCount; if (forceToSingleBin && event.binCount > 1) { binStart = eventbinStart + event.binCount - 1; binCount = 1; } else { binStart = eventbinStart; binCount = event.binCount; } if (binStart > nbins + FATTENED_EVENT_WIDTH) { break; } if (binStart + binCount < 0) { continue; } if (binCount < 1) { continue; // happens when an event end overlaps with an event start, needs fix in DBE } int w; int x; int xLeftEdge, xRightEdge; { int binEnd = binStart + binCount - 1; int xStart = timeAxisCalculator.getLowCoordForBin(binStart); int xEnd = timeAxisCalculator.getLowCoordForBin(binEnd + 1) - 1; w = xEnd - xStart + 1; x = xStart; xLeftEdge = xStart; xRightEdge = xEnd; } boolean shortTick = true; boolean standaloneTick = true; if (w < FATTENED_EVENT_WIDTH && !row.rowData.rowDefinition.getTLDataType().equals(Settings.TLData_type.TL_GCEVENT)) { // attempt to fatten event int extension = (FATTENED_EVENT_WIDTH - w) / 2; // how much to add to each side // widen right side first int adjustedW; final int next_xStart; if (ii + 1 < events.length) { // check distance to event on right final GenericEvent nextEvent = events[ii + 1]; final int nextEventbinStart = nextEvent.binStart - binStartOffset; final int nextBinStart; if (forceToSingleBin && nextEvent.binCount > 1) { nextBinStart = nextEventbinStart + nextEvent.binCount - 1; } else { nextBinStart = nextEventbinStart; } next_xStart = timeAxisCalculator.getLowCoordForBin(nextBinStart); int avail = (next_xStart - (x + w)) / 2; if (avail < 0) { // overlapping events // note: intentinally not merged with next case adjustedW = w + avail; // shorten this event if (adjustedW < 1) { adjustedW = 1; // weird, not expected } } else if (avail < extension) { // not overlapping, but cramped adjustedW = w + avail; } else { // enough space for full expansion adjustedW = w + extension; } } else { adjustedW = w + extension; next_xStart = -1; } // now widen left side int adjustedX; if (prev_event_x < x - extension) { adjustedX = x - extension; } else { adjustedX = prev_event_x + 1; } adjustedW += x - adjustedX; // make tick marks of different heights (visual cue to zoom to see details) if (xLeftEdge == next_xStart - 1 && xLeftEdge == prev_event_x_tick + 1) { // touching both previous and next ticks // if(event.binNSamples>1){ // there are hidden events if ((xLeftEdge % 4) == 0) { // add special jagged edge // only use tall ticks for every third adjacent tick shortTick = false; // } } } if (xLeftEdge == next_xStart - 1 || xLeftEdge == prev_event_x_tick + 1) { standaloneTick = false; } w = adjustedW; x = adjustedX; } int x2 = x + w - 1; prev_event_x = x2; prev_event_x_tick = xRightEdge; if (event instanceof SampleEvent) { // YXXX how inefficient is this? SampleEvent sampleEvt = (SampleEvent) event; drawSampleEvent( g, sampleEvt.propValues, stateInfo, x, x2, dataStartY, dataEndY, drawingSelectedItem, showDivisions); } else if (event instanceof StackEvent) { StackEvent stackEvt = (StackEvent) event; drawStackEvent( g, stackEvt, x, x2, dataStartY, dataEndY, xLeftEdge, xRightEdge, drawingSelectedItem, shortTick, standaloneTick); } else if (event instanceof GenericEvent) { // CXXX Bug 20801848 - maybe add a function drawGCEvent() drawGenericEvent(g, x, x2, dataStartY, dataEndY, drawingSelectedItem, showDivisions); } else { int foo = 0; // weird } } if (!drawingSelectedItem) { drawRowVBorders(g, rowStartY, rowEndY, -1, -1); } } private int[] getRowVisibleBinMinMax(final RowData dataCopy) { // return minimum and maximum bin for valid data // if no valid data is visible, returns (Integer.MAX_VALUE, Integer.MIN_VALUE) final int[] minMaxNA = {Integer.MAX_VALUE, Integer.MIN_VALUE}; if (dataCopy == null || !dataCopy.eventDataIsValid()) { return minMaxNA; } int lowBinLimit = 0; int highBinLimit = timeAxisCalculator.getNumBins() - 1; { // limit chart to experiment's time boundaries final long timeOffset = dataCopy.rowDefinition.getTimeOrigin(); final long wallTimeStart = dataCopy.rowDefinition.getDataTimeStart() - timeOffset; final long wallTimeEnd = dataCopy.rowDefinition.getDataTimeEnd() - timeOffset; final long visibleStart = timeAxisCalculator.getTimeStart(); final long visibleEnd = timeAxisCalculator.getTimeEnd(); if (wallTimeStart > visibleStart) { if (wallTimeStart > visibleEnd) { return minMaxNA; } lowBinLimit = timeAxisCalculator.getBinAtTime(wallTimeStart); } if (wallTimeEnd < visibleEnd) { if (wallTimeEnd < visibleStart) { return minMaxNA; } highBinLimit = timeAxisCalculator.getBinAtTime(wallTimeEnd); } } int[] loHi = {lowBinLimit, highBinLimit}; return loHi; } private void drawRowChartValues( Graphics g, final RowGeometry row, final RowData dataCopy, final long longVals[], int binStartOffset, final int visibleWidth, final boolean preferZeroYOrigin) { final int rowStartY = row.startY - currScrollY; final int rowEndY = row.endY - currScrollY; final int dataStartY = row.dataStartY - currScrollY; final int dataEndY = row.dataEndY - currScrollY; final int rowHeight = dataEndY - dataStartY + 1; final int[] binMinMax = getRowVisibleBinMinMax(dataCopy); final int lowBinLimit = binMinMax[0]; final int highBinLimit = binMinMax[1] + 1; // +1 is fudge for missing pixel at some zooms int borderHeight = rowHeight < 6 ? 0 : 1; final int yOrigin = dataEndY - borderHeight; // -1 for bottom border final int lineThickness = rowHeight < 6 ? 1 : 2; final int dataHeight = rowHeight - 2 * borderHeight - (lineThickness - 1); // -1 for highlight // compute vertical scale long min_val = Long.MAX_VALUE; long max_val = Long.MIN_VALUE; int startBin = binStartOffset >= 0 ? binStartOffset : 0; for (int bin = startBin; bin < longVals.length; bin++) { final int visibleBin = bin - binStartOffset; if (visibleBin > highBinLimit) { break; } if (visibleBin < lowBinLimit) { continue; } // only consider visible time when computing y range long val = longVals[bin]; if (min_val > val) { min_val = val; } if (max_val < val) { max_val = val; } } if (min_val > 0 && preferZeroYOrigin) { min_val = 0; // zero Y origin unless minimum is negative } if (min_val == Long.MAX_VALUE) { min_val = 0; } if (max_val == Long.MIN_VALUE) { max_val = 0; } final long range = max_val - min_val; final double scale; if (range == 0) { scale = 0; } else { scale = (double) (dataHeight - lineThickness) / range; } // fill background { int xMargin = timeAxisCalculator.getMargin(); int x1 = xMargin; int x2 = visibleWidth - xMargin; drawHorizontalBand( g, x1, dataStartY, x2, dataEndY, CHART_BORDER_COLOR, CHART_BACKGROUND_COLOR); drawCaliper(g, dataStartY + 1, dataEndY - 1, CHART_BACKGROUND_SEL_COLOR); } // draw line g.setColor(CHART_GRAPH_COLOR); int peakStart = -1; int peakY = 0; int prevX = 0; int prevY = 0; long prevVal = 0; boolean firstTime = true; boolean lastTime = false; for (int bin = startBin; bin < longVals.length; bin++) { final int visibleBin = bin - binStartOffset; if (visibleBin == highBinLimit || bin == longVals.length - 1) { lastTime = true; } if (visibleBin > highBinLimit) { break; } if (visibleBin < lowBinLimit) { continue; } // calc vertical final Long curVal = longVals[bin] - min_val; final int h = (int) Math.round(scale * curVal); final int currY = yOrigin - h; // just above top of grey bar // calc horizonal final int x1 = timeAxisCalculator.getLowCoordForBin(visibleBin); final int x2 = timeAxisCalculator.getLowCoordForBin(visibleBin + 1) - 1; int centerX = (x1 + x2) / 2; if (firstTime) { prevY = currY; prevVal = curVal; prevX = x1; firstTime = false; } if (dataHeight > 3) { g.drawLine(prevX, prevY, centerX, currY); if (lineThickness != 1) { if (!(curVal == 0 && prevVal == 0)) { // only show non-baseline values thicker g.drawLine(prevX, prevY - 1, centerX, currY - 1); } } } else { if (!(curVal == 0 && prevVal == 0)) { // only show non-baseline values g.drawLine(prevX, prevY, centerX, currY); } } // highlight peaks boolean isPeak = (max_val == longVals[bin] && max_val != min_val); if (max_val == 1) { // don't highlight bins with just one event // note: won't work if values are based on HWC counts or time. isPeak = false; } if (isPeak) { if (peakStart == -1) { peakStart = centerX; } peakY = currY; } if (peakStart != -1 && (!isPeak || lastTime)) { // we know the end of the peak; let's draw the highlight int peakEnd = centerX; if (!isPeak) { peakEnd--; // we passed the peak } int delta = peakEnd - peakStart; final int min_peak_width = 4; if (delta < min_peak_width) { int fatten = (min_peak_width - delta + 1) / 2; peakEnd += fatten; peakStart -= fatten; } g.setColor(CHART_GRAPH_COLOR_MAX); int yOffset = peakY - lineThickness - borderHeight + 1; g.drawLine(peakStart, yOffset, peakEnd, yOffset); if (lineThickness != 1) { g.drawLine(peakStart, yOffset - 1, peakEnd, yOffset - 1); } g.setColor(CHART_GRAPH_COLOR); peakStart = -1; } prevY = currY; prevVal = curVal; prevX = centerX; } FontInfo title_font = getSmallFont(g); FontInfo value_font = getSmallBoldFont(g); if (title_font != null && value_font != null && value_font.height - 3 <= dataStartY - rowStartY) { // add Labels int xMargin = timeAxisCalculator.getMargin(); int xMax = timeAxisCalculator.getCanvasPixels() - xMargin; int xMin = xMargin; int textStartY = dataStartY - 1 - title_font.height + title_font.ascent; final String chartTitle = row.propUName; int chartTitleWidth = stringWidth(g, title_font.font, chartTitle); String yValue = getString(max_val); int yValueWidth = stringWidth(g, value_font.font, yValue); // Chart Title if (chartTitleWidth + yValueWidth < xMax - xMin - 10) { g.setColor(Color.BLACK); g.setFont(title_font.font); g.drawString(chartTitle, xMin + 1, textStartY); } // Y low and high values g.setColor(CHART_NUMERIC_TEXT_COLOR); g.setFont(value_font.font); if (yValueWidth < xMax - xMin) { g.drawString(yValue, xMax - yValueWidth - 1, textStartY); } if (value_font.height + 2 < dataHeight) { yValue = getString(min_val); yValueWidth = stringWidth(g, value_font.font, yValue); textStartY = yOrigin - value_font.height + value_font.ascent; g.drawString(yValue, xMax - yValueWidth - 1, textStartY); } } drawRowVBorders(g, rowStartY, rowEndY, dataStartY, dataEndY); } private void drawHorizontalBand( final Graphics g, final int x1, final int y1, final int x2, final int y2, final Color border, final Color fill) { g.setColor(fill); g.fillRect(x1, y1, x2 - x1, y2 - y1); g.setColor(border); g.drawLine(x1, y1, x2, y1); g.drawLine(x1, y2, x2, y2); g.setColor(Color.BLACK); } private String getString(long val) { Long lval = new Long(val); return lval.toString(); } private int stringWidth(final Graphics g, Font font, String stmp) { int strPixels = g.getFontMetrics(font).stringWidth(stmp); return strPixels; } private void drawStackEvent( Graphics g, final StackEvent thisEvent, final int startX, final int endX, final int startY, final int endY, final int xLeftEdge, final int xRightEdge, final boolean doSetSelected, boolean shortTick, boolean standaloneTick) { final int x = startX; final int wid = endX - startX + 1; final int height = endY - startY + 1; if (doSetSelected && height < 1) { setSelectionBounds(startX, startY, wid, height); return; } if (height < 1) { return; } final int nominalSegmentHeight = stack_frame_pixels; // check user's "cpu idle color" setting boolean useIdleColor = false; if (idle_color_set && thisEvent.mState > 1) { // YXXX yuck! if (idle_color == null) { return; } useIdleColor = true; } // determine stack alignment based on user settings final int numFrames; final int startFrame; final int frameInc; final int anchorY; final int tickY; final int topEdgeOfStack; final long[] stackFuncs = tl2DataFetcher.getStackFuncArray(thisEvent.stackId); final int tick_height = height >= EVENT_TICK_HEIGHT ? EVENT_TICK_HEIGHT : height; final int nominalHeight = tick_height + stack_frame_pixels * stackFuncs.length; final boolean truncated = nominalHeight > (endY - startY + 1); final int framesThatFit = (height - tick_height + stack_frame_pixels - 1) / stack_frame_pixels; if (stackFuncs.length > framesThatFit) { numFrames = framesThatFit; } else { numFrames = stackFuncs.length; } if (stack_align == Settings.TLStack_align.TLSTACK_ALIGN_ROOT) { startFrame = stackFuncs.length - 1; // main frameInc = -1; anchorY = 1 + endY - tick_height - nominalSegmentHeight; tickY = 1 + endY - tick_height; int _topEdgeOfStack = 1 + endY - tick_height - numFrames * nominalSegmentHeight; if (_topEdgeOfStack < startY) { topEdgeOfStack = startY; } else { topEdgeOfStack = _topEdgeOfStack; } } else { startFrame = 0; // leaf frameInc = 1; anchorY = startY + tick_height; tickY = startY; topEdgeOfStack = anchorY; } // draw stack boundary tick marks if (standaloneTick) { g.setColor(TICK_ONE_PIXEL_WIDE_COLOR); } else if (numFrames > 0) { g.setColor(TICK_WITH_STACK_COLOR); } else { g.setColor(TICK_STANDALONE_COLOR); } if (tick_height < 2) { // row is squashed to very few pixels, widen event to make it visible if (xLeftEdge != xRightEdge) { g.drawLine(xRightEdge - 1, tickY, xRightEdge, tickY); } g.drawLine(xLeftEdge - 1, tickY, xLeftEdge, tickY); } else { int tickYStart = tickY; int tickYEnd = tickY + tick_height - 1; if (shortTick && tick_height > 2) { tickYEnd -= 1; } if (xLeftEdge != xRightEdge) { g.drawLine(xRightEdge, tickYStart, xRightEdge, tickYEnd); } g.drawLine(xLeftEdge, tickYStart, xLeftEdge, tickYEnd); // if (thisEvent.binNSamples > 1) { // g.drawLine(xLeftEdge - 1, tickYStart, xLeftEdge - 1, tickYEnd); // } } // draw the stack Color color = idle_color; int stackHeight = 0; for (int ii = 0, frame = startFrame; ii < numFrames; ii++, frame += frameInc) { int segmentHeight = nominalSegmentHeight; if (!useIdleColor) { if (doSetSelected || stateColorSnapshot == null) { // selected objects are fetched later, color may not be in stateColorSnapshot color = colorMap.getFuncColor(stackFuncs[frame]); // slower, requires lock } else { color = stateColorSnapshot.getColorMap().get(stackFuncs[frame]); } if (color == null) { color = Color.LIGHT_GRAY; } } int yPos = anchorY + ii * segmentHeight * frameInc; if (yPos < startY) { segmentHeight -= (startY - yPos); yPos = startY; } int tmpEndY = yPos + segmentHeight - 1; if (tmpEndY > endY) { segmentHeight -= (tmpEndY - endY); } if (segmentHeight <= 0) { continue; // weird } stackHeight += segmentHeight; g.setColor(color); g.fillRect(x, yPos, wid, segmentHeight); if (ii == numFrames - 1 && truncated) { int y = (frameInc > 0) ? yPos + segmentHeight - 1 : yPos; Color darker = color.darker(); g.setColor(darker); g.drawLine(x, y, x + wid - 1, y); } } if (doSetSelected) { setSelectionBounds(x, topEdgeOfStack, wid, stackHeight); } } private void drawSampleEvent( final Graphics g, final long stateVals[], TimelineVariable.StatesDisplayInfo stateInfo, final int startX, final int endX, final int startY, final int endY, final boolean doSetSelected, boolean showDivisions) { final long propValues[] = stateInfo.raw2displayValues(stateVals); if (propValues == null || propValues.length == 0) { return; } final int event_w = endX - startX + 1; final int sampleHeight = endY - startY + 1; // calc total double total = 0; for (long val : propValues) { total += val; } if (total == 0) { return; } final int x = startX; final int w = event_w; // draw sample colors long sum_time = 0; int yPrev = startY + SAMPLE_BORDER_HEIGHT; int dataHeight = sampleHeight - SAMPLE_BORDER_HEIGHT * 2; for (int i = 0; i < propValues.length; i++) { sum_time += propValues[i]; double percent = sum_time / total; int height = (int) Math.round(percent * dataHeight); int yNew = startY + height + SAMPLE_BORDER_HEIGHT; if (yNew > yPrev) { final Color color = stateInfo.getColorByDisplayIdx(i); g.setColor(color); g.fillRect(x, yPrev, w, yNew - yPrev); } yPrev = yNew; } // vertical dividers if (showDivisions && w >= MIN_SAMPLE_3D_WIDTH) { final int y1 = startY + sampleHeight - 1 - SAMPLE_BORDER_HEIGHT; final int y2 = startY + SAMPLE_BORDER_HEIGHT; final int x1 = x; final int x2 = x + w - 1; // g.setColor(Color.LIGHT_GRAY); // g.drawLine(x1, y1, x1, y2); g.setColor(SAMPLE_VDIVIDER_COLOR); g.drawLine(x2, y1, x2, y2); } if (SAMPLE_BORDER_HEIGHT > 0 && SAMPLE_BORDER_COLOR != null) { final int y1 = startY + sampleHeight - 1; final int y2 = startY; final int x1 = x; final int x2 = x + w - 1; g.setColor(SAMPLE_BORDER_COLOR); g.drawLine(x1, y1, x2, y1); g.drawLine(x1, y2, x2, y2); } if (doSetSelected) { setSelectionBounds(x, startY, w, sampleHeight); } } // CXXX Bug 20801848 - maybe change to drawGCEvent() private void drawGenericEvent( final Graphics g, final int startX, final int endX, final int startY, final int endY, final boolean doSetSelected, boolean showDivisions) { final int event_w = endX - startX + 1; final int sampleHeight = endY - startY + 1; final int x = startX; final int w = event_w; int yPrev = startY + SAMPLE_BORDER_HEIGHT; int dataHeight = sampleHeight - SAMPLE_BORDER_HEIGHT * 2; g.setColor(Color.GRAY); int yNew = startY + dataHeight + SAMPLE_BORDER_HEIGHT; g.fillRect(x, yPrev, w, yNew - yPrev); // vertical dividers if (showDivisions && w >= MIN_SAMPLE_3D_WIDTH) { final int y1 = startY + sampleHeight - 1 - SAMPLE_BORDER_HEIGHT; final int y2 = startY + SAMPLE_BORDER_HEIGHT; final int x1 = x; final int x2 = x + w - 1; // g.setColor(Color.LIGHT_GRAY); // g.drawLine(x1, y1, x1, y2); g.setColor(SAMPLE_VDIVIDER_COLOR); g.drawLine(x2, y1, x2, y2); } if (SAMPLE_BORDER_HEIGHT > 0 && SAMPLE_BORDER_COLOR != null) { final int y1 = startY + sampleHeight - 1; final int y2 = startY; final int x1 = x; final int x2 = x + w - 1; g.setColor(SAMPLE_BORDER_COLOR); g.drawLine(x1, y1, x2, y1); g.drawLine(x1, y2, x2, y2); } if (doSetSelected) { setSelectionBounds(x, startY, w, sampleHeight); } } // private String getDescription(final MouseEvent evt) { //YXXX unused // final RowGeometry cachedRow; // cachedRow = screenY2RowGeometry(evt.getY()); // if ( cachedRow == null ){ // return null; // } // return cachedRow.rowData.rowDefinition.getLongDescription(); // } public int getVZoomLevel() { return vzoom_level; } public int getStackFramePixels() { return stack_frame_pixels; } public Settings.TLStack_align getStackAlign() { return stack_align; } public long getAbsoluteTimeStart() { if (recentDataSnapshot == null) { return 0; } return recentDataSnapshot.getAbsoluteTimeStart(); } public long getAbsoluteTimeEnd() { if (recentDataSnapshot == null) { return 0; } return recentDataSnapshot.getAbsoluteTimeEnd(); } public boolean selectionActive() { if (selection_event == null) { return false; } return true; } public long getSelectionTimeEnd() { if (selection_event == null) { return 0; } return selection_event.eventTimeEnd; } public long getSelectionTimeStart() { if (selection_event == null) { return 0; } return selection_event.eventTimeStart; } public double getSelectionYCenter() { if (selection_event == null) { return 0; } int ycoord = dataAxisCalculator.getCenterCoordForRow(selection_event.rowNum); double selection_ypct_center = dataAxisCalculator.getPercentNearCoord(ycoord); return selection_ypct_center; } public class FindNearXYResult { public final RowGeometry rowGeometry; public final long clickTime; public final GenericEvent event; public final Object chartData; // YXXX would prefer to use GenericEvent as type public final boolean directTimeHit; public final int x, y; public FindNearXYResult( int x, int y, RowGeometry rowGeometry, long clickTime, GenericEvent event, Object chartData, boolean directTimeHit) { this.x = x; this.y = y; this.rowGeometry = rowGeometry; this.clickTime = clickTime; this.event = event; this.chartData = chartData; this.directTimeHit = directTimeHit; } } public FindNearXYResult findNearXY( final int xx, final int yy, final boolean searchOnlyMasterRows) { // xx: either Integer.MIN_VALUE to use previous selection click time, or x coordinate final TimelineSelectionEvent recentSel = getRecentSelection(); final int y; final int rowNum; if (yy == Integer.MIN_VALUE) { if (recentSel != null) { rowNum = recentSel.rowNum; } else { rowNum = dataAxisCalculator.getRowStart(); } y = dataAxisCalculator.getCenterCoordForRow(rowNum); } else { y = yy; rowNum = dataAxisCalculator.getRowAtCoord(y); } RowGeometry rowGeometry = rowNum2RowGeometry(rowNum); if (rowGeometry == null) { return null; } final RowGeometry row; if (searchOnlyMasterRows) { // redirect any clicks on charts to master row row = rowGeometry.getMasterRow(); } else { row = rowGeometry; } final long clickTime; final int x; boolean inMargin = false; if (xx == Integer.MIN_VALUE) { if (recentSel != null) { clickTime = recentSel.clickTime; } else { clickTime = timeAxisCalculator.getTimeStart(); } x = timeAxisCalculator.getCoordAtTime(clickTime); } else { x = xx; int margin = timeAxisCalculator.getMargin(); int availWidth = timeAxisCalculator.getAvailPixels(); if (x < margin || x > availWidth + margin) { inMargin = true; } clickTime = timeAxisCalculator.getTimeNearCoord(x); } final RowData dataCopy = row.rowData.grabEventData(); // row.rowData is volatile, get snapshot Object chartData = null; if (row.isChartData()) { final Object vals = dataCopy.getChartData(row.chartPropIdx); do { // chart events are based on pixel-sized bins (not event time info) final int binStartOffset = getBinStartOffset(dataCopy); if (binStartOffset == INVALID_BIN) { break; // weird } final int clickBin = timeAxisCalculator.getBinAtTime(clickTime); if (vals instanceof SampleEvent[]) { // SampleEvent[]-style data is sparse; only bins with data are stored final SampleEvent[] events = (SampleEvent[]) vals; if (events.length == 0) { break; } final int virtualDataBin = clickBin + binStartOffset; final int srchIdx = searchEventsByBin(events, virtualDataBin); final SampleEvent event = events[srchIdx]; final int binEnd = event.binStart + event.binCount - 1; if (event.binStart > virtualDataBin || binEnd < virtualDataBin) { break; // not in data set } chartData = event; } else if (vals instanceof long[]) { // long[]-style data has a value for every bin final int[] binMinMax = getRowVisibleBinMinMax(dataCopy); final int lowBinLimit = binMinMax[0]; final int highBinLimit = binMinMax[1]; if (clickBin < lowBinLimit || clickBin > highBinLimit) { break; // click is outside of chart's valid data } final int dataBin = clickBin + binStartOffset; final long[] events = (long[]) vals; if (dataBin < 0 || dataBin >= events.length) { break; // weird } chartData = events[dataBin]; } else { int ii = 0; // weird, for breakpoint break; } } while (false); } GenericEvent[] events = dataCopy.getEvents(); if (!dataCopy.eventDataIsValid() || events == null || events.length == 0) { return new FindNearXYResult(x, y, row, clickTime, null, chartData, false); } // The events are ordered by timeEnd, but they might overlap // See Dbe.cc dbeGetTLEventIdxNearTime() for algorithm. // We'll do a binary search of visible (painted) events. // If searchEventsByTime() can't find an exact match, the result // will be after clickTime except if it is the last item. final int srchIdx = searchEventsByTime(events, clickTime); final long srchEndTime = events[srchIdx].timeEnd; int winner = -1; final long winnerDelta; do { if (clickTime == srchEndTime) { // exact winner = srchIdx; winnerDelta = 0; break; } final long srchTimeStart = events[srchIdx].timeStart; final long srchTimeDelta = distanceToEvent(clickTime, srchTimeStart, srchEndTime); if (srchEndTime < clickTime // hit rightmost max || srchIdx == 0) { // hit leftmost max winner = srchIdx; winnerDelta = srchTimeDelta; break; } // need to choose final int prevIdx = srchIdx - 1; final long prevTimeDelta = distanceToEvent(clickTime, events[prevIdx].timeStart, events[prevIdx].timeEnd); if (srchTimeDelta < prevTimeDelta) { winner = srchIdx; winnerDelta = srchTimeDelta; break; } else { winner = prevIdx; winnerDelta = prevTimeDelta; break; } } while (false); final GenericEvent event = events[winner]; final long timeTolerance = timeAxisCalculator.getTimePerBin() * CLICK_PIXEL_TOLERANCE; final boolean directTimeHit = !inMargin && (winnerDelta < timeTolerance); return new FindNearXYResult(x, y, row, clickTime, event, chartData, directTimeHit); } // binary search. If no exact match, the result's timeEnd // will be greater than clickTime unless the result is the last item. private int searchEventsByTime(GenericEvent[] events, long clickTime) { int lo = 0; int hi = events.length - 1; while (lo < hi) { int md = (hi + lo) / 2; if (clickTime > events[md].timeEnd) { lo = md + 1; } else { hi = md; } } return lo; } // binary search. If no exact match, the result's timeEnd // will be greater than clickTime unless the result is the last item. private int searchEventsByBin(GenericEvent[] events, int clickBin) { int lo = 0; int hi = events.length - 1; while (lo < hi) { int md = (hi + lo) / 2; int binEnd = events[md].binStart + events[md].binCount - 1; if (clickBin > binEnd) { lo = md + 1; } else { hi = md; } } return lo; } private long distanceToEvent(long refTime, long eventStart, long eventEnd) { if (refTime < eventStart) { return eventStart - refTime; } if (eventEnd < refTime) { return refTime - eventEnd; } return 0; } // ===== text dump of timeline data for debugging and automated GUI testing ===== public String dumpXY(final FindNearXYResult result) { if (result == null) { return "null"; } StringBuilder buf = new StringBuilder(); final RowGeometry row = result.rowGeometry; final RowDefinition rowDef = row.rowData.rowDefinition; buf.append("Timeline Data Near (x=" + result.x + ", y=" + result.y + "):"); buf.append(" rowNum=" + row.rowNum); buf.append(" clickTime=" + result.clickTime / NS_PER_SEC); buf.append(" directTimeHit=" + result.directTimeHit); buf.append("\n"); buf.append(" rowLabel=" + dumpRowInfo(row)); buf.append( " procTimeRange=[" + (rowDef.getDataTimeStart() - rowDef.getTimeOrigin()) / NS_PER_SEC); buf.append(", " + (rowDef.getDataTimeEnd() - rowDef.getTimeOrigin()) / NS_PER_SEC + "]"); buf.append("\n"); buf.append(" rowToolTip='" + rowDef.getLongDescription() + "'"); buf.append(dumpGenericEvent(result.event, row)); if (row.isChartData()) { buf.append("\n Chart='" + row.propUName + "'"); if (result.chartData != null) { if (result.chartData instanceof StackEvent) { buf.append("Unexected Chart Data"); } else if (result.chartData instanceof SampleEvent) { final SampleEvent event = (SampleEvent) result.chartData; buf.append(dumpSampleEvent(event, row.propName)); } else if (result.chartData instanceof Long) { final Long val = (Long) result.chartData; buf.append(" Value=" + val); } else { buf.append("UNKNOWN Chart Data!"); } } } buf.append("\n"); return buf.toString(); } private String dumpGenericEvent(GenericEvent evt, RowGeometry row) { if (evt != null) { StringBuilder buf = new StringBuilder(); buf.append("\n Event: "); buf.append(evt.toString()); if (evt instanceof SampleEvent) { buf.append("\n Sample:"); final SampleEvent event = (SampleEvent) evt; final String propName = row.getMasterRow().propName; buf.append(dumpSampleEvent(event, propName)); } return buf.toString(); } return ""; } private String dumpSampleEvent(final SampleEvent sampleEvent, final String propName) { if (sampleEvent == null) { return ""; } StringBuilder buf = new StringBuilder(); final TimelineVariable.StatesDisplayInfo stateInfo; stateInfo = TimelineVariable.getStateInfo(propName); if (stateInfo.statePropName.isEmpty()) { int ii = 0; // weird return ""; } final long stateVals[] = stateInfo.raw2displayValues(sampleEvent.propValues); long total = 0; for (int ii = 0; ii < stateVals.length; ii++) { total += stateVals[ii]; } final long binDuration = sampleEvent.timeEnd - sampleEvent.timeStart + 1; if (binDuration > 0) { final double nthreads = 1.0 * total / binDuration; buf.append(String.format(" nthreads=%.1f", nthreads)); } else { buf.append("<unknown sample duration>"); } buf.append(" (totalSampleTime=" + total / NS_PER_SEC + ")"); for (int ii = 0; ii < stateVals.length; ii++) { if (stateVals[ii] == 0) { continue; } final String state = stateInfo.getNameByDisplayIdx(ii); final double percent = 100.0 * stateVals[ii] / total; buf.append(String.format("\n %.2f%%", percent)); buf.append(" state='" + state + "'"); buf.append(" color=" + stateInfo.getColorByDisplayIdx(ii)); } return buf.toString(); } /** * @param limit limit in number of lines. 0 means all lines. * @return formatted text */ public String exportAsText(Integer limit) { TL2DataSnapshot dataSnapshot = recentDataSnapshot; if (dataSnapshot == null || dataSnapshot.getRowData().isEmpty()) { final String message; if (dataSnapshot == null) { message = AnLocale.getString("Experiment load in progress..."); } else { message = AnLocale.getString("Data not available for this filter selection"); } return message; } StringBuilder buf = new StringBuilder(); GenericEvent gevent = getVisibleSelection(); buf.append("\n============ TIMELINE DUMP ============"); buf.append("\n=== Selection ==="); if (gevent != null) { RowGeometry selRow = rowGeometry.get(selection_event.rowNum); buf.append("\n Timeline " + dumpRowInfo(selRow)); buf.append(dumpGenericEvent(gevent, selRow)); } else { buf.append("\n <no event selected>"); } if (caliper != null) { buf.append( "\n Time selection range: [" + caliper.getLowTime() + ", " + caliper.getHighTime() + "]"); } if (rowGeometry == null) { buf.append("\nWARNING: timeline panel has not been drawn yet"); return buf.toString(); } int nRows = rowGeometry.size(); if (currRowFirst > nRows || currRowLast > nRows) { buf.append("\nWARNING: timeline data row count is inconsistent"); return buf.toString(); } for (int ii = currRowFirst; ii < currRowLast; ii++) { final RowGeometry row = rowGeometry.get(ii); final RowData dataCopy = row.rowData.grabEventData(); // row.rowData is volatile, get snapshot final int binStartOffset = getBinStartOffset(dataCopy); buf.append("\n=== Timeline " + dumpRowInfo(row) + " ==="); if (binStartOffset == INVALID_BIN) { buf.append("\n Fetching Data..."); continue; } if (!row.isChartData()) { // specifies the events themselves GenericEvent[] events = dataCopy.getEvents(); buf.append(dumpRowEvents(row, events, binStartOffset)); continue; } // specifies a chart final Object vals = dataCopy.getChartData(row.chartPropIdx); if (vals instanceof long[]) { long longVals[] = (long[]) vals; buf.append(dumpRowChartValues(dataCopy, longVals, binStartOffset)); } else if (vals instanceof SampleEvent[]) { SampleEvent sampleEvents[] = (SampleEvent[]) vals; buf.append(dumpRowEvents(row, sampleEvents, binStartOffset)); } else { buf.append("\nERROR: unexpected data type"); continue; // weird, vals is unexpected type } } return buf.toString(); } private String dumpRowInfo(RowGeometry row) { final RowDefinition rowDef = row.rowData.rowDefinition; StringBuilder buf = new StringBuilder(); buf.append( "'" + rowDef.getShortLabel() + "'" // + " " + rowDef.getExpName() + " " + rowDef.getDataDescUName() + " "); if (row.subrowNum == 0) { buf.append("Events"); } else { buf.append(row.propUName); } return buf.toString(); } private String dumpRowEvents( final RowGeometry row, final GenericEvent[] events, final int binStartOffset) { StringBuilder buf = new StringBuilder(); ; if (events == null) { buf.append("\n <no data>"); return buf.toString(); } if (events.length == 0) { buf.append("\n <no events>"); return buf.toString(); } final TimelineVariable.StatesDisplayInfo stateInfo; if (events[0] instanceof SampleEvent) { // see TLExperiment.getChartProps() stateInfo = TimelineVariable.getStateInfo(row.propName); } else { stateInfo = null; } boolean forceToSingleBin = false; RowDefinition rowDef = row.rowData.rowDefinition; if (!row.isChartData() && rowDef.getTLDataType().equals(Settings.TLData_type.TL_CLOCK)) { // Hack to show clock profiling callstacks as a point in time // ... but show microstate bar for the full duration forceToSingleBin = true; } for (int ii = 0; ii < events.length; ii++) { final GenericEvent event = events[ii]; final int eventbinStart = event.binStart - binStartOffset; final int nbins = timeAxisCalculator.getNumBins(); final int binStart, binCount; if (forceToSingleBin && event.binCount > 1) { binStart = eventbinStart + event.binCount - 1; binCount = 1; } else { binStart = eventbinStart; binCount = event.binCount; } if (binStart > nbins + FATTENED_EVENT_WIDTH) { break; } if (binStart + binCount < 0) { continue; } { int binEnd = binStart + binCount - 1; int xStart = timeAxisCalculator.getLowCoordForBin(binStart); int xEnd = timeAxisCalculator.getLowCoordForBin(binEnd + 1) - 1; buf.append(dumpGenericEvent(event, row)); break; // only print the first visible event for now } } return buf.toString(); } private String dumpRowChartValues( final RowData dataCopy, final long longVals[], int binStartOffset) { StringBuilder buf = new StringBuilder(); ; final int[] binMinMax = getRowVisibleBinMinMax(dataCopy); final int lowBinLimit = binMinMax[0]; final int highBinLimit = binMinMax[1] + 1; // +1 is fudge for missing pixel at some zooms int startBin = binStartOffset >= 0 ? binStartOffset : 0; int maxPrintValues = 10; buf.append("\n Leftmost non-zero chart values: "); for (int bin = startBin; bin < longVals.length; bin++) { final int visibleBin = bin - binStartOffset; if (visibleBin > highBinLimit) { break; } if (visibleBin < lowBinLimit) { continue; } long val = longVals[bin]; if (val != 0) { if (maxPrintValues == 0) { break; } maxPrintValues--; buf.append(" " + val + "@" + bin); } } return buf.toString(); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/IconRuler.java�������������������������������������������0000644�0001750�0001750�00000034437�14517772113�020405� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.timeline_common.VerticalRowRuler; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.ruler.Ruler; import org.gprofng.mpmt.util.ruler.valuetypes.ValuesGeneric; import java.awt.*; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.swing.ImageIcon; import javax.swing.JTable; public final class IconRuler extends VerticalRowRuler implements Ruler, Accessible { private final int ICON_WIDTH = 16; private final int ICON_HEIGHT = 16; private final int ICON_HPAD = 3; private final int CURSOR_HPAD = 7; private List<RowGeometry> rowGeometry; private int rowFirst; // first visible row private int rowLast; // first non-Visible row private int eventSelectionRow; // selected event's row private TreeSet<Integer> selectedRows; // highlighted rows private int scrollY; // font state private static Font TEXT_FONT; private int FONT_HEIGHT = 0; private int FONT_ASCENT = 0; private int FONT_DESCENT = 0; private int rulerWidth = 0; // drawer settings private ValuesGeneric valueType; private int paddingLow; private int paddingHigh; private final Color backColor = Color.WHITE; private final Color selectionBackColor = TimelineDraw.GENERIC_SELECTION_COLOR; private final Color selectionTextColor = Color.BLACK; private boolean comparisonEnabled; // preferred size private boolean lockPreferredSize = false; private Dimension preferredD = new Dimension(1, 1); // non-zero for layout mgr private int actualWidth; static { JTable jtable = new JTable(); Font org_font = jtable.getFont(); TEXT_FONT = new Font("SansSerif", org_font.getStyle(), org_font.getSize()); } public IconRuler(ValuesGeneric type) { // YXXX icon ruler shouldn't take value type? super(); this.valueType = type; // YXXX this should be a local copy this.paddingLow = 0; this.paddingHigh = 0; setToolTipText(""); reset(); AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Vertical Ruler")); } private void reset() { rowGeometry = new ArrayList(); rowFirst = -1; rowLast = -1; eventSelectionRow = -1; selectedRows = new TreeSet(); comparisonEnabled = false; } private boolean isFontInitialized() { if (FONT_HEIGHT != 0) { return true; } if (TEXT_FONT != null) { FontMetrics fm = this.getFontMetrics(TEXT_FONT); if (fm != null) { FONT_ASCENT = fm.getAscent() - 1; // YXXX bogus adjust for looks FONT_DESCENT = fm.getDescent() - 2; // YXXX bogus adjust for looks FONT_HEIGHT = FONT_ASCENT + FONT_DESCENT; return true; } } return false; } public void setRowGeometry( List<RowGeometry> geometry, int scrollY, int firstVisibleRow, int lastVisibleRow, int selectedRow, TreeSet<Integer> multiselect_rows) { this.rowGeometry = geometry; this.scrollY = scrollY; this.rowFirst = firstVisibleRow; this.rowLast = lastVisibleRow; this.eventSelectionRow = selectedRow; this.selectedRows = multiselect_rows; this.comparisonEnabled = false; if (geometry.size() > 1) { int grp0 = geometry.get(0).rowData.rowDefinition.getExpGroupId(); int grpLast = geometry.get(geometry.size() - 1).rowData.rowDefinition.getExpGroupId(); if (grpLast != grp0) { comparisonEnabled = true; } } repaint(); } /** * Set a spacing to align component padLo is at the "0" end of the graphics' coordinate system * padHi is at the opposite end */ public void setPadding(int padLo, int padHi) { if (paddingLow != padLo || paddingHigh != padHi) { paddingLow = padLo; paddingHigh = padHi; repaint(); // should we do this elsewhere, as well? } } /** set direction of ruler w.r.t. coordinate system */ public void setOrderReverse(boolean reverse) {} // if the LabelCoordinateCalculator stays the same, you can call this // WARNING: Modifies values in the global variable that was passed in! @Override public final void setRange(long lo, long hi) { // YXXX only used to determine repaints if (valueType.getLowValue() != lo || valueType.getHighValue() != hi) { valueType.setRange(lo, hi); repaint(); } } @Override public void lockRulerThickness(Graphics g, boolean lock) { /* * YXXX not sure if it ok to use g from another context, but * font size is needed to set preferred ruler size, and * I don't know how else to get font size without g. * Maybe we should never attempt to lock ruler thickness? * Unfortunately, changing thickness might unexpectedly change * data range that can be shown on center panel. * For now, workaround is to provide g. */ if (!lockPreferredSize && lock) { recomputePreferredSize(g); } lockPreferredSize = lock; } private int calcWidth(final Graphics g, String stmp) { if (!isFontInitialized()) { return 0; // YXXX or could return a guess } int strPixels = g.getFontMetrics(TEXT_FONT).stringWidth(stmp); return strPixels; } /** Recompute preferred size */ private boolean recomputePreferredSize(Graphics g) { if (!isFontInitialized()) { return false; } int textWidth = calcWidth(g, "99 (Base)"); // YXXX should use real labels? rulerWidth = textWidth + ICON_WIDTH + ICON_HPAD + CURSOR_HPAD; boolean changed = internalSetPreferredSize(rulerWidth, 0); return changed; } // override parent @Override public Dimension getPreferredSize() { return preferredD; } private boolean internalSetPreferredSize(int width, int height) { boolean changed = false; if (preferredD.width != width || preferredD.height != height) { preferredD.width = width; preferredD.height = height; changed = true; } return changed; } @Override protected void paintComponent(Graphics g) { if (!isFontInitialized()) { // should never happen since <g> should allow font to be set return; } if (!lockPreferredSize) { boolean changed = recomputePreferredSize(g); if (changed) { revalidate(); // YXXX not supposed to revalidate from paint } } myPaintComponent(g); } private int screenY(int virtualY) { return virtualY - scrollY; } // Paints the ruler private void myPaintComponent(final Graphics gr) { Graphics2D g = (Graphics2D) gr; Rectangle drawHere = g.getClipBounds(); actualWidth = drawHere.width; // erase entire ruler g.setColor(backColor); g.fillRect(drawHere.x, drawHere.y, drawHere.width, drawHere.height); if (rowGeometry.isEmpty()) { drawBorders(g, drawHere.height); return; } // Do the ruler labels in a small font that's black. g.setFont(TEXT_FONT); int lastVisibleRow = rowLast; // draw horizontal lines, selected rows' background for (int ii = rowFirst; ii < lastVisibleRow; ii++) { RowGeometry row = rowGeometry.get(ii); int groupId = row.rowData.rowDefinition.getExpGroupId(); if (selectedRows.contains(ii)) { g.setColor(selectionBackColor); } else if (comparisonEnabled) { g.setColor(AnMetric.getMetricBackground(groupId)); } else { g.setColor(backColor); } { int startY = screenY(row.startY); int height = screenY(row.endY) - startY + 1 + 1; // overshoot by 1 int width = drawHere.width; g.fillRect(drawHere.x, startY, width, height); } if (row.rowDividerHeight > 0) { // divider below this row int y = screenY(row.endY + 1); if (row.isCompareGroupEnd) { TimelineDraw.drawDashedDivider( g, TimelineDraw.COMPARE_GRP_DIVIDER_COLOR, 0, actualWidth, y, row.rowDividerHeight); } else if (row.isExperimentEnd) { TimelineDraw.drawSolidDivider( g, TimelineDraw.EXPERIMENT_DIVIDER_COLOR, 0, actualWidth, y, row.rowDividerHeight); } else if (row.isEntityEnd) { TimelineDraw.drawSolidDivider( g, TimelineDraw.STANDARD_DIVIDER_COLOR, 0, actualWidth, y, row.rowDividerHeight); } else { TimelineDraw.drawDashedDivider( g, TimelineDraw.STANDARD_DIVIDER_COLOR, 0, actualWidth, y, row.rowDividerHeight); } } if (screenY(row.startY) > drawHere.height) { lastVisibleRow = ii; break; } } // draw icons for (int ii = rowFirst; ii < lastVisibleRow; ) { RowGeometry masterRow = rowGeometry.get(ii).getMasterRow(); final int firstSubrow = masterRow.rowNum - masterRow.subrowNum; final int lastSubrow = firstSubrow + masterRow.nSubrows - 1; ii = lastSubrow + 1; ImageIcon icon = masterRow.rowData.rowDefinition.getTLDataType().getIcon(); if (icon == null) { continue; } int block_startY = rowGeometry.get(firstSubrow).startY; int block_endY = rowGeometry.get(lastSubrow).endY; int row_height = block_endY - block_startY + 1; if (ICON_HEIGHT > row_height) { continue; } { int centerY = screenY((block_endY + block_startY + 1) / 2); int startY = centerY - ICON_HEIGHT / 2; icon.paintIcon(this, g, actualWidth - ICON_WIDTH - ICON_HPAD - CURSOR_HPAD, startY); } } // draw text for (int ii = rowFirst; ii < lastVisibleRow; ii++) { RowGeometry row = rowGeometry.get(ii); if (ii == eventSelectionRow) { RowGeometry masterRow = rowGeometry.get(ii).getMasterRow(); final int firstSubrow = masterRow.rowNum - masterRow.subrowNum; final int lastSubrow = firstSubrow + masterRow.nSubrows - 1; int block_startY = rowGeometry.get(firstSubrow).startY; int block_endY = rowGeometry.get(lastSubrow).endY; if (block_endY - block_startY > 5) { block_endY--; block_startY++; } if (block_endY - block_startY > 7) { block_endY--; block_startY++; } drawHighlight(g, block_startY, block_endY); } if (!row.isEntityStart) { continue; } String str = row.rowData.rowDefinition.getShortLabel(); if (str == null) { continue; } // scan ahead for entity end to get height int entity_startY = row.startY; int entity_endY = row.endY; for (int jj = ii; jj < lastVisibleRow; jj++) { RowGeometry tmp_row = rowGeometry.get(jj); if (tmp_row.isEntityEnd) { entity_endY = tmp_row.endY; break; } } int row_height = entity_endY - entity_startY + 1; int fudge_factor = 2; if (FONT_HEIGHT - fudge_factor > row_height) { continue; } int textStartY = screenY(entity_startY); if (FONT_HEIGHT > row_height) { textStartY -= (FONT_HEIGHT - row_height + 3) / 2; } boolean is_selected = selectedRows.contains(ii); int groupId = row.rowData.rowDefinition.getExpGroupId(); // clear text background { Rectangle r = TEXT_FONT.getStringBounds(str, g.getFontRenderContext()).getBounds(); if (is_selected) { g.setColor(selectionBackColor); } else if (comparisonEnabled) { g.setColor(AnMetric.getMetricBackground(groupId)); } else { g.setColor(backColor); } g.fillRect(0, textStartY + 1, r.width, FONT_HEIGHT - 1); } if (is_selected) { g.setColor(selectionTextColor); } else { g.setColor(Color.black); } g.drawString(str, 0, textStartY + FONT_ASCENT); } drawBorders(g, drawHere.height); } private void drawHighlight(Graphics g, int dataStartY, int dataEndY) { Color c[] = {Color.YELLOW, Color.YELLOW, Color.RED}; final int borderSz = c.length; int startY = dataStartY + borderSz; int endY = dataEndY - borderSz; int y = screenY(startY); int h = endY - startY + 1; int x = actualWidth - CURSOR_HPAD + 3; int w = -1; for (int i = 0; i < c.length; i++) { g.setColor(c[i]); g.drawRect(x - i - 1, y - i - 1, w + 2 * i + 1, h + 2 * i + 1); } } private void drawBorders(Graphics g, int height) { g.setColor(Color.black); g.drawLine(0, 0, actualWidth, 0); g.drawLine(0, height - 1, actualWidth, height - 1); } private RowGeometry findRow(int screenY) { int virtualY = screenY + scrollY; for (int ii = rowFirst; ii < rowLast; ii++) { RowGeometry row = rowGeometry.get(ii); if (virtualY <= row.endY && virtualY >= row.startY) { return row; } } return null; } // The tooltip to be displayed for any icon inside the ruler, TimelineDraw // goes through the list of data to find what is being displayed at that "y" // location for the evt and sets the tooltip accordingly @Override public String getToolTipText(MouseEvent evt) { int screenY = evt.getY(); RowGeometry row = findRow(screenY); if (row != null) { String rc = row.rowData.rowDefinition.getLongDescription(); return rc; } return null; } @Override public AccessibleContext getAccessibleContext() { // variable accessibleContext is protected in superclass if (accessibleContext == null) { accessibleContext = new AccessibleIconRuler(); } return accessibleContext; } final class AccessibleIconRuler extends AccessibleJComponent { @Override public AccessibleRole getAccessibleRole() { return AccessibleRole.CANVAS; } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/RowGeometry.java�����������������������������������������0000644�0001750�0001750�00000005645�14517772113�020765� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import java.util.List; public class RowGeometry { public final int rowNum; // index into parent List public final List<RowGeometry> parent; // parent list public final int nSubrows; // total number of rows within data type public final int subrowNum; // row number within data type public final RowData rowData; public final int chartPropIdx; // -1 for event data, >=0 for data chart public final String propName; // internal name of PROP_* property public final String propUName; // user-visible name of PROP_* property public final int startY; public final int endY; public final int dataStartY; public final int dataEndY; public final boolean isEntityStart; public final boolean isEntityEnd; public final boolean isExperimentEnd; public final boolean isCompareGroupEnd; public final int rowDividerHeight; // height of divider below this row private RowGeometry masterRow; // points to row used for selection public RowGeometry( int rowNum, List<RowGeometry> parent, int nSubrows, int subrowNum, RowData rowData, int chartPropIdx, // -1 for event data, >=0 for data chart String propName, String propUName, int startY, int endY, int dataStartY, int dataEndY, boolean isEntityStart, boolean isEntityEnd, boolean isExperimentEnd, boolean isCompareGroupEnd, int rowDividerHeight) { this.rowNum = rowNum; this.parent = parent; this.nSubrows = nSubrows; this.subrowNum = subrowNum; this.rowData = rowData; // note: rowData will be updated asynchronously this.masterRow = this; this.chartPropIdx = chartPropIdx; this.propName = propName; this.propUName = propUName; this.startY = startY; this.endY = endY; this.dataStartY = dataStartY; this.dataEndY = dataEndY; this.isEntityStart = isEntityStart; this.isEntityEnd = isEntityEnd; this.isExperimentEnd = isExperimentEnd; this.isCompareGroupEnd = isCompareGroupEnd; this.rowDividerHeight = rowDividerHeight; } public void setMasterRow(RowGeometry row) { masterRow = row; } public RowGeometry getMasterRow() { return masterRow; } public boolean isChartData() { return (chartPropIdx != -1); } } �������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TLExperiment.java����������������������������������������0000644�0001750�0001750�00000022146�14517772113�021055� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.experiment_props.*; import org.gprofng.mpmt.settings.Settings; import java.util.ArrayList; import java.util.List; public class TLExperiment { // YXXX refactor or rename. Sole remaining method is createRows() private final PropDescriptor PROP_EVT_COUNT = // used to get packet count new PropDescriptor( "EVT_COUNT", "Event Count", // Should be I18N'D YXXX Settings.PROP_NONE, null, null); private boolean descriptorIsEnabled( final String nameWithAux, final long tldata_hidden_mask, final List<String> tldata_cnames) { if (tldata_hidden_mask == 0 || tldata_cnames == null || tldata_cnames.isEmpty()) { return true; } for (int ii = 0; ii < tldata_cnames.size(); ii++) { long bit = tldata_hidden_mask & 1L << ii; if (bit != 0) { String hiddenName = tldata_cnames.get(ii); if (nameWithAux.equals(hiddenName)) { return false; } } } return true; } // routine to discover the Experiment's rows // returns: RowDefinitions grouped by entity) public List<TL2DataSnapshot.EntityDefinitions> createEntityRowDefinitions( final ExperimentProperties experimentProperties, final List<Entity> ents, final int entity_prop_id, final long tldata_hidden_mask, final List<String> tldata_cnames, final boolean show_states, final boolean show_charts, final long time_origin, // timestamp at left origin (nanoseconds) final boolean comparing) { List<TL2DataSnapshot.EntityDefinitions> entityList = new ArrayList(); if (ents == null || ents.isEmpty()) { return entityList; } // add rows that aren't associated with an entity List<DataDescriptor> data_descs_with_ent = new ArrayList(); List<DataDescriptor> data_descs_without_ent = new ArrayList(); final Entity ent0 = ents.get(0); final int ent_prop_id = ent0.getPropId(); final String ent_prop_id_name = ent0.getPropIdName(); final boolean prop_is_expid = ent_prop_id_name.equalsIgnoreCase("EXPID"); List<DataDescriptor> descriptors = experimentProperties.getTstampDataDescriptors(); for (DataDescriptor dataD : descriptors) { if (dataD.findProp("TSTAMP") == null) { // YXXX redundant?? continue; // only draw entities that have time } if (dataD.getTLDataType().equals(Settings.TLData_type.TL_HEAPSZ) || dataD.getTLDataType().equals(Settings.TLData_type.TL_GCEVENT)) { // CXXX Bug 20801848 // YXXX see if we can avoid special case by adding property to DataDescriptor data_descs_without_ent.add(dataD); continue; } if (prop_is_expid) { data_descs_without_ent.add(dataD); continue; } if (dataD.findProp(ent_prop_id) != null) { data_descs_with_ent.add(dataD); } else { data_descs_without_ent.add(dataD); } } List<RowDefinition> entityRowDefs = newEntityRowDefs( experimentProperties, data_descs_without_ent, null, tldata_hidden_mask, tldata_cnames, show_states, show_charts, time_origin, comparing); entityList.add(new TL2DataSnapshot.EntityDefinitions(entityRowDefs)); // add rows for entities for (Entity ent : ents) { entityRowDefs = newEntityRowDefs( experimentProperties, data_descs_with_ent, ent, tldata_hidden_mask, tldata_cnames, show_states, show_charts, time_origin, comparing); entityList.add(new TL2DataSnapshot.EntityDefinitions(entityRowDefs)); } return entityList; } private boolean tryAdd( List<PropDescriptor> chartProps, final DataDescriptor dataD, final String propName) { PropDescriptor prop = dataD.findProp(propName); if (prop != null) { String[] stateNames = prop.getStateNames(); if (stateNames == null) { // value chart chartProps.add(prop); return true; } else { // state chart // ... do not chart items that have only one state int nStates = 0; int maxstates = prop.getStateNames().length; for (int ii = 0; ii < maxstates; ii++) { if (stateNames[ii] != null) { nStates++; } } if (nStates > 1) { chartProps.add(prop); return true; } } } return false; } // TBR? transfer this logic into event details classes? private List<PropDescriptor> getChartProps( final DataDescriptor dataD, final boolean show_states, final boolean show_charts) { List<PropDescriptor> chartProps = new ArrayList(); Settings.TLData_type tltype = dataD.getTLDataType(); if (tltype.equals(Settings.TLData_type.TL_SAMPLE)) { if (show_charts) { chartProps.add(PROP_EVT_COUNT); } } else if (tltype.equals(Settings.TLData_type.TL_CLOCK)) { if (show_states) { tryAdd(chartProps, dataD, "MSTATE"); // See MSTATE_COLORS_BY_OVERVIEW_IDX // tryAdd( chartProps, dataD, "OMPSTATE" );// See <TBD>TL_UNKNOWN_GENERIC_COLOR_TABLE // tryAdd( chartProps, dataD, "MPISTATE" );// See <TBD>TL_UNKNOWN_GENERIC_COLOR_TABLE } if (show_charts) { chartProps.add(PROP_EVT_COUNT); } } else if (tltype.equals(Settings.TLData_type.TL_SYNC)) { if (show_charts) { tryAdd(chartProps, dataD, "EVT_TIME"); } } else if (tltype.equals(Settings.TLData_type.TL_IOTRACE)) { if (show_states) { tryAdd(chartProps, dataD, "IOTYPE"); // See TL_IOTRACE_IOTYPE_COLOR_TABLE } if (show_charts) { tryAdd(chartProps, dataD, "EVT_TIME"); } } else if (tltype.equals(Settings.TLData_type.TL_HEAP)) { if (show_states) { tryAdd(chartProps, dataD, "HTYPE"); // See TL_HEAP_HTYPE_COLOR_TABLE } if (show_charts) { tryAdd(chartProps, dataD, "HSIZE"); } } else if (tltype.equals(Settings.TLData_type.TL_HEAPSZ)) { tryAdd(chartProps, dataD, "HCUR_ALLOCS"); tryAdd(chartProps, dataD, "HCUR_LEAKS"); // if(show_states){ // tryAdd( chartProps, dataD, "HTYPE" );// See TL_HEAP_HTYPE_COLOR_TABLE // } } else if (tltype.equals(Settings.TLData_type.TL_MPI)) { if (show_states) { // tryAdd( chartProps, dataD, "MPITYPE" );// See <TBD>TL_UNKNOWN_GENERIC_COLOR_TABLE } if (show_charts) { // tryAdd( chartProps, dataD, "MPISCOUNT" ); // tryAdd( chartProps, dataD, "MPIRCOUNT" ); // tryAdd( chartProps, dataD, "MPISBYTES" ); // tryAdd( chartProps, dataD, "MPIRBYTES" ); chartProps.add(PROP_EVT_COUNT); } } else if (tltype.equals(Settings.TLData_type.TL_RACES)) { if (show_states) { // tryAdd( chartProps, dataD, "RTYPE" );// See <TBD>TL_UNKNOWN_GENERIC_COLOR_TABLE } if (show_charts) { chartProps.add(PROP_EVT_COUNT); } } else if (tltype.equals(Settings.TLData_type.TL_GCEVENT)) { // CXXX Bug 20801848 if (show_charts) { chartProps.add(PROP_EVT_COUNT); } } else { if (show_charts) { chartProps.add(PROP_EVT_COUNT); } } return chartProps; } private List<RowDefinition> newEntityRowDefs( final ExperimentProperties experimentProperties, final List<DataDescriptor> dscrList, final Entity ent, final long tldata_hidden_mask, final List<String> tldata_cnames, final boolean show_states, final boolean show_charts, final long time_origin, final boolean comparing) { final List<RowDefinition> rawDataRows = new ArrayList(); for (DataDescriptor dataD : dscrList) { int auxmax = dataD.getAuxCount(); if (auxmax == 0) { // descriptor doesn't contain multiple types auxmax = 1; } for (int aux = 0; aux < auxmax; aux++) { String tldata_cmd = dataD.getErRcTLDataCmdName(aux); if (!descriptorIsEnabled(tldata_cmd, tldata_hidden_mask, tldata_cnames)) { continue; } List<PropDescriptor> chartProps = getChartProps(dataD, show_states, show_charts); RowDefinition row = new RowDefinition( experimentProperties, ent, dataD, aux, chartProps, time_origin, comparing); rawDataRows.add(row); } } return rawDataRows; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TL2CoordCalcData.java������������������������������������0000644�0001750�0001750�00000027137�14517772113�021447� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.timeline_common.CoordCalcDataMaster; import java.util.ArrayList; /** * Coordinate calculator for timeline rows * * <p>Coordinate systems used: * * <p>"vcoord": coordinate system to represent user rows on screen where Zero corresponds to upper * edge of first row. "canvas": coordinate system of canvas. Scrollbar and margins are added to * vcoord. * * <p>Note: A lot of the complexity in this class is related to vertical zoom, a feature which is * currently disabled. */ public class TL2CoordCalcData extends CoordCalcDataMaster { // --- total range of rows to be displayed private int abs_row_end = 0; // absolute end row (at full zoom out) private int abs_row_count = 0; // number of rows (at full zoom out) // --- canvas size private int canvasPixels = 0; // --- zoom range (value [0.0-1.0] corresponds to [0-vcoord_total_pixels]) private boolean use_rows_for_range = false; // rows or percent to set range? private double visible_start_pct = 0.0; // visible start (% of total) private double visible_end_pct = 1.0; // visible end (% of total) private int visible_start_row = 0; // visible start (row) private int visible_end_row = 0; // visible start (row) // --- state private boolean is_initialized = false; // edt_revalidate() has been called at least once private boolean needs_compute = false; private int vcoord_visible_top = 0; // vcoord offset to start of visible data // --- row layout (vcoord) private ArrayList<Integer> vcoord_row_tops; // row upper edge (unscaled) private ArrayList<Integer> vcoord_row_bottoms; // row lower edge (unscaled) private int vcoord_total_pixels = 1; // total size of all rows (unscaled) // preferences private final int canvasY_header = 0; // optional vertical offset private final int canvasY_margin; // space between TL and ruler public static final double HUNDRED_PERCENT_ROUNDUP = 0.999; public TL2CoordCalcData(int canvas_margin) { canvasY_margin = canvas_margin; } // --- canvas geometry /** Sets current canvas height */ @Override public void setCanvasPixels(int visiblePixels) { if (canvasPixels != visiblePixels) { canvasPixels = visiblePixels; needs_compute = true; } } /** Gets current canvas height */ public int getCanvasPixels() { return canvasPixels; } // --- row geometry settings @Override public void edt_revalidate() { // setAbsRowMinHeight*() must be called first if (needs_compute) { calculateRowSizes(); needs_compute = false; } is_initialized = true; } /** sets variables used to calculate row height */ private void calculateRowSizes() { // update vcoord_visible_top if (vcoord_row_tops == null) { vcoord_total_pixels = 1; vcoord_visible_top = 0; needs_compute = false; return; } double requested_pct = visible_end_pct - visible_start_pct; double avail_pct = (double) getAvailPixels() / vcoord_total_pixels; if (avail_pct > 1.0) { avail_pct = 1.0; } if (requested_pct < avail_pct) { // enough space to show more; expand range double center_pct = (visible_end_pct + visible_start_pct) / 2; visible_start_pct = center_pct - avail_pct / 2; visible_end_pct = center_pct + avail_pct / 2; } if (visible_start_pct < 0) { // shift range to start at 0 visible_end_pct += (0 - visible_start_pct); visible_start_pct = 0; } if (visible_end_pct > 1.0) { // shift range to end below %100 visible_start_pct -= (visible_end_pct - 1.0); visible_end_pct = 1.0; } if (visible_start_pct < 0) { visible_start_pct = 0; // weird, request was greater than %100 } visible_start_row = getRowNearPercent(visible_start_pct); visible_end_row = getRowNearPercent(visible_end_pct); vcoord_visible_top = (int) (vcoord_total_pixels * visible_start_pct); needs_compute = false; } /** margins allow states along edges to be visible and accessible */ public int getMargin() { return canvasY_margin; } public boolean isInitialized() { return is_initialized; } public boolean isValid() { return !needs_compute; } // --- row range private void setAbsRowCount(int rowCount) { int end = rowCount > 0 ? rowCount - 1 : 0; if (abs_row_count != rowCount || abs_row_end != end) { abs_row_count = rowCount; abs_row_end = end; needs_compute = true; } } public int getAbsRowEnd() { return abs_row_end; } public int getAbsRowCount() { return abs_row_count; } private void internalSetRowHeights(ArrayList<Integer> mins, int rowCount, int minPixels) { int absRowCount = (mins != null) ? mins.size() : rowCount; setAbsRowCount(absRowCount); int total_used = 0; if (absRowCount == 0) { vcoord_row_tops = vcoord_row_bottoms = null; needs_compute = true; } else { ArrayList<Integer> new_vcoord_row_tops = new ArrayList(absRowCount); ArrayList<Integer> new_vcoord_row_bottoms = new ArrayList(absRowCount); for (int ii = 0; ii < absRowCount; ii++) { new_vcoord_row_tops.add(total_used); final int rowHeight; if (mins != null) { rowHeight = mins.get(ii); } else { rowHeight = minPixels; } total_used += rowHeight; new_vcoord_row_bottoms.add(total_used); } for (int ii = 0; !needs_compute && ii < absRowCount; ii++) { if (new_vcoord_row_tops.get(ii) != vcoord_row_tops.get(ii) || new_vcoord_row_bottoms.get(ii) != vcoord_row_bottoms.get(ii)) { needs_compute = true; } } vcoord_row_tops = new_vcoord_row_tops; vcoord_row_bottoms = new_vcoord_row_bottoms; } // set unscaled row layout vcoord_total_pixels = total_used; if (vcoord_total_pixels < 1) { vcoord_total_pixels = 1; } edt_revalidate(); // visible_start_row = getRowNearPercent(visible_start_pct); // visible_end_row = getRowNearPercent(visible_end_pct); } public void setAbsRowMinHeights(int rowCount, int minPixels) { internalSetRowHeights(null, rowCount, minPixels); } public void setAbsRowMinHeights(ArrayList<Integer> mins) { internalSetRowHeights(mins, 0, 0); } public void setExpandToFill(boolean expands) {} public void setRowRange(int startrow, int endrow) { // snap to row not implemented at this time } public int getRowStart() { return visible_start_row; } public int getRowEnd() { return visible_end_row; } public int getRowCount() { return visible_end_row - visible_start_row + 1; } public void setVisibleRange(double start, double end) { if (use_rows_for_range != false || visible_start_pct != start || visible_end_pct != end) { use_rows_for_range = false; visible_start_pct = start; visible_end_pct = end; visible_start_row = getRowNearPercent(visible_start_pct); visible_end_row = getRowNearPercent(visible_end_pct); needs_compute = true; } } public double getVisibleStart() { return visible_start_pct; } public double getVisibleEnd() { return visible_end_pct; } public double getVisiblePercent() { return visible_end_pct - visible_start_pct; } // ---------- computed values ---------- private int vcoord2canvas(int vy) { int canvasY = vy - vcoord_visible_top + (canvasY_margin + canvasY_header); return canvasY; } private int canvas2vcoord(int canvasY) { int vy = canvasY + vcoord_visible_top - (canvasY_margin + canvasY_header); return vy; } public int getAvailPixels() { int availHeight = canvasPixels - canvasY_margin * 2; if (availHeight < 1) { availHeight = 1; } return availHeight; } public int getTotalPixels() { // YXXX unused return vcoord_total_pixels; } public int getMinPixelsForAllRows() { return vcoord_total_pixels; } public int getMinPixelsRequired(int row_lo, int row_hi) { // YXXX unused if (vcoord_row_tops == null) { return 0; } int top = vcoord_row_tops.get(row_lo); int bottom = vcoord_row_tops.get(row_hi); return bottom - top; } /** Get top coordinate for the ith row */ public int getLowCoordForRow(int yrow) { if (vcoord_row_tops == null) { return 0; } int vy = vcoord_row_tops.get(yrow); int y = vcoord2canvas(vy); return y; } /** Get center coordinate for the ith row */ public int getCenterCoordForRow(int yrow) { if (vcoord_row_tops == null) { return 0; } int vyt = vcoord_row_tops.get(yrow); int vyb = vcoord_row_bottoms.get(yrow); int vy = (vyt + vyb) / 2; int y = vcoord2canvas(vy); return y; } /** Get bottom coordinate for the ith row */ public int getHighCoordForRow(int yrow) { if (vcoord_row_tops == null) { return 0; } int vy = vcoord_row_bottoms.get(yrow); int y = vcoord2canvas(vy); return y; } // will return -1 if yy is between states public int getRowAtCoord(int canvasY) { // YXXX this might no longer be needed int idx = internalCoord2Row(canvasY); if (idx >= getAbsRowCount()) { return -1; } return idx; } // always returns a valid row num public int getRowNearCoord(int canvasY) { int idx = internalCoord2Row(canvasY); int nrows = getAbsRowCount(); if (idx < 0) { return 0; } else if (idx >= nrows) { return nrows - 1; } return idx; } // always returns a valid row num private int internalCoord2Row(int canvasY) { if (vcoord_row_tops == null) { return -1; } int vy = canvas2vcoord(canvasY); if (vy < 0) { return -1; } int nrows = getAbsRowCount(); for (int ii = 0; ii < nrows; ii++) { if (vy >= vcoord_row_tops.get(ii) && vy < vcoord_row_bottoms.get(ii)) { return ii; } } return nrows; } public double getPercentNearCoord(int canvasY) { if (vcoord_row_tops == null) { return 0; } int vy = canvas2vcoord(canvasY); double percent = (double) vy / vcoord_total_pixels; return percent; } public double getCenterPercentForRow(int yrow) { if (vcoord_row_tops == null) { return 0; } int uy = (vcoord_row_tops.get(yrow) + vcoord_row_bottoms.get(yrow)) / 2; double percent = (double) uy / vcoord_total_pixels; return percent; } public double getRowPercentOfTotal(int yrow) { if (vcoord_row_tops == null) { return 0; } int uy = vcoord_row_bottoms.get(yrow) - vcoord_row_tops.get(yrow); double percent = (double) uy / vcoord_total_pixels; return percent; } public int getRowNearPercent(double percent) { if (vcoord_row_tops == null) { return 0; } int uy = (int) (vcoord_total_pixels * percent); if (uy <= 0) { return 0; } int nrows = getAbsRowCount(); for (int ii = 0; ii < nrows - 1; ii++) { if (uy >= vcoord_row_tops.get(ii) && uy < vcoord_row_bottoms.get(ii)) { return ii; } } return nrows - 1; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/RowData.java���������������������������������������������0000644�0001750�0001750�00000005637�14517772113�020044� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.timeline2.data.*; // RowData contains per-row event data that must be synchronized between // a worker fetch thread and the AWT thread. // // In order to minimize MT risks, AWT-only data should not go into this class. public class RowData { // final public final RowDefinition rowDefinition; // immutable public final int idx; // location within RowData list (stable for life of snapshot) // dynamic data from gp-display-text private RowDataRequestParams params; private GenericEvent[] events; // primary row events private Object[] perPropChartData; // chart data private boolean dataValid = false; public RowData(RowDefinition rowDefinition, int idx) { this.rowDefinition = rowDefinition; this.idx = idx; } // --- the following should only be called from data fetcher public synchronized RowDataRequestParams getParams() { return params; } public synchronized void setEventData( RowDataRequestParams params, GenericEvent[] events, Object[] perPropData) { this.params = params; this.dataValid = true; this.events = events; this.perPropChartData = perPropData; } public synchronized RowData grabEventData() { RowData rowData = new RowData(rowDefinition, idx); rowData.params = this.params; rowData.dataValid = this.dataValid; rowData.events = this.events; rowData.perPropChartData = this.perPropChartData; return rowData; } public synchronized void invalidateEventData() { this.params = null; this.dataValid = false; this.events = null; this.perPropChartData = null; } public synchronized boolean eventDataIsValid() { // set to FALSE when data is invalid, set to TRUE after data is valid return dataValid; } // --- the following can be called by any thread (e.g. paint thread) public RowDefinition getRowDef() { // does not contain changing data; not synchronized return rowDefinition; } public synchronized GenericEvent[] getEvents() { return events; } public synchronized Object getChartData(int idx) { if (perPropChartData == null) { return null; } if (idx < 0 || idx >= perPropChartData.length) { return null; // weird } return perPropChartData[idx]; } } �������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TimelineView.java����������������������������������������0000644�0001750�0001750�00000111631�14517772113�021074� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnEvent; import org.gprofng.mpmt.AnListener; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.guitesting.GUITesting; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.settings.TimelineSetting; import org.gprofng.mpmt.timeline_common.TimelinePanel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSplitPane; import javax.swing.KeyStroke; /** * Derived from MPITimelineDisp.java * * <p>computed==true: -> use current TL2DataSnapshot, but always refetch rows updated==true: -> use * current TL2DataSnapshot and reuse row data if possible (repaint will handle fetching row data * from a TL2DataSnapshot) */ public final class TimelineView extends AnDisplay implements ExportSupport, AnChangeListener { // Created and owned by this class: private final MetaExperiment metaExperiment; // components private JPanel callStackPane; // right hand tab pane private JPanel detailsInfoTabComp; // details private TL2ControlPanel controlPanel; // control panel in rhTabPane private JPanel leftTabPanel; // left tab panel private TimelinePanel timelinePanel; // generic timeline framework private TL2Drawer drawer; // timeline data + drawer // private MPITLDrawer drawer; // timeline data + drawer // computing state private boolean fetchingNewExperiments = false; // Constructor public TimelineView() { super(AnWindow.getInstance(), AnDisplay.DSP_Timeline, AnVariable.HELP_TabsTimeline); // listen for color chooser changes window .getColorChooser() .getColorMap() .addAnListener( new AnListener() { @Override public void valueChanged(AnEvent e) { repaintTLDrawer(); } }); metaExperiment = new MetaExperiment(window, this); // YXXX potential race; leaks this in constructor instantiateTimelineDrawer(); // creates timelinePanel, drawer, etc. setAccessibility(AnLocale.getString("Timeline")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("TimelineView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_NEW: case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: computed = false; fetchingNewExperiments = true; if (e.getType() == AnChangeEvent.Type.EXPERIMENTS_LOADING_NEW) { edt_resetAll(); // YXXX includes resetting anWindow.getColorChooser() colors } else { edt_resetExperiments(); } break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: edt_clearRows(); // clear previous row data, stops background IPC computed = false; break; case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGING: case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); switch (anSettingChangeEvent.getType()) { case VIEW_MODE: case LIBRARY_VISIBILITY: case FORMAT: if (e.getType() == AnChangeEvent.Type.SETTING_CHANGING) { edt_clearRows(); // clear previous row data, stops background IPC } computed = false; if (selected) { computeOnAWorkerThread(); } break; case TIMELINE: // stack height, group-by, which properties to show if (e.getType() == AnChangeEvent.Type.SETTING_CHANGING) { break; // these can happen quickly; just handle CHANGED event } List newSettings = (List) anSettingChangeEvent.getNewValue(); boolean[] ret = edt_settingsChanged(newSettings); boolean newExperimentFetchNeeded = ret[0]; boolean drawNeeded = ret[1]; if (newExperimentFetchNeeded) { computed = false; if (selected) { computeOnAWorkerThread(); } } else if (drawNeeded) { repaintTLDrawer(); } break; default: break; } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void requestFocus() { if (timelinePanel != null) { timelinePanel.requestFocus(); } } @Override public JPopupMenu getFilterPopup() { return controlPanel.getFilterPopup(); } protected void initComponentsXXXmpview() {} // Is current selected tab? @Override public void setSelected(final boolean set) { // called from AWT thread final JSplitPane splitPane; // YXXX RE_FACTOR super.setSelected(set); // enableAction(set); // Show right pane if we get selected // if (set) { // window.showRightPane(); // } } // tab to populate right-side info area public JComponent getStackInfoTabComp() { return callStackPane; } public JComponent getDetailsInfoTabComp() { return detailsInfoTabComp; } // name for tab in right-side info area public String getStackInfoTabName() { return AnLocale.getString("Call Stack - Timeline"); // YXXX javadoc } // name for tab in right-side info area public String getDetailsInfoTabName() { return AnLocale.getString("Selection Details"); // YXXX javadoc } class FocusPanel extends JPanel { @Override public void requestFocus() { if (controlPanel != null) { controlPanel.getStackViewPane().requestFocus(); } } } // Minimal initialize of GUI components. Should not do IPC. // NOTE: called by super() init; other class variables not initted yet(!) @Override protected void initComponents() { this.setLayout(new BorderLayout()); // right hand tab callStackPane = new FocusPanel(); callStackPane.setLayout(new BorderLayout()); detailsInfoTabComp = new JPanel(); detailsInfoTabComp.setLayout(new BorderLayout()); // main tab leftTabPanel = new JPanel(); leftTabPanel.setLayout(new BorderLayout()); // YXXX ally also set in AnWindow.java... String accessibleName = AnLocale.getString("Timeline"); leftTabPanel.getAccessibleContext().setAccessibleName(accessibleName); leftTabPanel.getAccessibleContext().setAccessibleDescription(accessibleName); leftTabPanel.setToolTipText(accessibleName); this.add(leftTabPanel, BorderLayout.CENTER); this.revalidate(); String ks_string; KeyStroke ks_def; ks_def = KeyboardShortcuts.contextMenuActionShortcut; this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_def); this.getActionMap() .put( ks_def, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.showContextMenu(ev); } } }); ks_string = "FIRST"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_HOME, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectFirst(); } } }); ks_string = "ENTER"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel.getTimelinePanel()) { controlPanel.getTimelinePanel().zoomToCaliper(); } } }); ks_string = "CENTERTIMESEL"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.findTimeMarker(); } } }); ks_string = "CENTEREVENTSEL"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_F, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectFind(); } } }); // --- plain arrows ks_string = "LEFT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectLeft(); } } }); ks_string = "RIGHT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectRight(); } } }); ks_string = "UP"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectUp(); } } }); ks_string = "DOWN"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectDown(); } } }); // --- shift ctrl arrows ks_string = "SHIFTCTRLLEFT"; ks_def = KeyStroke.getKeyStroke( KeyEvent.VK_LEFT, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.pageLeft(); } } }); ks_string = "SHIFTCTRLRIGHT"; ks_def = KeyStroke.getKeyStroke( KeyEvent.VK_RIGHT, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.pageRight(); } } }); ks_string = "SHIFTCTRLUP"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.pageUp(); } } }); ks_string = "SHIFTCTRLDOWN"; ks_def = KeyStroke.getKeyStroke( KeyEvent.VK_DOWN, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.pageDown(); } } }); // --- shift arrows ks_string = "SHIFTLEFT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectLeft(false, true); } } }); ks_string = "SHIFTRIGHT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectRight(false, true); } } }); ks_string = "SHIFTUP"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectUp(false, true); } } }); ks_string = "SHIFTDOWN"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.selectDown(false, true); } } }); // --- ctrl arrows ks_string = "CTRLLEFT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.stepLeft(); } } }); ks_string = "CTRLRIGHT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.stepRight(); } } }); ks_string = "CTRLUP"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_UP, InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.stepUp(); } } }); ks_string = "CTRLDOWN"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.stepDown(); } } }); // --- zoom ks_string = "ZOOMIN"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.genericZoomIn(); } } }); ks_string = "ZOOMINE"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.genericZoomIn(); } } }); ks_string = "ZOOMOUT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.genericZoomOut(); } } }); if (true) { // Thomas' race condition needs to be sorted out first // --- height ks_string = "VZOOMIN"; ks_def = KeyStroke.getKeyStroke( KeyEvent.VK_EQUALS, InputEvent.SHIFT_MASK | InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { int sd = window.getSettings().getTimelineSetting().getTLStackDepth() + 1; window.getSettings().getTimelineSetting().setTLStackDepth(TimelineView.this, sd); } }); ks_string = "VZOOMINE"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_EQUALS, InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { int sd = window.getSettings().getTimelineSetting().getTLStackDepth() + 1; window.getSettings().getTimelineSetting().setTLStackDepth(TimelineView.this, sd); } }); ks_string = "VZOOMOUT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_MINUS, InputEvent.CTRL_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { int sd = window.getSettings().getTimelineSetting().getTLStackDepth() - 1; if (sd >= 0) { window .getSettings() .getTimelineSetting() .setTLStackDepth(TimelineView.this, sd); } } }); } ks_string = "ZOOMRESET"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_0, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.resetZoom(); } } }); ks_string = "ZOOMUNDO"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.undoZoom(); } } }); ks_string = "ZOOMREDO"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != controlPanel) { controlPanel.redoZoom(); } } }); ks_string = "CENTERTIMEMARKER"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SLASH, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.setTimeMarker(); } } }); ks_string = "MOVETIMEMARKERLEFT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.moveTimeMarkerLeft(); } } }); ks_string = "MOVETIMEMARKERRIGHT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_CLOSE_BRACKET, 0, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.moveTimeMarkerRight(); } } }); ks_string = "ADJUSTSELECTIONRANGELEFT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_OPEN_BRACKET, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.moveTimeRangeToLeft(); } } }); ks_string = "ADJUSTSELECTIONRANGERIGHT"; ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_CLOSE_BRACKET, InputEvent.SHIFT_MASK, false); this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, ks_string); this.getActionMap() .put( ks_string, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { if (null != timelinePanel) { timelinePanel.moveTimeRangeToRight(); } } }); // ks_string = "COLORCHOOSER"; // ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_C, 0, false); // this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, // ks_string); // this.getActionMap().put(ks_string, new AbstractAction() { // @Override // public void actionPerformed(ActionEvent ev) { // window.getColorChooser().setVisible(true); // } // }); // // ks_string = "TIMELINESETTINGS"; // ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_S, 0, false); // this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, // ks_string); // this.getActionMap().put(ks_string, new AbstractAction() { // @Override // public void actionPerformed(ActionEvent ev) { // window.getSettings().showDialog(window.getSettings().settingsTimelineIndex); // } // }); } /** * Initialize the TimelinePanel and TL2ControlPanel objects and add them to the eventPane. Called * only from edt_threadDoCompute() */ private void instantiateTimelineDrawer() { // called from AWT thread drawer = new TL2Drawer(metaExperiment.getDataFetcher()); drawer .getDataAxisMaster() .setAbsRowMinHeights(drawer.getAbsoluteRowCount(), 100); // just some value to init calc timelinePanel = new TimelinePanel( drawer, TimelinePanel.MouseDragMode.MOUSE_GRABBING_MODE, TimelinePanel.MouseDragMode.MOUSE_SELECTION_MODE, TimelinePanel.MouseDragMode.MOUSE_GRABBING_MODE); drawer.setParent(timelinePanel); // YXXX yuck controlPanel = new TL2ControlPanel(window, timelinePanel, drawer); detailsInfoTabComp.add(controlPanel.getDetailsTextPanel()); callStackPane.add(controlPanel.getDetailsPanel(), BorderLayout.CENTER); callStackPane.revalidate(); JPanel toolbarPanel = new JPanel(new GridBagLayout()); toolbarPanel.setMinimumSize(new Dimension(10, 10)); toolbarPanel.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.CENTER; gridBagConstraints.weightx = 1.0; toolbarPanel.add(controlPanel.getToolbar(), gridBagConstraints); leftTabPanel.add(toolbarPanel, BorderLayout.NORTH); if (GUITesting.getInstance().isRunningUnderGUITesting()) { // Use a fixed size panel for GUI testing Dimension dim = new Dimension(820, 750); timelinePanel.setPreferredSize(dim); timelinePanel.setMinimumSize(dim); timelinePanel.setMaximumSize(dim); timelinePanel.setSize(dim); JPanel tmpPanel = new JPanel(); tmpPanel.add(timelinePanel); timelinePanel.setBorder(BorderFactory.createLineBorder(Color.darkGray, 1)); leftTabPanel.add(tmpPanel, BorderLayout.CENTER); } else { leftTabPanel.add(timelinePanel, BorderLayout.CENTER); } leftTabPanel.revalidate(); } @Override public void doCompute() { // called by "Display_thread" AnUtility.checkIfOnAWTThread(false); if (!selected) { return; } if (!computed) { metaExperiment.ipcUpdateRows(); // IPC! } timelinePanel.repaint(); computed = true; } // presentation settings delivered via AnSettingChangeEvent.Type.TIMELINE //can be AWT thread public boolean[] edt_settingsChanged(List new_tm) { // presentation:timeline settings were changed final String new_entity_prop_name; final int new_entity_button_num; final Settings.TLStack_align new_stack_align; final int new_vzoom_level; final int new_stack_frame_pixels; final long new_tldata_hidden_mask; // unchecked tldata boxes final List<String> new_tldata_cnames; // (samples, ...) final List<String> new_tldata_unames; // (samples, ...) final int new_tldata_names_version; final boolean tldata_show_states, tldata_show_charts; // final ArrayList new_tm;// populated by Presentation.java // new_tm = (ArrayList) event.getAux(); new_entity_prop_name = (String) new_tm.get(0); new_entity_button_num = ((Integer) new_tm.get(1)).intValue(); new_stack_align = (Settings.TLStack_align) new_tm.get(2); new_vzoom_level = ((Integer) new_tm.get(3)).intValue(); new_tldata_hidden_mask = ((Long) new_tm.get(4)).longValue(); new_tldata_cnames = (List<String>) new_tm.get(5); new_tldata_unames = (List<String>) new_tm.get(6); new_tldata_names_version = ((Integer) new_tm.get(7)).intValue(); tldata_show_states = ((Boolean) new_tm.get(8)).booleanValue(); tldata_show_charts = ((Boolean) new_tm.get(9)).booleanValue(); new_stack_frame_pixels = ((Integer) new_tm.get(10)).intValue(); TimelineSetting.EntityProp entityProp = AnWindow.getInstance() .getSettings() .getTimelineSetting() .getTl_entity_prop(new_entity_button_num); if (entityProp == null) { return new boolean[] {false, false}; // weird } // set up next snapshot boolean drawNeeded = edt_updatePresentationDrawingOptions( new_stack_align, new_vzoom_level, new_stack_frame_pixels); boolean fetchNeeded = metaExperiment.edt_updatePresentationFetchOptions( entityProp, new_tldata_hidden_mask, tldata_show_states, tldata_show_charts, new_tldata_cnames, new_tldata_unames, new_tldata_names_version); return new boolean[] {fetchNeeded, drawNeeded}; } private boolean edt_updatePresentationDrawingOptions( // AWT only! final Settings.TLStack_align new_stack_align, final int new_vzoom_level, final int new_stack_frame_pixels) { boolean updated = false; if (drawer.event_drawer.getStackAlign() != new_stack_align) { drawer.event_drawer.setStackAlign(new_stack_align); updated = true; } if (drawer.event_drawer.getVZoomLevel() != new_vzoom_level) { drawer.event_drawer.setVZoomLevel(new_vzoom_level); drawer.event_drawer.edt_recalcRowOffsets(); if (timelinePanel != null) { timelinePanel.edt_revalidateAll(false); } updated = true; } if (drawer.event_drawer.getStackFramePixels() != new_stack_frame_pixels) { drawer.event_drawer.setStackFramePixels(new_stack_frame_pixels); updated = true; } return updated; } // YXXX not @Override? public void setCPUIdleColor(final boolean set, final Color color) { // YXXX this is retarded drawer.event_drawer.setCPUIdleColor(set, color); repaintTLDrawer(); } public void repaintTLDrawer() { // Called from data fetcher worker thread if (selected) { timelinePanel.repaint(); } } // Reset row data, stops background IPC for row fetching (force a new data snapshot, recheck // experiments) private void edt_clearRows() { // e.g. filters, user/expert/machine mode, TL presentation // create a new TL2DataSnapshot because row definitions may have changed metaExperiment.resetCurrentActivity(); // triggers repaint } // Clear display private void edt_resetExperiments() { // e.g. add/drop experiments controlPanel.resetStackView(); // FIXUP: RE_ARCH metaExperiment.resetCurrentActivity(); // triggers repaint timelinePanel.edt_resetExperiments(); } private void edt_resetAll() { // e.g. Open Experiment controlPanel.edt_resetAll(); metaExperiment.edt_resetAll(); // resets TL2DataSnapshot. Also triggers repaint drawer.edt_resetAll(); timelinePanel.edt_resetAll(); // may depend on TL2DataSnapshot being reset } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { if (GUITesting.getInstance().isRunningUnderGUITesting()) { System.out.println("timelinePanel dimensions: " + timelinePanel.getSize()); } StringBuilder buf = new StringBuilder(); // buf.append(controlPanel.exportAsText(limit)); // buf.append(timelinePanel.exportAsText(limit)); buf.append(drawer.event_drawer.exportAsText(limit)); return buf.toString(); } @Override public java.util.List<ExportFormat> getSupportedExportFormats() { java.util.List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return false; } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubviewTimeLine()); list.add(window.getTimelineCallStackSubview()); return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubviewTimeLine()); list.add(window.getTimelineCallStackSubview()); return list; } } �������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/TimelineSelectionEvent.java������������������������������0000644�0001750�0001750�00000011126�14517772113�023107� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.timeline.events.DetailsIPC; import org.gprofng.mpmt.timeline.events.EventDetail; import org.gprofng.mpmt.timeline_common.TimelineSelectionGenericEvent; import java.util.Vector; /** * Holds information about the selected timeline event. * * <p>Code is based on old timeline events and MPITL event selection. */ public class TimelineSelectionEvent extends TimelineSelectionGenericEvent { public static final long EVT_IDX_INVALID = -1; // note: value used in IPC public enum CursorAxis { UP_DOWN, LEFT_RIGHT, NA }; public final EventDetail eventDetail; // null for unknown public final int rowNum; // if -1, equivelant to "unselect" private final RowGeometry rowGeometry; // identifies row information, may be null private final RowDefinition rowDefinition; // identifies row information, may be null public final long stackId; // DetailsIPC.INVALID_STACK_ID for unknown private final Vector<StackState> stackFrames; // null for unknown // cursor movements that can be applied w.r.t. this selection public final boolean left; public final boolean right; public final boolean up; public final boolean down; public final boolean find; public final long eventIdx; // EVT_IDX_INVALID if no event under cursor; not valid after filter public final long clickTime; // time-location of mouse click, must be valid public final long eventTimeStart; public final long eventTimeEnd; public final boolean ctrlKey; public final boolean shiftKey; public final CursorAxis moveAxis; public final boolean requestCaliperUpdate; public final boolean updateRowSelections; public TimelineSelectionEvent() { // the "unselect" event this.rowNum = -1; // flags this as an unselect event this.rowGeometry = null; this.rowDefinition = null; this.eventDetail = null; this.stackId = DetailsIPC.INVALID_STACK_ID; this.stackFrames = null; left = right = up = down = find = false; this.eventIdx = EVT_IDX_INVALID; this.clickTime = 0; this.eventTimeStart = clickTime; this.eventTimeEnd = clickTime; this.ctrlKey = false; this.shiftKey = false; this.moveAxis = CursorAxis.NA; this.requestCaliperUpdate = false; this.updateRowSelections = false; } public TimelineSelectionEvent( RowGeometry rowGeometry, long clickTime, boolean ctrlKey, boolean shiftKey, CursorAxis axis, EventDetail evt, Vector<StackState> stackFrames, boolean left, boolean right, boolean up, boolean down, long eventIdx, long eventStartTime, long eventEndTime, boolean requestCaliperUpdate, boolean updateRowSelections) { this.rowGeometry = rowGeometry; if (rowGeometry == null) { this.rowNum = -1; this.rowDefinition = null; } else { this.rowNum = rowGeometry.rowNum; this.rowDefinition = rowGeometry.rowData.rowDefinition; } this.eventDetail = evt; if (evt == null) { this.stackId = DetailsIPC.INVALID_STACK_ID; } else { this.stackId = evt.getStack(); } this.stackFrames = stackFrames; this.left = left; this.right = right; this.up = up; this.down = down; this.eventIdx = eventIdx; this.find = (eventIdx != EVT_IDX_INVALID); this.clickTime = clickTime; this.eventTimeStart = eventStartTime; this.eventTimeEnd = eventEndTime; this.ctrlKey = ctrlKey; this.shiftKey = shiftKey; this.moveAxis = axis; this.requestCaliperUpdate = requestCaliperUpdate; this.updateRowSelections = updateRowSelections; } public RowGeometry getRowGeometry() { return rowGeometry; // may be null } public RowDefinition getRowDefinition() { return rowDefinition; // may be null } public Vector<StackState> getStackFrames() { Vector<StackState> vec = (Vector<StackState>) stackFrames.clone(); return vec; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/timeline2/MetaExperiment.java��������������������������������������0000644�0001750�0001750�00000054434�14517772113�021431� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.timeline2; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.experiment_props.ExperimentProperties; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.settings.TimelineSetting; import org.gprofng.mpmt.timeline2.TL2DataSnapshot.EntityDefinitions; import org.gprofng.mpmt.timeline2.TL2DataSnapshot.ExperimentDefinitions; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; // MetaExperiment is a container for holding multiple Experiments. // NOTE: Synchronization on this object is required because calls may come from // more than one thread. public final class MetaExperiment { // set by constructor parameters private final AnWindow w_IPC; // created and owned by this class: private final TL2DataFetcher tl2DataFetcher; private final TLExperiment tlExperiment; // timeline fetch settings private TimelineSetting.EntityProp entity_prop = null; // Row mode: CPU, THREAD, etc. private long tldata_hidden_mask; private boolean tldata_show_states; private boolean tldata_show_charts; private List<String> tldata_cnames; private List<String> tldata_unames; private int tldata_unames_version; // Constructor public MetaExperiment( final AnWindow awindow, final TimelineView timelineView) { // TimelineView only for doRepaint() this.w_IPC = awindow; this.tl2DataFetcher = new TL2DataFetcher(timelineView, awindow); this.tlExperiment = new TLExperiment(); init_tldata_settings(); } private void init_tldata_settings() { entity_prop = null; // Row mode: CPU, THREAD, etc. tldata_hidden_mask = 0; tldata_show_states = false; tldata_show_charts = false; tldata_cnames = new ArrayList(); tldata_unames = new ArrayList(); tldata_unames_version = -1; } public TL2DataFetcher getDataFetcher() { return tl2DataFetcher; } // --- public experiment interface ---- // clear(): old data is invalid so stop fetching and wait for *Update*() call public synchronized void resetCurrentActivity() { // action that precedes Update actions resetTimeData(); tl2DataFetcher.resetSnapshot(); } public synchronized void edt_resetAll() { // a fresh start e.g. "open experiment" // experiments.resetAll(); resetTimeData(); tl2DataFetcher.resetAll(); // YXXX: refactor: also clears color chooser colors init_tldata_settings(); } // Presentation row settings changed public synchronized boolean edt_updatePresentationFetchOptions( final TimelineSetting.EntityProp entity_prop, final long _tldata_hidden_mask, final boolean show_states, final boolean show_charts, final List<String> new_tldata_cnames, final List<String> new_tldata_unames, final int new_tldata_names_version) { boolean changed = false; if (this.entity_prop == null || this.entity_prop.prop_id != entity_prop.prop_id) { this.entity_prop = entity_prop; changed = true; } if (this.tldata_hidden_mask != _tldata_hidden_mask) { this.tldata_hidden_mask = _tldata_hidden_mask; changed = true; } if (this.tldata_show_states != show_states) { this.tldata_show_states = show_states; changed = true; } if (this.tldata_show_charts != show_charts) { this.tldata_show_charts = show_charts; changed = true; } if (this.tldata_unames_version != new_tldata_names_version) { this.tldata_unames_version = new_tldata_names_version; this.tldata_cnames = new ArrayList(new_tldata_cnames); this.tldata_unames = new ArrayList(new_tldata_unames); changed = true; } return changed; } public synchronized void ipcUpdateRows() { // generates a new TL2DataSnapshot //IPC! resetTimeData(); if (entity_prop == null) { tl2DataFetcher.setTL2DataSnapshot(null); return; } final int prop_id = entity_prop.prop_id; final calcExperimentTimeOriginsRC origins = calcExperimentTimeOrigins(false, true, true); List<ExperimentDefinitions> experimentList = new ArrayList(); final boolean comparing = w_IPC.getSettings().getCompareModeSetting().comparingExperiments(); // does not perform IPC List<ExperimentProperties> exps = w_IPC.getExperimentProperties().getAllExperimentProperties(); final int[] expIds = new int[exps.size()]; for (int ii = 0; ii < exps.size(); ii++) { expIds[ii] = exps.get(ii).getID(); } List<List<Entity>> entsList = ipcGetEntitiesV2(expIds, prop_id); for (int ii = 0; ii < entsList.size(); ii++) { ExperimentProperties expProps = exps.get(ii); List<Entity> ents = entsList.get(ii); int exp_id = expProps.getID(); List<EntityDefinitions> entityList = tlExperiment.createEntityRowDefinitions( expProps, ents, prop_id, tldata_hidden_mask, tldata_cnames, tldata_show_states, tldata_show_charts, origins.timeOrigins.get(exp_id), comparing); experimentList.add(new ExperimentDefinitions(entityList)); } experimentList = ipcPruneEmptyRows(experimentList); // IPC! TL2DataSnapshot tl2DataSnapshot; tl2DataSnapshot = new TL2DataSnapshot(entity_prop, experimentList, 0, origins.maxDuration); tl2DataFetcher.setTL2DataSnapshot(tl2DataSnapshot); } // --- internal stuff ---- private void resetTimeData() {} private List<ExperimentDefinitions> ipcPruneEmptyRows( // IPC! List<ExperimentDefinitions> experimentList) { List<ExperimentDefinitions> pruned = Collections.unmodifiableList(new ArrayList()); if (experimentList == null) { return pruned; } int sz = 0; for (ExperimentDefinitions expDef : experimentList) { for (EntityDefinitions entityDef : expDef.experimentEntities) { sz += entityDef.entityRows.size(); } } if (sz == 0) { return pruned; } int exp_ids[] = new int[sz]; int data_ids[] = new int[sz]; int entity_prop_ids[] = new int[sz]; int entity_prop_vals[] = new int[sz]; int hwctags[] = new int[sz]; int ii = 0; for (ExperimentDefinitions expDef : experimentList) { for (EntityDefinitions entityDef : expDef.experimentEntities) { for (RowDefinition row : entityDef.entityRows) { exp_ids[ii] = row.getExpID(); data_ids[ii] = row.getDataDescriptor().getDataId(); entity_prop_ids[ii] = row.getEntity().getPropId(); entity_prop_vals[ii] = row.getEntity().getPropValue(); hwctags[ii] = row.getAux(); ii++; } } } boolean[] hasData = ipcHasTLData( exp_ids, data_ids, // IPC! entity_prop_ids, entity_prop_vals, hwctags); if (hasData == null || hasData.length != sz) { return pruned; // weird } // only add rows for Entities that have data // note: each rowBlock corresponds to an entity ii = 0; ArrayList<ExperimentDefinitions> newExpList = new ArrayList(); for (ExperimentDefinitions expDef : experimentList) { ArrayList<EntityDefinitions> newEntityList = new ArrayList(); for (EntityDefinitions entityDef : expDef.experimentEntities) { boolean entityHasData = false; for (RowDefinition row : entityDef.entityRows) { if (hasData[ii]) { entityHasData = true; // break; can't break here because we have to increment ii } ii++; } if (entityHasData) { newEntityList.add(entityDef); } } if (!newEntityList.isEmpty()) { newExpList.add(new ExperimentDefinitions(newEntityList)); } } pruned = Collections.unmodifiableList(newExpList); return pruned; } // --- internal stuff ---- public static final long NANOSEC = 1000000000L; private class TimeConversion { // timestamps relating wall time to HRT nanoseconds: private final long ref_hrt_ns; // reference hrt snapshot // Time distance from reference to global (and recent) point in time private final long global_offset_ns; // nanosecond distance from ref to global point public TimeConversion(long ref_hrt_ns, long global_offset_ns) { this.ref_hrt_ns = ref_hrt_ns; this.global_offset_ns = global_offset_ns; } public long hrtToNormalizedWallNanoSec(long hrt) { final long hrt_delta = hrt - ref_hrt_ns; final long normalized_wall_ns = global_offset_ns + hrt_delta; return normalized_wall_ns; } public long normalizedWallNanoSecToHrt(long normalized_wall_ns) { final long hrt_delta = normalized_wall_ns - global_offset_ns; return hrt_delta + ref_hrt_ns; } } private class calcExperimentTimeOriginsRC { final Long maxDuration; final Map<Integer, Long> timeOrigins; // expId, computed timestamp @ origin calcExperimentTimeOriginsRC(Long maxDuration, Map<Integer, Long> timeOrigins) { this.maxDuration = maxDuration; this.timeOrigins = timeOrigins; } } private calcExperimentTimeOriginsRC calcExperimentTimeOrigins( final boolean forceAllLeft, // force founders and descendents left final boolean forceFoundersLeft, // force founders but not descedents left final boolean forceNonConcurrentLeft // force standalone founders left // final Map<Integer, Long> customOffsets ) { List<ExperimentProperties> expProps = w_IPC.getExperimentProperties().getAllExperimentProperties(); final Map<Integer, Long> rcTimeOrigins = new HashMap(); // key: expId, value: hrt of origin long rcMaxDuration = 0L; if (expProps == null || expProps.isEmpty()) { return new calcExperimentTimeOriginsRC(rcMaxDuration, rcTimeOrigins); } // loop thru all exps, save subexperiment-to-founder offsets if (forceFoundersLeft || forceAllLeft) { final Map<Integer, Long> offsets = new HashMap(); long minOffset = 0; for (ExperimentProperties exp : expProps) { final int expId = exp.getID(); long offset; if (forceAllLeft) { offset = 0; // start at experiment's origin } else { offset = exp.getTimeOffset(); // founder start } // if (customOffsets != null) { // final Long customOffset = customOffsets.get(expId); // if (customOffset != null) { // offset += customOffset; // } // } offsets.put(expId, offset); if (minOffset > offset) { // find the most negative offset minOffset = offset; } } // if(forceFoundersLeft || forceAllLeft){ // save per-experiment origin timestamp, as well as longest duration for (ExperimentProperties exp : expProps) { final int expId = exp.getID(); // normalize to minOffset so that leftmost start is at origin final long offset = offsets.get(expId) - minOffset; final long expOrigin = exp.getStartTime() - offset; final long expDuration = exp.getEndTime() - expOrigin; rcTimeOrigins.put(expId, expOrigin); rcMaxDuration = Math.max(expDuration, rcMaxDuration); } return new calcExperimentTimeOriginsRC(rcMaxDuration, rcTimeOrigins); } // Scan for founder experiments that are concurrent in time // We will left-align any founders that are not concurrent with others. // The following holds wall-to-hrtime reference values. // For a given host "epoch" (e.g. between reboots), // there should be only one pair of references used. // This is because the HRT and time of day ticks may not be synchronized class HostnameTimeRef { public final String hostname; private long wall_seconds; private long hrt; HostnameTimeRef(String hostname, long wall_seconds, long hrt) { this.hostname = hostname; this.wall_seconds = wall_seconds; this.hrt = hrt; } public boolean sameEpoch(HostnameTimeRef other) { if (!hostname.equals(other.hostname)) { return false; } final long wall_delta = (wall_seconds - other.wall_seconds) * NANOSEC; final long hrt_delta = hrt - other.hrt; final long delta = wall_delta - hrt_delta; if (Math.abs(delta) > 2 * NANOSEC) { return false; } return true; } public boolean isBetterRef(HostnameTimeRef other) { if (!sameEpoch(other)) { return false; } if (wall_seconds < other.wall_seconds) { return false; } if (hrt < other.hrt) { return false; } return true; } public void update(HostnameTimeRef other) { wall_seconds = other.wall_seconds; hrt = other.hrt; } } // Represents a blob of experiments that overlap in time: class ConcurrentExperiments { private final Map<Integer, ExperimentProperties> subexps; // expId key private final Map<Integer, HostnameTimeRef> hostInfo; // expId key private final Map<Integer, TimeConversion> timeInfo; // expId key private long start; private long end; private final long wallNormalizeSeconds; public ConcurrentExperiments(long wallNormalizeSeconds) { subexps = new HashMap(); hostInfo = new HashMap(); timeInfo = new HashMap(); start = Long.MAX_VALUE; end = Long.MIN_VALUE; this.wallNormalizeSeconds = wallNormalizeSeconds; } public boolean overlaps(ConcurrentExperiments other) { if (other == null) { return false; } if (start == Long.MAX_VALUE || end == Long.MIN_VALUE) { // anything overlaps with new object return true; // weird } if (other.start > end) { return false; } if (other.end < start) { return false; } return true; } private void updateRange(long start, long end) { if (this.start > start) { this.start = start; } if (this.end < end) { this.end = end; } } public void add(ExperimentProperties exp, HostnameTimeRef ref) { int expId = exp.getID(); long globalOffset = (ref.wall_seconds - wallNormalizeSeconds) * NANOSEC; // globalOffset += nanoSecCorrection; TimeConversion timeConv = new TimeConversion(ref.hrt, globalOffset); final long tmpStart = exp.getStartTime(); final long tmpEnd = exp.getEndTime(); final long localRefToStart = timeConv.hrtToNormalizedWallNanoSec(tmpStart); final long localRefToEnd = timeConv.hrtToNormalizedWallNanoSec(tmpEnd); updateRange(localRefToStart, localRefToEnd); subexps.put(expId, exp); hostInfo.put(expId, ref); timeInfo.put(expId, timeConv); } public void add(ConcurrentExperiments other) { if (other == null) { return; } updateRange(other.start, other.end); subexps.putAll(other.subexps); hostInfo.putAll(other.hostInfo); timeInfo.putAll(other.timeInfo); } public long getDuration() { if (start == Long.MAX_VALUE || end == Long.MIN_VALUE) { return 0; // weird } return end - start; } public long getExpHrtAtConcurrentStart(int expId) { if (start == Long.MAX_VALUE || end == Long.MIN_VALUE) { return 0; // weird } TimeConversion timeConv = timeInfo.get(expId); final long origin = timeConv.normalizedWallNanoSecToHrt(start); return origin; } } // create hostMap; maps experiments to canonical host wall-to-hrt reference values: long min_wall = Long.MAX_VALUE; long max_wall = Long.MIN_VALUE; Map<String, List<HostnameTimeRef>> hostMap = new HashMap(); // key hostname Map<Integer, HostnameTimeRef> expTimeRef = new HashMap(); // key expId for (ExperimentProperties exp : expProps) { String hostname = exp.getHostname(); if (min_wall > exp.getStartWallSeconds()) { min_wall = exp.getStartWallSeconds(); } if (max_wall < exp.getStartWallSeconds()) { max_wall = exp.getStartWallSeconds(); } HostnameTimeRef tmpRef = new HostnameTimeRef(hostname, exp.getStartWallSeconds(), exp.getStartTime()); List<HostnameTimeRef> timeRefs = hostMap.get(hostname); boolean found = false; if (timeRefs == null) { timeRefs = new ArrayList(); hostMap.put(hostname, timeRefs); } else { for (HostnameTimeRef hostRef : timeRefs) { if (hostRef.sameEpoch(tmpRef)) { if (hostRef.isBetterRef(tmpRef)) { hostRef.update(tmpRef); } tmpRef = hostRef; found = true; break; } } } if (!found) { timeRefs.add(tmpRef); } expTimeRef.put(exp.getID(), tmpRef); } if (max_wall - min_wall > Integer.MAX_VALUE) { int ii = 1; // weird! Will overflow when converted to nanoseconds } final long wallNormalizeSeconds = min_wall; // first, store all descendents as concurrent final Map<Integer, ConcurrentExperiments> founders = new HashMap(); // founderExpId key for (ExperimentProperties exp : expProps) { final int expId = exp.getID(); final Integer founderId = exp.getFounderID(); // update founder ConcurrentExperiments ConcurrentExperiments timeInfo = founders.get(founderId); if (timeInfo == null) { timeInfo = new ConcurrentExperiments(wallNormalizeSeconds); founders.put(founderId, timeInfo); } timeInfo.add(exp, expTimeRef.get(expId)); } // next, any founders that are concurrent get merged List<ConcurrentExperiments> blobs = new ArrayList(founders.values()); for (int ii = 0; ii < blobs.size(); ii++) { ConcurrentExperiments base = blobs.get(ii); if (base == null) { continue; } for (int jj = ii + 1; jj < blobs.size(); jj++) { ConcurrentExperiments cmp = blobs.get(jj); if (base.overlaps(cmp)) { base.add(cmp); blobs.set(jj, null); // mark assimilated items as null } } } // next, prune assimilated items List<ConcurrentExperiments> liveBlobs = new ArrayList(); for (ConcurrentExperiments blob : blobs) { if (blob == null) { continue; } liveBlobs.add(blob); } // scan for leftmost founders, durations for (ConcurrentExperiments blob : liveBlobs) { final long blob_offset = forceNonConcurrentLeft ? 0 : blob.start; Long duration = blob.getDuration() + blob_offset; if (rcMaxDuration < duration) { rcMaxDuration = duration; } for (Map.Entry<Integer, ExperimentProperties> entry : blob.subexps.entrySet()) { final ExperimentProperties exp = entry.getValue(); final int expId = exp.getID(); long origin = blob.getExpHrtAtConcurrentStart(expId) - blob_offset; // final long debug = exp.getStartTime() - origin; rcTimeOrigins.put(expId, origin); } } return new calcExperimentTimeOriginsRC(rcMaxDuration, rcTimeOrigins); } // ---IPC--- (Native methods from liber_dbe.so) private boolean[] ipcHasTLData( int exp_ids[], int data_ids[], int entity_prop_ids[], int entity_prop_vals[], int hwctags[]) { synchronized (IPC.lock) { w_IPC.IPC().send("hasTLData"); w_IPC.IPC().send(0); w_IPC.IPC().send(exp_ids); w_IPC.IPC().send(data_ids); w_IPC.IPC().send(entity_prop_ids); w_IPC.IPC().send(entity_prop_vals); w_IPC.IPC().send(hwctags); return (boolean[]) w_IPC.IPC().recvObject(); } } private List<Entity> processGetEntities(final Object[] objs, final int entity_prop_id) { if (entity_prop_id == Settings.PROP_NONE) { return null; } if (objs == null) { return null; } ArrayList<Entity> ents = new ArrayList(); if (objs.length == 0) { return ents; } final int prop_vals[] = (int[]) objs[0]; final String names[] = (String[]) objs[1]; final String g_names[] = (String[]) objs[2]; final String p_names[] = (String[]) objs[3]; final String propNameV[] = (String[]) objs[4]; // only 1 element expected final int[] ent_values; final int size = prop_vals.length; final String entity_prop_id_name = propNameV[0]; for (int i = 0; i < size; i++) { int prop_val = prop_vals[i]; String name = names[i]; String g_name = g_names[i]; String p_name = p_names[i]; Entity newEnt = new Entity(entity_prop_id, entity_prop_id_name, prop_val, name, g_name, p_name); ents.add(newEnt); } return ents; } private List<List<Entity>> ipcGetEntitiesV2(final int[] expIds, final int entity_prop_id) { List<List<Entity>> entsList = new ArrayList(); if (expIds.length == 0) { return entsList; } final Object[] expEntities = ipcRawGetEntitiesV2(expIds, entity_prop_id); if (expEntities == null) { return entsList; // weird; } for (int ii = 0; ii < expEntities.length; ii++) { final Object[] objs = (Object[]) expEntities[ii]; List<Entity> entities = processGetEntities(objs, entity_prop_id); entsList.add(entities); } return entsList; } private Object[] ipcRawGetEntitiesV2(final int[] expIds, final int ekind) { synchronized (IPC.lock) { w_IPC.IPC().send("getEntitiesV2"); w_IPC.IPC().send(0); w_IPC.IPC().send(expIds); w_IPC.IPC().send(ekind); return (Object[]) w_IPC.IPC().recvObject(); } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnString.java������������������������������������������������������0000644�0001750�0001750�00000002567�14517772113�016337� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; // Analyzer String object public final class AnString extends AnObject implements Comparable { private String obj; // Constructor public AnString(String value) { obj = value; } // Analyzer String printing format public String toString() { return obj; } // As String.compareTo public int compareTo(Object o) { return obj.compareTo((String) o); } // Never used // // Convert String[] to AnString[] // public static AnString[] toArray(String[] list) { // int length = list.length; // AnString[] new_list = new AnString[length]; // // for (int i = 0; i < length; i++) // new_list[i] = new AnString(list[i]); // // return new_list; // } } �����������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/SourceDisassemblyView.java�����������������������������������������0000644�0001750�0001750�00000027441�14517772113�021103� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnSplitPaneInternal; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dimension; import java.util.ArrayList; import java.util.List; import javax.swing.BoxLayout; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JViewport; /** Dual Source / Disassembly tab */ public final class SourceDisassemblyView extends AnDisplay implements ExportSupport, AnChangeListener { private JScrollPane errorPane = null; private SourceDisp upperSourcePanel; private DisasmDisp lowerSourcePanel; private JSplitPane splitPane; private boolean inCompute = false; private boolean initialized; private int focusedPart; /** Creates a new instance of SrcDisamDisp */ public SourceDisassemblyView() { super(AnWindow.getInstance(), AnDisplay.DSP_SourceDisassembly, AnVariable.HELP_TabsSrcDisassm); focusedPart = 1; initialized = false; setAccessibility(AnLocale.getString("Source/Disassembly")); AnEventManager.getInstance().addListener(this); } @Override public void requestFocus() { if (upperSourcePanel != null) { upperSourcePanel.requestFocus(); } } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("SourceDisassemblyView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: setComputed(false); clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: if (selected) { filterChanged(); } setComputed(false); if (selected) { computeOnAWorkerThread(); } break; case SOURCE_FINDING_CHANGED: setComputed(false); if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.SRC_DIS || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.SEARCH_PATH || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.PATH_MAP || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { setComputed(false); if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void setComputed(boolean set) { super.setComputed(set); upperSourcePanel.setComputed(set); lowerSourcePanel.setComputed(set); } @Override public JPopupMenu getFilterPopup() { return upperSourcePanel.getFilterPopup(); } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String text; text = upperSourcePanel.exportAsText(limit, format, delimiter); text = text + lowerSourcePanel.exportAsText(limit, format, delimiter); return text; } @Override protected void initComponents() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); upperSourcePanel = new SourceDisp( window, AnDisplay.DSP_Source, null, AnDisplay.DSP_SourceDisassembly); // AnVariable.HELP_TabsSource); lowerSourcePanel = new DisasmDisp( window, AnDisplay.DSP_Disassembly, null, AnDisplay.DSP_SourceDisassembly); // AnVariable.HELP_TabsDisassembly); lowerSourcePanel.table.setWrapMetricNames(false); // make the both parts to be 0ed Dimension minDim = new Dimension(0, 0); upperSourcePanel.setMinimumSize(minDim); lowerSourcePanel.setMinimumSize(minDim); splitPane = new AnSplitPaneInternal(JSplitPane.VERTICAL_SPLIT, upperSourcePanel, lowerSourcePanel); // the both parts are equals splitPane.setResizeWeight(0.5); // put the split bar in the middle splitPane.setDividerLocation(0.5); // // splitPane.setOneTouchExpandable(true); add(splitPane); } @Override public synchronized void doCompute() { AnUtility.checkIfOnAWTThread(false); if (!selected) { return; // Not selected } if (window .getSettings() .getCompareModeSetting() .comparingExperiments()) { // XXXX show error when compare is on, needs simplified, but the // situation is different for different views reset(); JLabel error_label = new JLabel(); error_label.setHorizontalAlignment(JLabel.CENTER); error_label.getAccessibleContext().setAccessibleName(AnLocale.getString("Error message")); error_label .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Error message")); JViewport error_view = new JViewport(); error_view.setView(error_label); String msg = AnLocale.getString("Not available when comparing experiments"); error_label.setText(msg); if (errorPane == null) { errorPane = new AnJScrollPane(); add(errorPane, BorderLayout.CENTER); } errorPane.setViewportView(error_view); errorPane.setVisible(true); if (splitPane != null) { splitPane.setVisible(false); } return; } if (errorPane != null) { errorPane.setVisible(false); } if (splitPane != null) { splitPane.setVisible(true); } if (inCompute) { return; // Weak synchronization } inCompute = true; if (!initialized) { initialized = true; splitPane.setDividerLocation(0.5); } if (true) // cur_pc_2 != parent.getSelPC(2) ) { // System.err.println("Update low"); lowerSourcePanel.setSelected(true); lowerSourcePanel.doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) } if (true) // cur_pc_1 != parent.getSelPC(1) ) { upperSourcePanel.setSelected(true); upperSourcePanel.doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) } computed = true; inCompute = false; } private static JPanel toolbarPanel = null; // Fixup: pass it to SourceDisp instead of being static!!!! public static JPanel getToolbarPanelInternal() { if (toolbarPanel == null) { toolbarPanel = new JPanel(); toolbarPanel.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); toolbarPanel.setLayout(new BorderLayout()); } return toolbarPanel; } @Override public JPanel getToolbarPanel() { return getToolbarPanelInternal(); } // Update view specific tool bar public void updateToolBar() { if (focusedPart == 1 && upperSourcePanel != null) { upperSourcePanel.updateToolBar(); } else if (focusedPart == 2 && lowerSourcePanel != null) { lowerSourcePanel.updateToolBar(); } } /** Remember which part is active (has focus) to continue search */ public void focusInHalf(int stype) { if (stype == AnTable.AT_SRC) { focusedPart = 1; } if (stype == AnTable.AT_DIS) { focusedPart = 2; } } public void syncHalf(int stype) { if (focusedPart == 2 && stype == AnTable.AT_SRC) { upperSourcePanel.computeOnAWorkerThread(); } if (focusedPart == 1 && stype == AnTable.AT_DIS) { lowerSourcePanel.computeOnAWorkerThread(); } } // @Override public void filterChanged() { // System.out.println("SourceDisassemblyView:filterChanged: " + this); if (upperSourcePanel == null || lowerSourcePanel == null) { return; } upperSourcePanel.filterChanged(); lowerSourcePanel.filterChanged(); } @Override public void clearHistory() { if (upperSourcePanel == null || lowerSourcePanel == null) { return; } upperSourcePanel.clearHistory(); lowerSourcePanel.clearHistory(); } @Override protected boolean supportsFindText() { return true; } /** Find */ @Override public int find(final String str, final boolean next, boolean caseSensitive) { int value = -1; if (focusedPart == 1) { value = upperSourcePanel.find(str, next, caseSensitive); } else if (focusedPart == 2) { value = lowerSourcePanel.find(str, next, caseSensitive); } return value; } @Override public java.util.List<ExportFormat> getSupportedExportFormats() { java.util.List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.JPG); formats.add(ExportFormat.TEXT); return formats; } @Override public boolean exportLimitSupported() { return false; } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); list.add(window.getTimelineCallStackSubview()); list.add(window.getIoCallStackSubview()); return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnDialog.java������������������������������������������������������0000644�0001750�0001750�00000022314�14517772113�016260� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.util.gui.AnJScrollPane; import java.awt.BorderLayout; import java.awt.Container; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import javax.accessibility.AccessibleContext; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.KeyStroke; import javax.swing.border.EmptyBorder; public abstract class AnDialog extends JDialog implements ActionListener { protected int win_id; protected AnWindow window; protected final AnDialog dialog; protected boolean close_on_enter; private final Frame frame; private JPanel work_area; private JPanel response; protected ResponseAction ok, apply, close; private ResponseAction help; public ResponseAction[] aux_actions; private final String help_id; private boolean locationSet = false; public final AnWindow getWindow() { return window; } // Constructor public AnDialog( final AnWindow awindow, final Frame frame, final String title, final boolean has_scroll, final String[] aux, final char[] mnemonic, final String help_id) { super(frame, title); this.win_id = 0; this.frame = frame; window = awindow; dialog = this; close_on_enter = true; this.help_id = help_id; // Initialize GUI components & center it in frame initComponents(has_scroll, aux, mnemonic); final AccessibleContext context = dialog.getAccessibleContext(); context.setAccessibleName(title); context.setAccessibleDescription(title); } // Constructor with modal setting public AnDialog( final AnWindow awindow, final Frame frame, final String title, final boolean has_scroll, final String[] aux, final char[] mnemonic, final String help_id, final boolean modal) { super(frame, title, modal); this.win_id = 0; this.frame = frame; window = awindow; dialog = this; close_on_enter = true; this.help_id = help_id; // Initialize GUI components & center it in frame initComponents(has_scroll, aux, mnemonic); final AccessibleContext context = dialog.getAccessibleContext(); context.setAccessibleName(title); context.setAccessibleDescription(title); } // Initialize GUI components private void initComponents(final boolean has_scroll, final String[] aux, final char[] mnemonic) { final Container cnt; JPanel panel; final int nb; cnt = getContentPane(); cnt.setLayout(new BorderLayout()); // work area work_area = new JPanel(new BorderLayout(4, 4)); work_area.setOpaque(false); work_area.setBorder(new EmptyBorder(12, 12, 0, 12)); panel = new JPanel(new GridLayout(1, 1)); panel.setOpaque(false); // panel.setBorder(new BevelBorder(BevelBorder.LOWERED)); panel.add(has_scroll ? (JComponent) new AnJScrollPane(work_area) : (JComponent) work_area); cnt.add(panel, BorderLayout.CENTER); // response area GridBagConstraints gridBagConstraints; response = new JPanel(new GridBagLayout()); response.setOpaque(false); // response.setBackground(AnEnvironment.DEFAULT_DIALOG_BACKGROUND); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; // gridBagConstraints.weightx = 1.0; // Filler gridBagConstraints.insets = new java.awt.Insets(8, 8, 12, 0); response.add(new JLabel(), gridBagConstraints); gridBagConstraints.insets = new java.awt.Insets(8, 4, 12, 0); // Add online help if (aux == null) { aux_actions = null; } else { nb = aux.length; aux_actions = new ResponseAction[nb]; for (int i = 0; i < nb; i++) { response.add(aux_actions[i] = new ResponseAction(aux[i], mnemonic[i]), gridBagConstraints); } } gridBagConstraints.weightx = 1.0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; response.add(new JLabel(""), gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(8, 0, 12, 4); response.add(ok = new ResponseAction(AnLocale.getString("OK")), gridBagConstraints); response.add( apply = new ResponseAction( AnLocale.getString("Apply"), AnLocale.getString('A', "MNEM_DIALOG_APPLY")), gridBagConstraints); response.add( close = new ResponseAction(AnLocale.getString("Close", "DIALOG_CLOSE"), ' '), gridBagConstraints); if (help_id != null) { final String command = AnLocale.getString("Help", "DIALOG_HELP"); response.add( help = new ResponseAction(command, AnLocale.getString('H', "MNEM_DIALOG_HELP")), gridBagConstraints); // ((JComponent) cnt).registerKeyboardAction(help, command, // KeyboardShortcuts.helpActionShortcut, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); // ((JComponent) cnt).registerKeyboardAction(help, command, // KeyboardShortcuts.helpActionShortcut, JComponent.WHEN_FOCUSED); ((JComponent) cnt) .registerKeyboardAction( help, command, KeyboardShortcuts.helpActionShortcut, JComponent.WHEN_IN_FOCUSED_WINDOW); } // Filler gridBagConstraints.insets = new java.awt.Insets(4, 0, 12, 8); response.add(new JLabel(), gridBagConstraints); getRootPane().setDefaultButton(ok); ((JComponent) cnt) .registerKeyboardAction( ok, AnLocale.getString("OK"), KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); ((JComponent) cnt) .registerKeyboardAction( close, AnLocale.getString("Close", "DIALOG_CLOSE"), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); panel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); panel.add(response); cnt.add(response, BorderLayout.SOUTH); } public final void setWin(final AnWindow awin) { window = awin; win_id = 0; } // Get win_id public final int getID() { return win_id; } public final JPanel getWorkArea() { return work_area; } /** * Gets default buttons * * @return */ public JButton[] getDefaultButtons() { JButton[] buttons = new JButton[3]; buttons[0] = (JButton) ok; buttons[1] = (JButton) apply; buttons[2] = (JButton) close; return buttons; } // Set visible @Override public void setVisible(final boolean aFlag) { if (aFlag) { if (!locationSet) { setLocationRelativeTo(frame); locationSet = true; } } super.setVisible(aFlag); if (aFlag) { work_area.requestFocus(); } } // Add component in work area protected final void setAccessory(final JComponent work) { work_area.add(work, BorderLayout.CENTER); pack(); } protected boolean vetoClose() { return false; } protected final class ResponseAction extends JButton implements ActionListener { public ResponseAction(final String text) { super(text); final AccessibleContext context = this.getAccessibleContext(); context.setAccessibleName(text); context.setAccessibleDescription(text); addActionListener(this); } public ResponseAction(final String text, final char mnemonic) { this(text); if (mnemonic != ' ') { setMnemonic(mnemonic); } } @Override public void actionPerformed(final ActionEvent event) { final String cmd = event.getActionCommand(); if (cmd.equals(AnLocale.getString("OK"))) { dialog.actionPerformed(event); if (!vetoClose() && (close_on_enter || (event.getSource() != getContentPane()))) { dialog.setVisible(false); } } else if (cmd.equals(AnLocale.getString("Apply"))) { dialog.actionPerformed(event); } else if (cmd.equals(AnLocale.getString("Close", "DIALOG_CLOSE"))) { if (close_on_enter || (event.getSource() != getContentPane())) { dialog.setVisible(false); } } else if (cmd.equals(AnLocale.getString("Help", "DIALOG_HELP"))) { Analyzer.showHelp(help_id); } else { dialog.actionPerformed(event); } } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/SourceDisp.java����������������������������������������������������0000644�0001750�0001750�00000217153�14517772113�016671� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnTable.SelObjInfo; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.Shape; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.util.ArrayList; import java.util.HashMap; import java.util.Set; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTextPane; import javax.swing.SwingUtilities; import javax.swing.border.LineBorder; import javax.swing.text.BadLocationException; import javax.swing.text.DefaultHighlighter; import javax.swing.text.Highlighter; import javax.swing.text.JTextComponent; import javax.swing.text.LayeredHighlighter; import javax.swing.text.Position; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; import javax.swing.text.View; public class SourceDisp extends FuncListDisp { private int[] src_type; // private boolean can_comp; private int prevScroll = -1; private boolean inCompute = false; private int my_src_type = AnTable.AT_SRC; private int my_src_type_only = AnTable.AT_SRC_ONLY; /** Keeps last warning to avoid showing the same warning message many times */ private String lastWarning = null; protected SelObjInfo lastFilterSelection = null; protected long lastSelSrc = -1; protected long lastSelFunc = -1; // Constructor public SourceDisp(final AnWindow window, final int type, final String help_id) { super(window, type, 0, help_id); } // Constructor public SourceDisp(final AnWindow window, final int type, final String help_id, final int ptype) { super(window, type, 0, help_id); parent_type = ptype; } // Constructor public SourceDisp( final AnWindow window, final int type, final int subtype, final String help_id, final int ptype) { super(window, type, subtype, help_id); parent_type = ptype; } // Initialize GUI components protected void initComponents() { setLayout(new BorderLayout()); String acName = null; String acDesc = null; JLabel acLabel = null; acName = AnLocale.getString("Source"); acDesc = AnLocale.getString("Show source for selected function"); if (acName != null) { acLabel = new JLabel(acName, JLabel.RIGHT); } table = new AnTable(type, true, true, can_sort, false, true, true, true, acName, acDesc, acLabel); table.setParent(this); if (acLabel != null) { acLabel.setVisible(false); acLabel.setDisplayedMnemonic(acName.charAt(0)); table.add(acLabel); } table.addAnListener(new TableHandler()); add(table, BorderLayout.CENTER); HotGapPanel hotGapPanel = new HotGapPanel(this); table.setHotGapPanel(hotGapPanel); add(hotGapPanel, BorderLayout.EAST); warningPane = new JPanel(); warningPane.setVisible(false); // warningPane.setBorder(AnVariable.textBorder); warningPane.setBorder(new LineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR)); add(warningPane, BorderLayout.SOUTH); } // Clear display @Override public void clear() { if (table != null) { table.removeAll(); } } @Override public void clearHistory() { if (table != null) { table.clearHistory(); } } public int getParentType() { return this.parent_type; } // Compute & update function list table @Override public void doCompute() { final long sel_obj; int new_ind; final int sort_ind; final Object[] raw_data; final String pwarnstr; final MetricLabel[] label; AnUtility.checkIfOnAWTThread(false); // Not selected if (!selected) { return; } if (inCompute) { // NM TEMPORARY should be synchronized return; } else { inCompute = true; } if (lastFilterSelection != null) { window.getSelectedObject().setSelObjV2(lastFilterSelection.id); } if (!forceCompute && parent_type != AnDisplay.DSP_SourceDisassembly && table.srcRenderer.functionIdToRow != null) { long src_obj = window.getSelectedObject().getSelObj(DSP_SourceSelectedObject, 0); long funcId = window.getSelectedObject().getSelObjV2("FUNCTION"); Integer targetRow = table.srcRenderer.functionIdToRow.get(funcId); if (targetRow != null && src_obj == sel_src && src_obj != 0) { int targetFuncRow = (targetRow - 1 >= 0) ? (targetRow - 1) : 0; long cur_sel_obj = window.getSelectedObject().getSelObj(type, subtype); int sel_ind = window.getSelectedObject().getSelIndex(cur_sel_obj, type, subtype); if (sel_ind != -1) { window.getSelectedObject().setSelObj(sel_ind, type, subtype); targetFuncRow = sel_ind; boolean recordHistory = table.getNavigationHistoryPool().getHistory().enabled; if (recordHistory) { table.getNavigationHistoryPool().getHistory().enabled = false; } table.setSelectedRow(targetFuncRow); if (recordHistory) { table.getNavigationHistoryPool().getHistory().enabled = true; } table.fireAnEvent(new AnEvent(table, AnEvent.EVT_SELECT, targetFuncRow, null)); table.srcRenderer.tryAddNewObj(); table.getAnParent().updateToolBar(); inCompute = false; computed = true; window .getCalledByCallsSourceView() .doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) lastSelFunc = table.srcRenderer.getFunctionBaseRowWhenCompare(targetFuncRow); if (tailAction != null) { tailAction.tailFunction(); tailAction = null; } return; } } } if (forceCompute) { forceCompute = false; } sel_obj = window.getSelectedObject().getSelObj(type, subtype); // sel_func = window.getSelObj(DSP_FUNCTION, 0); // if (-1 == sel_func) { sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) // } if (!computed) { // need re-compute reset(); Object[] res = setFuncData(sel_func, type, subtype); new_ind = (int) ((long[]) (res[0]))[0]; String errstr = ((String[]) (res[1]))[0]; long sf_id = ((long[]) (res[0]))[1]; String sf_name = ((String[]) (res[1]))[1]; // Update table if (errstr == null) { updateWarningPanel(); table.setViewport(); Object[][] table_data; raw_data = getFuncList(type, subtype); Object[] raw_marks = getHotMarks(type); Object[] raw_marks_inc = getHotMarksInc(type); int[][] marks = new int[2][]; marks[0] = (int[]) raw_marks[0]; marks[1] = (int[]) raw_marks[1]; int[][] marks_inc = new int[2][]; marks_inc[0] = (int[]) raw_marks_inc[0]; marks_inc[1] = (int[]) raw_marks_inc[1]; final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(type); table_data = localProcessData( mlist, raw_data); // first index is for column, second index is for rows src_type = (int[]) raw_data[raw_data.length - 1]; // AnTable.AnTable.AT_SRC, DIS, QUOTE, etc. String[] hdrContent = getNames(type, 0); // name column table header contents (?) label = getSettings().getMetricsSetting().getLabel(table_data, null, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); new_ind = (new_ind == -1) ? 0 : new_ind; int sel_ind = window.getSelectedObject().getSelIndex(sel_obj, type, subtype); if (sel_ind == -1) { // XXX we should not call setSelObj when we go to the Source tab window .getSelectedObject() .setSelObj(new_ind, type, subtype); // set SelObj DSP_SRC_FILE before renderSrc() sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) } table.setData( label, table_data, hdrContent, src_type, new_ind, name_col, sort_ind, marks, marks_inc); if (sel_func == 0) { // XXX we should not call setSelObj when we go to the Source tab window.getSelectedObject().setSelObj(new_ind, type, subtype); } } else { window.getExperimentsView().appendLog(AnLocale.getString("Error: ") + errstr); if (sf_name == null || sf_name.startsWith("(")) { // FIXUP: need better API table.showMessage(errstr); } else { table.showMessage(new CannotFindFilePanel(errstr, sf_name, sf_id)); } // table.showMessage(errstr, sf_name, sf_id); computed = true; inCompute = false; return; } } // Update selected row new_ind = window.getSelectedObject().getSelIndex(sel_obj, type, subtype); if (new_ind == -1) { new_ind = table.getSelectedRow(); if (new_ind == -1) { new_ind = 0; } table.showSelectedRow(); // if (-1 == sel_func) { // Do we need sel_func? sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) // } } else { table.setSelectedRow(new_ind); } // XXX we should not call setSelObj when we go to the Source tab window.getSelectedObject().setSelObj(new_ind, type, subtype); // scroll to previous location after re-sort if (prevScroll > 0) { table.setScroll(prevScroll); prevScroll = -1; } updateGap(); // Update summary display if (parent_type != AnDisplay.DSP_SourceDisassembly) { updateSummary(new_ind); } computed = true; // pstatstr = window.getMsg(AnUtility.PSTAT_MSG); pwarnstr = window.getMsg(AnUtility.PWARN_MSG); // if (pstatstr != null) { // window.appendLog(pstatstr); // } if (pwarnstr != null) { window.showProcessorWarning(pwarnstr); } if (lastFilterSelection != null) { if (lastSelSrc == sel_src && lastFilterSelection.lineno != -1) { table.setSelectedRow(lastFilterSelection.lineno); // XXX we should not call setSelObj when we go to the Source tab window.getSelectedObject().setSelObj(lastFilterSelection.lineno, type, subtype); } lastFilterSelection = null; lastSelSrc = -1; } // Set toolbar and select subviews updateToolBar(); window .getCalledByCallsSourceView() .doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) lastSelFunc = table.srcRenderer.getFunctionBaseRowWhenCompare(new_ind); if (tailAction != null) { tailAction.tailFunction(); tailAction = null; } inCompute = false; } protected BackForwardControls getBackForwardControls() { if (backForwardControls == null) { backForwardControls = new BackForwardControls(); } backForwardControls.updateToolBarStatus(); return backForwardControls; } @Override public void updateToolBar() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { if (backForwardControls == null) { backForwardControls = new BackForwardControls(); } backForwardControls.updateToolBarStatus(); if (parent_type == AnDisplay.DSP_SourceDisassembly) { if (type == AnDisplay.DSP_Disassembly) { SourceDisassemblyView.getToolbarPanelInternal().removeAll(); SourceDisassemblyView.getToolbarPanelInternal() .add(backForwardControls, BorderLayout.CENTER); SourceDisassemblyView.getToolbarPanelInternal().repaint(); } } else if (parent_type == AnDisplay.DSP_DualSource) { DualSourceView.getToolbarPanelInternal().removeAll(); DualSourceView.getToolbarPanelInternal() .add(backForwardControls, BorderLayout.CENTER); DualSourceView.getToolbarPanelInternal().repaint(); } else { AnCompDisp.getToolbarPanelInternal().removeAll(); AnCompDisp.getToolbarPanelInternal().add(backForwardControls, BorderLayout.CENTER); AnCompDisp.getToolbarPanelInternal().repaint(); } } }); } @Override public void syncSrcDisWin() { if (parent_type == DSP_SourceDisassembly) { if (type == DSP_Source) { window.getSourceDisassemblyView().focusInHalf(AnTable.AT_SRC); window.getSourceDisassemblyView().syncHalf(AnTable.AT_DIS); } else if (type == DSP_Disassembly) { window.getSourceDisassemblyView().focusInHalf(AnTable.AT_DIS); window.getSourceDisassemblyView().syncHalf(AnTable.AT_SRC); } } } // Set current func/load-object in 'selected func' & summary display private void updateSummary(final int new_ind) { int[] rows = table.getSelectedRows(); if (null != rows) { if (rows.length > 1) { // Special case for multiselection: pass only lines with my_src_type int len = 0; for (int i = 0; i < rows.length; i++) { int k = rows[i]; if (k < src_type.length) { int stype = src_type[k]; if (stype < 0) { stype = -stype; } if ((stype == my_src_type) || (stype == my_src_type_only)) { len++; } } } if ((len > 0) && (len != rows.length)) { long[] filtered_rows = new long[len]; for (int i = 0, m = 0; i < rows.length; i++) { int k = rows[i]; int stype = src_type[k]; if (stype < 0) { stype = -stype; } if ((stype == my_src_type) || (stype == my_src_type_only)) { filtered_rows[m] = rows[i]; m++; } } window.getSelectionManager().updateSelection(filtered_rows, type, subtype, 1); return; } } window.getSelectionManager().updateSelection(rows, type, subtype, 1); // } else { // no source } } @Override public void goToLine(final AnTable tbl, final int row) { AnDisplay anDisplay = null; if (tbl.getNavigationHistoryPool() != null) { if (type == DSP_Source) { tbl.getNavigationHistoryPool().getHistory().goToSrcNew(row); anDisplay = window.getCalledByCallsSourceView(); } else if (type == DSP_Disassembly) { tbl.getNavigationHistoryPool().getHistory().goToDisNew(row); anDisplay = window.getCalledByCallsDisassemblyView(); } updateToolBar(); } tbl.setSelectedRow(row); window.getSelectedObject().setSelObj(row, type, subtype); long curSelFunc = window.getSelectedObject().getSelObjV2("FUNCTION"); if (curSelFunc != lastSelFunc || curSelFunc == 0) { lastSelFunc = curSelFunc; anDisplay.setComputed(false); anDisplay.computeOnAWorkerThread(); } updateSummary(row); syncSrcDisWin(); } // Listener for updating table private final class TableHandler implements AnListener { public void valueChanged(final AnEvent event) { final int from; final int to; int stype = 0; final boolean can_nav; switch (event.getType()) { case AnEvent.EVT_SELECT: // Selecting from = event.getValue(); if (can_sort) { can_nav = true; } else { stype = src_type[from]; if (stype < 0) { stype = -stype; } can_nav = (stype == AnTable.AT_SRC) || (stype == AnTable.AT_SRC_ONLY) || (stype == AnTable.AT_FUNC) || (stype == AnTable.AT_DIS) || (stype == AnTable.AT_QUOTE); } if ((type == DSP_Source)) { deselectRaceStack(subtype); // FIXUP: REARCH window.getSourceDisassemblyView().focusInHalf(AnTable.AT_SRC); } if ((type == DSP_SourceDisassembly) || (type == DSP_Disassembly)) { if (stype == AnTable.AT_DIS) { window.getSourceDisassemblyView().focusInHalf(AnTable.AT_DIS); } else { // SOURCE window.getSourceDisassemblyView().focusInHalf(AnTable.AT_SRC); } } // Set selected object & Update summary display if (can_nav) { window.getSelectedObject().setSelObj(from, type, subtype); long curSelFunc = window.getSelectedObject().getSelObjV2("FUNCTION"); if (curSelFunc != lastSelFunc || curSelFunc == 0) { lastSelFunc = curSelFunc; window.getCalledByCallsSourceView().setComputed(false); window.getCalledByCallsSourceView().computeOnAWorkerThread(); } updateSummary(from); if (parent_type == DSP_SourceDisassembly) { window.getSourceDisassemblyView().syncHalf(AnTable.AT_DIS); } // if ((type == DSP_SOURCE) || (type == DSP_DISASM)) { // // fixme, xxxx to make MARTY and RDT people happy, Do not // pop Summary Tab to top for Source or Disasm // } else { // window.showSummary(); // } } else // in other cases (eg. AnTable.AT_SRC_ONLY), just update summary { long curSelFunc = window.getSelectedObject().getSelObjV2("FUNCTION"); if (curSelFunc != lastSelFunc || curSelFunc == 0) { lastSelFunc = curSelFunc; window.getCalledByCallsSourceView().setComputed(false); window.getCalledByCallsSourceView().computeOnAWorkerThread(); } updateSummary(from); } // if (parent_type == DSP_SOURCE_DISASM) { // XXXX don't update toolbar // for src in src&dis view // updateToolBar(); // } break; case AnEvent.EVT_SORT: // Sorting // save current scroll location prevScroll = table.getScroll(); int functionsColumn = getFuncSortColumn(((Integer) event.getAux()).intValue()); getSettings() .getMetricsSetting() .setSortMetricByDType(this, functionsColumn, AnDisplay.DSP_Functions); break; case AnEvent.EVT_COPY_ALL: // Copy all lines copyAll(); break; case AnEvent.EVT_COPY_SEL: // Copy selected lines copySelected(); break; case AnEvent.EVT_SWITCH: // Column switching if (table != null) { table.columnsSaved = false; } from = event.getValue(); to = ((Integer) event.getAux()).intValue(); getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, type); break; } } } protected int getFuncSortColumn(int srcdis_sort_ind) { int ret = -1; AnMetric[] func_mlist = getSettings().getMetricsSetting().getMetricListByMType(MetricsSetting.MET_NORMAL); AnMetric[] srcdis_mlist = getSettings().getMetricsSetting().getMetricListByMType(MetricsSetting.MET_SRCDIS); if (srcdis_sort_ind < 0 || srcdis_sort_ind >= srcdis_mlist.length) { return -1; } for (int ind = 0; ind < func_mlist.length; ind++) { if (srcdis_mlist[srcdis_sort_ind].getUserName().equals(func_mlist[ind].getUserName())) { ret = ind; break; } } if (ret == -1) { ret = getSettings().getMetricsSetting().getSortColumnByDType(AnDisplay.DSP_Functions); } return ret; } // Is current selected tab? @Override public void setSelected(final boolean set) { selected = set; window.getCalledByCallsSourceView().setSelected(set); } // @Override // public String exportAsText(Integer limit, ExportSupport.ExportFormat format, Character // delimiter) { // // Update Total value // AnObject[] totals = getTotals(type, subtype); // IPC call // if (totals != null) { // if (MaximumValues == null) { // MaximumValues = new Object[2][totals.length]; // MaximumValues[1] = totals; // } // MaximumValues[0] = totals; // } // // Call super.exportAsText // String text = super.exportAsText(limit, format, delimiter); // return text; // } public void filterChanged() { long id = window.getSelectedObject().getSelObjV2("FUNCTION"); int cur_line = table.getSelectedRow(); lastFilterSelection = new SelObjInfo(id, cur_line, ""); lastSelSrc = sel_src; forceCompute = true; } /* * Class to render source code for simple syntax highlighting */ static class SrcRenderer { // Fortran keywords (see CR 7206640) private final String[] FORTRAN95_KEYWORDS = { "assign", "backspace", "block", "data", "call", "close", "common", "continue", "data", "dimension", "do", "else", "if", "end", "endfile", "endif", "entry", "equivalence", "external", "format", "function", "goto", "implicit", "inquire", "intrinsic", "open", "parameter", "pause", "print", "program", "read", "return", "rewind", "rewrite", "save", "stop", "subroutine", "then", "write", "allocate", "allocatable", "case", "contains", "cycle", "deallocate", "elsewhere", "exit", "include", "interface", "intent", "module", "namelist", "nullify", "only", "operator", "optional", "pointer", "private", "procedure", "public", "result", "recursive", "select", "sequence", "target", "use", "while", "where", "elemental", "forall", "pure", "integer", "real", "complex", "logical", "character", "double", "precision", "type", "kind", "in", "out", "inout", "blockdata", "doubleprecision", "elseif", "elsewhere", "endblockdata", "enddo", "endforall", "endfunction", "endinterface", "endmodule", "endprogram", "endselect", "endsubroutine", "endtype", "endwhere", "selectcase", "selecttype" }; private final String[] JAVA_KEYWORDS = { "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "const", "continue", "default", "do", "double", "else", "enum", "extends", "false", "final", "finally", "float", "for", "goto", "if", "implements", "import", "instanceof", "int", "interface", "long", "native", "new", "null", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "true", "transient", "try", "void", "volatile", "while" }; private final String[] C_KEYWORDS = { "auto", "_Bool", "break", "case", "char", "_Complex", "const", "continue", "default", "do", "double", "else", "enum", "extern", "float", "for", "goto", "if", "_Imaginary", "inline", "int", "long", "register", "restrict", "return", "short", "signed", "sizeof", "static", "struct", "switch", "typedef", "union", "unsigned", "void", "volatile", "while" }; private final String[] CPP_KEYWORDS = { "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break", "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "const", "constexpr", "const_cast", "continue", "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit", "export", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long", "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr ", "operator", "or", "or_eq", "private", "protected", "public", "register", "reinterpret_cast", "return", "short", "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this", "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq" }; private final String SPLIT_PATTERN = "[@$~!%&();,#<>*/= +-?:.|\\[\\]{}^]"; protected final HashMap<String, Boolean> fortran95KeywordMap; protected final HashMap<String, Boolean> javaKeywordMap; protected final HashMap<String, Boolean> cKeywordMap; protected final HashMap<String, Boolean> cppKeywordMap; protected int caretLinePosition = -1; protected AnTable fl_table; public SrcRenderer(AnTable table) { fl_table = table; fortran95KeywordMap = new HashMap<String, Boolean>(); javaKeywordMap = new HashMap<String, Boolean>(); cKeywordMap = new HashMap<String, Boolean>(); cppKeywordMap = new HashMap<String, Boolean>(); for (int i = 0; i < FORTRAN95_KEYWORDS.length; i++) { fortran95KeywordMap.put(FORTRAN95_KEYWORDS[i], Boolean.TRUE); } for (int i = 0; i < JAVA_KEYWORDS.length; i++) { javaKeywordMap.put(JAVA_KEYWORDS[i], Boolean.TRUE); } for (int i = 0; i < C_KEYWORDS.length; i++) { cKeywordMap.put(C_KEYWORDS[i], Boolean.TRUE); } for (int i = 0; i < CPP_KEYWORDS.length; i++) { cppKeywordMap.put(CPP_KEYWORDS[i], Boolean.TRUE); } } protected String srcType = "c"; protected Object[][] tableData = null; protected int[] srcTypeData = null; protected boolean srcInComment = false; protected HashMap<Integer, SrcTextMarker> srcRendered = null; // stores cached SrcTextMarker of each line protected HashMap<Integer, SrcTextPane> srcPaneCreated = null; // stores cached SrcTextPane of each line protected HashMap<Long, HashMap<Integer, SrcTextMarker>> srcRenderedMap = new HashMap< Long, HashMap< Integer, SrcTextMarker>>(); // stores cached srcRendered of each selected object that has // been shown in Source View before protected HashMap<Long, HashMap<Integer, SrcTextPane>> srcPaneCreatedMap = new HashMap< Long, HashMap< Integer, SrcTextPane>>(); // stores cached srcPaneCreated of each selected object that has // been shown in Source View before protected int maxSrcCachedNumber = 15; // XXXX cacheing asumes the content will always be the same for the same DSP_SRC_FILE // object protected HashMap<Long, HashMap<Integer, String>> functionRenderedMap = new HashMap<Long, HashMap<Integer, String>>(); protected HashMap<Integer, String> functionRendered = null; // a map from row to function name protected HashMap<Long, HashMap<Integer, Boolean>> functionCallerCalleeAddedMap = new HashMap<Long, HashMap<Integer, Boolean>>(); protected HashMap<Integer, Boolean> functionCallerCalleeAdded = null; // a map from row to whether it's been added caller-callee info protected HashMap<Long, HashMap<Long, ArrayList<SelObjInfo>>> callerInfoMap = new HashMap<Long, HashMap<Long, ArrayList<SelObjInfo>>>(); protected HashMap<Long, ArrayList<SelObjInfo>> callerInfo = null; // a map from function id to its callers' ids protected HashMap<Long, HashMap<Integer, ArrayList<SelObjInfo>>> calleeInfoMap = new HashMap<Long, HashMap<Integer, ArrayList<SelObjInfo>>>(); protected HashMap<Integer, ArrayList<SelObjInfo>> calleeInfo = null; // a map from call site row to callees' ids protected HashMap<Long, ArrayList<Long>> functionIdMap = new HashMap<Long, ArrayList<Long>>(); protected ArrayList<Long> functionId = null; // a vector of function id of each row or null protected HashMap<Long, HashMap<Long, Integer>> functionIdToRowMap = new HashMap<Long, HashMap<Long, Integer>>(); protected HashMap<Long, Integer> functionIdToRow = null; // a map from function id to row protected HashMap<Long, HashMap<Integer, Integer>> lineNoToRowMap = new HashMap<Long, HashMap<Integer, Integer>>(); protected HashMap<Integer, Integer> lineNoToRow = null; // a map from line number to row protected HashMap<Long, HashMap<Integer, Integer>> newRowToOldRowMap = new HashMap<Long, HashMap<Integer, Integer>>(); protected HashMap<Integer, Integer> newRowToOldRow = null; // a map from new row to old row protected ArrayList<Integer> rowToFuncBaseRow = null; protected int old_viewmode = -1; protected Object[] getFuncCalleeInfo(final int type, final int[] rows, final int groupId) { synchronized (IPC.lock) { fl_table.getAnParent().window.IPC().send("getFuncCalleeInfo"); fl_table.getAnParent().window.IPC().send(0); fl_table.getAnParent().window.IPC().send(type); fl_table.getAnParent().window.IPC().send(rows); fl_table.getAnParent().window.IPC().send(groupId); return (Object[]) fl_table.getAnParent().window.IPC().recvObject(); } } protected Object[] getFuncCallerInfo(final int type, final int[] rows, final int groupId) { synchronized (IPC.lock) { fl_table.getAnParent().window.IPC().send("getFuncCallerInfo"); fl_table.getAnParent().window.IPC().send(0); fl_table.getAnParent().window.IPC().send(type); fl_table.getAnParent().window.IPC().send(rows); fl_table.getAnParent().window.IPC().send(groupId); return (Object[]) fl_table.getAnParent().window.IPC().recvObject(); } } protected long[] getFuncId(final int type, final int begin, final int length) { synchronized (IPC.lock) { fl_table.getAnParent().window.IPC().send("getFuncId"); fl_table.getAnParent().window.IPC().send(0); fl_table.getAnParent().window.IPC().send(type); fl_table.getAnParent().window.IPC().send(begin); fl_table.getAnParent().window.IPC().send(length); return (long[]) fl_table.getAnParent().window.IPC().recvObject(); } } public int mapRow(int newRow) { return newRowToOldRow.get(newRow) == null ? -1 : newRowToOldRow.get(newRow); } // Process the raw data from mixed Primary/Object to pure Object array. // Creates and updates MaximumValues. public Object[][] localProcessData(final Object[] raw_data) { // raw_data has one vector for each column of metric values. // In addition, it has a vector of dbe row identifiers (HistItem->obj->id) int i; if (raw_data == null) { return null; } final int nc = raw_data.length - 1; // number of metric columns if (nc < 0) { return null; } final Object[][] data = new Object[nc][]; for (i = 0; i < nc; i++) { if (raw_data[i] instanceof double[]) { data[i] = AnDouble.toArray((double[]) raw_data[i]); } else if (raw_data[i] instanceof int[]) { data[i] = AnInteger.toArray((int[]) raw_data[i]); } else if (raw_data[i] instanceof long[]) { if ((((long[]) raw_data[i]).length == 0) || !AnAddress.isAddress(((long[]) raw_data[i])[0])) { data[i] = AnLong.toArray((long[]) raw_data[i]); } else { data[i] = AnAddress.toArray((long[]) raw_data[i]); } } else { data[i] = (Object[]) raw_data[i]; } } return data; } protected void releaseMap(HashMap map, int count) { Set keys = map.keySet(); int i = 0; for (Object key : keys) { map.put(key, null); i++; if (i >= count) { break; } } } protected void renderSrc( final String[] hdrContent, final Object[][] table_data, final int[] src_type, final long sel_src, final int view_mode) { tableData = table_data; srcTypeData = src_type; if (hdrContent.length <= 0) { return; } // set src type for source view if (hdrContent[0].startsWith("Source File")) { int dotPos = hdrContent[0].lastIndexOf('.'); if (dotPos != -1) { srcType = hdrContent[0].substring(dotPos + 1); if (srcType.matches("[0-9]*\\)?")) { int dotPos2 = hdrContent[0].lastIndexOf('.', dotPos - 1); if (dotPos2 != -1) { srcType = hdrContent[0].substring(dotPos2 + 1, dotPos); } } srcType = srcType.replaceFirst("\\)", ""); srcType = srcType.replaceFirst("_[a-zA-Z0-9\\-]*", ""); int dummyPos = srcType.indexOf(" (not found"); if (dummyPos != -1) { srcType = srcType.substring(0, dummyPos); } } } // initialize or store new cached data for the selected object if (srcRenderedMap.size() >= maxSrcCachedNumber || old_viewmode != view_mode) { // clear data cache before it gets too large releaseMap(srcRenderedMap, maxSrcCachedNumber / 3); releaseMap(srcPaneCreatedMap, maxSrcCachedNumber / 3); releaseMap(functionRenderedMap, maxSrcCachedNumber / 3); releaseMap(functionIdMap, maxSrcCachedNumber / 3); releaseMap(functionIdToRowMap, maxSrcCachedNumber / 3); releaseMap(lineNoToRowMap, maxSrcCachedNumber / 3); releaseMap(newRowToOldRowMap, maxSrcCachedNumber / 3); releaseMap(callerInfoMap, maxSrcCachedNumber / 3); releaseMap(calleeInfoMap, maxSrcCachedNumber / 3); } if (old_viewmode != view_mode) { old_viewmode = view_mode; } srcRendered = srcRenderedMap.get(sel_src); functionRendered = functionRenderedMap.get(sel_src); functionCallerCalleeAdded = functionCallerCalleeAddedMap.get(sel_src); srcPaneCreated = srcPaneCreatedMap.get(sel_src); functionId = functionIdMap.get(sel_src); functionIdToRow = functionIdToRowMap.get(sel_src); lineNoToRow = lineNoToRowMap.get(sel_src); newRowToOldRow = newRowToOldRowMap.get(sel_src); callerInfo = callerInfoMap.get(sel_src); calleeInfo = calleeInfoMap.get(sel_src); boolean isRenew = false; if (srcRendered == null || lineNoToRow == null || newRowToOldRow == null || sel_src == 0) { isRenew = true; } if (srcRendered == null) { srcRendered = new HashMap<Integer, SrcTextMarker>(); } if (functionRendered == null) { functionRendered = new HashMap<Integer, String>(); } if (functionCallerCalleeAdded == null) { functionCallerCalleeAdded = new HashMap<Integer, Boolean>(); } if (functionId == null) { functionId = new ArrayList<Long>(); } if (functionIdToRow == null) { functionIdToRow = new HashMap<Long, Integer>(); } if (lineNoToRow == null) { lineNoToRow = new HashMap<Integer, Integer>(); } if (newRowToOldRow == null) { newRowToOldRow = new HashMap<Integer, Integer>(); } if (callerInfo == null) { callerInfo = new HashMap<Long, ArrayList<SelObjInfo>>(); } if (calleeInfo == null) { calleeInfo = new HashMap<Integer, ArrayList<SelObjInfo>>(); } if (isRenew) { srcRendered.clear(); lineNoToRow.clear(); newRowToOldRow.clear(); for (int i = 0; i < table_data[fl_table.getNameCol()].length; i++) { Object value = table_data[fl_table.getNameCol()][i]; int type = src_type[i] < 0 ? (-src_type[i]) : src_type[i]; if (value instanceof String && (type == AnTable.AT_SRC || type == AnTable.AT_SRC_ONLY)) { SrcTextMarker sm = new SrcTextMarker(i, ((String) value)); srcRendered.put(i, sm); newRowToOldRow.put(i, i); } } srcRenderedMap.put(sel_src, srcRendered); lineNoToRowMap.put(sel_src, lineNoToRow); newRowToOldRowMap.put(sel_src, newRowToOldRow); } if (srcPaneCreated == null || sel_src == 0) { if (srcPaneCreated == null) { srcPaneCreated = new HashMap<Integer, SrcTextPane>(); } srcPaneCreated.clear(); srcPaneCreatedMap.put(sel_src, srcPaneCreated); } // add function ids and caller callee info functionRendered.clear(); functionCallerCalleeAdded.clear(); functionId.clear(); functionIdToRow.clear(); callerInfo.clear(); calleeInfo.clear(); AnUtility.checkIPCOnWrongThread(false); long[] rawData = getFuncId(fl_table.getAnParent().type, 0, src_type.length); AnUtility.checkIPCOnWrongThread(true); long lastFuncId = 0; if (rawData != null) { for (int i = 0; i < rawData.length; i++) { long id = rawData[i]; if (id == 0) { int start = i; int end = i + 4; boolean found = false; for (int k = start; k < end && k < rawData.length; k++) { int type = src_type[k] < 0 ? (-src_type[k]) : src_type[k]; if (type == AnTable.AT_FUNC) { found = true; break; } } id = found ? 0 : lastFuncId; } functionId.add(id); int type = src_type[i] < 0 ? (-src_type[i]) : src_type[i]; if (type == AnTable.AT_FUNC) { functionIdToRow.put(rawData[i], i); lastFuncId = rawData[i]; } } } rowToFuncBaseRow = new ArrayList<Integer>(); int baseRow = 0; for (int i = 0; i < table_data[fl_table.getNameCol()].length; i++) { Object value = table_data[fl_table.getNameCol()][i]; int type = src_type[i] < 0 ? (-src_type[i]) : src_type[i]; if (type == AnTable.AT_FUNC) { functionRendered.put(i, (String) value); baseRow = i; } rowToFuncBaseRow.add(baseRow); } functionRenderedMap.put(sel_src, functionRendered); functionCallerCalleeAddedMap.put(sel_src, functionCallerCalleeAdded); functionIdMap.put(sel_src, functionId); functionIdToRowMap.put(sel_src, functionIdToRow); callerInfoMap.put(sel_src, callerInfo); calleeInfoMap.put(sel_src, calleeInfo); tryAddNewObj(); } public void tryAddNewObj() { // add new obj to history if it's different from current if (fl_table.getNavigationHistoryPool().getHistory().enabled && (fl_table.getType() == AnDisplay.DSP_Source || fl_table.getType() == AnDisplay.DSP_SourceV2)) { int row = fl_table.getSelectedRow(); SrcTextMarker sm = srcRendered.get(mapRow(row)); if (sm != null) { int lineNo = sm.lineNo; long fun_id = -1; if (functionId != null && row >= 0 && row < functionId.size()) { fun_id = functionId.get(row); } if (fun_id == 0) { fun_id = fl_table.getAnParent().window.getSelectedObject().getSelObjV2("FUNCTION"); } SelObjInfo cur_so = fl_table.getNavigationHistoryPool().getHistory().getCurrent(); if (cur_so == null || cur_so.id != fun_id || cur_so.lineno != lineNo) { SelObjInfo new_so = new SelObjInfo(fun_id, lineNo, ""); fl_table.getNavigationHistoryPool().getHistory().goToNew(new_so); } else { fl_table.getNavigationHistoryPool().getHistory().newAdded = false; } } } } public void addFunctionByRow(int row) { if (row < 0 || row >= srcTypeData.length) { return; } int type = srcTypeData[row] < 0 ? (-srcTypeData[row]) : srcTypeData[row]; if (type != AnTable.AT_FUNC) { return; } int[] funcIds = new int[1]; funcIds[0] = row; String functionName = (tableData == null) ? null : (String) tableData[fl_table.getNameCol()][row]; functionCallerCalleeAdded.put(row, true); AnUtility.checkIPCOnWrongThread(false); Object[] calleeData = getFuncCalleeInfo(fl_table.getType(), funcIds, fl_table.getGroupId()); Object[] callerData = getFuncCallerInfo(fl_table.getType(), funcIds, fl_table.getGroupId()); AnUtility.checkIPCOnWrongThread(true); if (calleeData != null && callerData != null && tableData != null && calleeData.length > 0 && callerData.length > 0) { addFunction(row, functionName, (Object[]) calleeData[0], (Object[]) callerData[0]); } } public void addFunction(int row, String function, Object[] calleeData, Object[] callerData) { if (calleeData == null) { return; } String[] names = (String[]) calleeData[calleeData.length - 1]; Object[][] return_data = localProcessData(calleeData); if (return_data.length != 2) { return; // error happens here } for (int i = 0; i < return_data[0].length; i++) { Integer callsite = ((AnInteger) return_data[0][i]).toInteger(); if (callsite == null) { continue; } Long calleeId = ((AnLong) return_data[1][i]).toLong(); String funcName = names[i]; SelObjInfo fi = new SelObjInfo(calleeId, -1, funcName); ArrayList<SelObjInfo> callees = calleeInfo.get(callsite); if (callees == null) { callees = new ArrayList<SelObjInfo>(); callees.add(fi); calleeInfo.put(callsite, callees); if (fl_table.getType() == AnDisplay.DSP_Source || fl_table.getType() == AnDisplay.DSP_SourceV2) { SrcTextMarker sm = srcRendered.get(mapRow(callsite)); if (sm != null) { sm.isCallSite = true; } } } else { callees.add(fi); } } if (callerData == null) { return; } names = (String[]) callerData[callerData.length - 1]; return_data = localProcessData(callerData); if (return_data.length != 2) { return; // error happens here } if (functionId == null || row < 0 || row >= functionId.size()) { return; } Long funcId = functionId.get(row); for (int i = 0; i < return_data[0].length; i++) { Long callerId = ((AnLong) return_data[0][i]).toLong(); Integer lineNo = ((AnInteger) return_data[1][i]).toInteger(); if (callerId == null) { continue; } String funcName = names[i]; SelObjInfo fi = new SelObjInfo(callerId, lineNo, funcName); ArrayList<SelObjInfo> callers = callerInfo.get(funcId); if (callers == null) { callers = new ArrayList<SelObjInfo>(); callers.add(fi); callerInfo.put(funcId, callers); } else { callers.add(fi); } } } protected String getFunctionWhenCompare(int row) { int funcRow; if (rowToFuncBaseRow == null) { funcRow = -1; } else if (rowToFuncBaseRow.get(row) == null) { funcRow = -1; } else { funcRow = rowToFuncBaseRow.get(row); } return functionRendered.get(funcRow); } protected int getFunctionBaseRowWhenCompare(int row) { if (rowToFuncBaseRow == null) { return 0; } try { if (rowToFuncBaseRow.get(row) == null) { // return 0; } return rowToFuncBaseRow.get(row); } catch (ArrayIndexOutOfBoundsException e) { // This can be a bug or a race condition return 0; } } public String getFunction(int row) { if (fl_table .getAnParent() .window .getSettings() .getCompareModeSetting() .comparingExperiments()) { return getFunctionWhenCompare(row); } if (functionId == null || row < 0 || row >= functionId.size()) { return null; } int funcRow = -1; Long id = functionId.get(row); if (id != null) { Integer funcR = functionIdToRow.get(id); if (funcR != null) { funcRow = funcR.intValue(); } } return functionRendered.get(funcRow); } public int getFunctionBaseRow(int row) { if (fl_table .getAnParent() .window .getSettings() .getCompareModeSetting() .comparingExperiments()) { return getFunctionBaseRowWhenCompare(row); } if (functionId == null || row < 0 || row >= functionId.size()) { return 0; } int funcRow = 0; Long id = functionId.get(row); if (id != null) { Integer funcR = functionIdToRow.get(id); if (funcR != null) { funcRow = funcR.intValue(); } } return funcRow; } public int getNextCallsite(int row) { int callsite = -1; if (calleeInfo == null) { return callsite; } for (int i = 0; i < calleeInfo.size(); i++) { if (calleeInfo.get(row + i) != null) { callsite = row + i; break; } } return callsite; } public int getRowByLineNo(int lineNo) { Integer result = lineNoToRow.get(lineNo); int ret = -1; if (result != null) { ret = result.intValue(); } return ret; } public SrcTextPane getSrcTextPane(final String content, final JComponent cmp, final int row) { if (functionCallerCalleeAdded.get(getFunctionBaseRow(row)) == null) { addFunctionByRow(getFunctionBaseRow(row)); } int lineBegin = content.indexOf('.'); int lineNo = -1; if (lineBegin != -1) { lineNo = Integer.parseInt(content.substring(0, lineBegin).trim()); } Integer oldRowObj = lineNoToRow == null ? null : lineNoToRow.get( lineNo); // lineNoToRow is the one to one mapping between line number and the // index in srcRendered & srcPaneCreated int oldRow = oldRowObj == null ? 0 : oldRowObj; SrcTextMarker sm = srcRendered.get(oldRow); SrcTextPane st = srcPaneCreated.get(oldRow); boolean oldIsCallSite = false; if (oldRow != row) { newRowToOldRow.put(row, oldRow); if (calleeInfo != null && calleeInfo.get(row) == null && sm != null) { oldIsCallSite = sm.isCallSite; sm.isCallSite = false; } } if (st == null || !st.getText() .equalsIgnoreCase(content)) { // only create JTextPanel when it needs to be shown st = new SrcTextPane(content, cmp, sm); srcPaneCreated.put(oldRow, st); } else { if (oldRow != row && sm != null && oldIsCallSite && !sm.isCallSite) { st.unSetCallSiteStyle(); } } return st; } // A JTextPane for src/dis table cell protected final class SrcTextPane extends JTextPane { private String text; private SrcTextMarker textMarker = null; private UnderlineHighlighter highlighter = new UnderlineHighlighter(Color.black); private Highlighter.HighlightPainter painter = highlighter.new UnderlineHighlightPainter(Color.black); public SrcTextPane(final String content, final JComponent cmp, final SrcTextMarker tm) { text = content; textMarker = tm; setFont(cmp.getFont()); setBorder(AnVariable.labelBorder); setForeground(cmp.getForeground()); setBackground(cmp.getBackground()); setHighlighter(highlighter); Style style1 = addStyle("keyword", null); StyleConstants.setForeground(style1, AnVariable.KEYWORD_COLOR); Style style2 = addStyle("comment", null); StyleConstants.setForeground(style2, AnVariable.COMMENT_COLOR); Style style3 = addStyle("directive", null); StyleConstants.setForeground(style3, AnVariable.DIRECTIVE_COLOR); Style style4 = addStyle("string", null); StyleConstants.setForeground(style4, AnVariable.STRING_COLOR); Style style5 = addStyle("lineno", null); StyleConstants.setForeground(style5, AnVariable.LINENO_COLOR); Style style6 = addStyle("lineno_bold", null); StyleConstants.setForeground(style6, AnVariable.LINENO_COLOR_BOLD); StyleConstants.setBold(style6, true); StyledDocument doc = getStyledDocument(); try { doc.insertString(0, content, null); if (textMarker == null) { return; } for (int i = 0; i < textMarker.marker.size(); i++) { int from = textMarker.marker.get(i).from; int length = textMarker.marker.get(i).length; String style = textMarker.marker.get(i).style; doc.setCharacterAttributes(from, length, getStyle(style), true); } if (textMarker.isCallSite) { highlighter.addHighlight(textMarker.codeBegin, textMarker.codeEnd, painter); for (int i = 0; i < textMarker.marker.size(); i++) { int from = textMarker.marker.get(i).from; int length = textMarker.marker.get(i).length; String style = textMarker.marker.get(i).style; if (style.equals("lineno")) { doc.setCharacterAttributes(from, length, getStyle("lineno_bold"), true); break; } } } } catch (BadLocationException e) { // System.err.println("BadLocationException: " + e); // e.printStackTrace(); } final MouseMotionListener[] ls = getMouseMotionListeners(); for (final MouseMotionListener l : ls) { removeMouseMotionListener(l); } SrcTextPaneMouseAdapter ma = new SrcTextPaneMouseAdapter(cmp, this); SrcTextPaneMouseMotionAdapter mam = new SrcTextPaneMouseMotionAdapter(cmp, this); SrcTextPaneMouseWheelAdapter maw = new SrcTextPaneMouseWheelAdapter(cmp, this); SrcTextPaneKeyAdapter ka = new SrcTextPaneKeyAdapter(cmp); this.addMouseListener(ma); this.addMouseMotionListener(mam); this.addMouseWheelListener(maw); addKeyListener(ka); this.setDragEnabled(false); this.setFont(cmp.getFont()); this.setBorder(AnVariable.labelBorder); this.setForeground(cmp.getForeground()); this.setBackground(cmp.getBackground()); this.setOpaque(false); setEditable(false); } public void unSetCallSiteStyle() { StyledDocument doc = getStyledDocument(); if (textMarker == null) { return; } Highlighter.Highlight[] hilites = highlighter.getHighlights(); for (int i = 0; i < hilites.length; i++) { if (hilites[i].getPainter() instanceof UnderlineHighlighter.UnderlineHighlightPainter) { highlighter.removeHighlight(hilites[i]); } } for (int i = 0; i < textMarker.marker.size(); i++) { int from = textMarker.marker.get(i).from; int length = textMarker.marker.get(i).length; String style = textMarker.marker.get(i).style; if (style.equals("lineno_bold")) { doc.setCharacterAttributes(from, length, getStyle("lineno"), true); break; } } } public String getText() { return text; } } protected void propagateToTable( MouseEvent e, boolean changeSource, final Component parentComponent) { if (JTextPane.class.isAssignableFrom(e.getSource().getClass())) { int oldX = e.getX(); int oldY = e.getY(); Point p = e.getPoint(); SwingUtilities.convertPointToScreen(p, e.getComponent()); e.translatePoint(-oldX, -oldY); SwingUtilities.convertPointFromScreen(p, parentComponent); e.translatePoint(p.x, p.y); if (changeSource) { e.setSource(parentComponent); } parentComponent.dispatchEvent(e); } } protected final class SrcTextPaneKeyAdapter extends KeyAdapter { private Component parentComponent; public SrcTextPaneKeyAdapter(JComponent cmp) { parentComponent = cmp; } public void propagateToTable(KeyEvent e) { e.setSource(parentComponent); parentComponent.dispatchEvent(e); } public void keyTyped(KeyEvent e) { propagateToTable(e); } public void keyPressed(KeyEvent e) { propagateToTable(e); } public void keyReleased(KeyEvent e) { propagateToTable(e); } } protected final class SrcTextPaneMouseMotionAdapter extends MouseMotionAdapter { private Component parentComponent; private JTextPane pane; public SrcTextPaneMouseMotionAdapter(JComponent cmp, JTextPane p) { pane = p; parentComponent = cmp; } public void mouseMoved(MouseEvent e) {} } protected final class SrcTextPaneMouseWheelAdapter implements MouseWheelListener { private Component parentComponent; private JTextPane pane; public SrcTextPaneMouseWheelAdapter(JComponent cmp, JTextPane p) { pane = p; parentComponent = cmp; } public void mouseWheelMoved(MouseWheelEvent e) { propagateToTable(e, true, parentComponent); } } protected final class SrcTextPaneMouseAdapter extends MouseAdapter { private Component parentComponent; private JTextPane pane; public SrcTextPaneMouseAdapter(JComponent cmp, JTextPane p) { pane = p; parentComponent = cmp; } public void mouseClicked(MouseEvent e) { propagateToTable(e, true, parentComponent); } public void mousePressed(MouseEvent e) { caretLinePosition = pane.getCaretPosition(); } public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } // A marker of the style for JTextPane for src/dis table cell protected final class SrcTextMarker { protected final class Highlighter { public int from; public int length; public String style; public Highlighter(int f, int l, String s) { from = f; length = l; style = s; } } public ArrayList<Highlighter> marker = new ArrayList<Highlighter>(); private String text = ""; private String type = ""; private int curRow = -1; public int lineNo = -1; public int codeBegin = 0; public int codeEnd = 0; public boolean isCallSite = false; public SrcTextMarker(int row, final String content) { curRow = row; if (srcType.equalsIgnoreCase("f") || srcType.equalsIgnoreCase("for")) { type = "fortranfixed"; } else if (srcType.equalsIgnoreCase("f90") || srcType.equalsIgnoreCase("f95")) { type = "fortranfree"; } else if (srcType.equalsIgnoreCase("java")) { type = "java"; } else if (srcType.equalsIgnoreCase("cpp") || srcType.equalsIgnoreCase("cc") || srcType.equalsIgnoreCase("cxx") || srcType.equalsIgnoreCase("hpp") || srcType.equalsIgnoreCase("hh") || srcType.equalsIgnoreCase("hxx")) { type = "cpp"; } else if (srcType.equalsIgnoreCase("c") || srcType.equalsIgnoreCase("h") || srcType.equalsIgnoreCase("inc")) { type = "c"; } text = content; renderCode(); } public void renderDirective(int startPos, int endPos) { if (endPos <= startPos) { return; } int directiveEnd = endPos; int isSpace = 0; boolean nonSpaceSeen = false; for (int i = startPos; i < endPos; i++) { if (text.charAt(i) != ' ' && text.charAt(i) != '\t' && text.charAt(i) != '#') { nonSpaceSeen = true; } if (nonSpaceSeen && (text.charAt(i) == ' ' || text.charAt(i) == '\t' || text.charAt(i) == '"' || text.charAt(i) == '<')) { directiveEnd = i; isSpace = (text.charAt(i) == ' ' || text.charAt(i) == '\t') ? 1 : 0; break; } } marker.add(new Highlighter(startPos, directiveEnd - startPos, "directive")); if (text.substring(startPos, directiveEnd).equals("#include")) { marker.add(new Highlighter(directiveEnd + isSpace, endPos, "string")); } } public void renderComment(int startPos, int endPos) { if (endPos <= startPos) { return; } marker.add(new Highlighter(startPos, endPos - startPos, "comment")); } public void renderQuote(int startPos, int endPos) { if (endPos <= startPos) { return; } marker.add(new Highlighter(startPos, endPos - startPos, "string")); } // render code that is not multiline comment in /**/ public void renderNonMLComment(int startPos, int endPos) { if (endPos <= startPos) { return; } boolean seenQuote = false; int start = -1; int end = 0; for (int i = startPos; i < endPos; i++) { if (text.charAt(i) == '"') { boolean isQuote = true; int k = i - 1; int slashNum = 0; while (k >= 0 && text.charAt(k) == '\\') { slashNum++; k--; } if (slashNum % 2 != 0) { isQuote = false; } if (isQuote) { if (seenQuote) { end = i + 1; renderQuote(start, end); } else { start = i; renderNonQuoteComment(end, start); } seenQuote = !seenQuote; } } } if (seenQuote) { renderQuote(start, endPos); } else { renderNonQuoteComment(end, endPos); } } // render non comment conde that is not inside "" public void renderNonQuoteComment(int startPos, int endPos) { if (endPos <= startPos) { return; } int startDirective = startPos; boolean foundDirective = false; if (type.equals("c") || type.equals("cpp")) { while (startDirective < endPos) { if (text.charAt(startDirective) == '#') { foundDirective = true; break; } startDirective++; } } if (foundDirective && text.charAt(startDirective) == '#') { renderDirective(startDirective, endPos); } else { String code = text.substring(startPos, endPos); String[] words = code.split(SPLIT_PATTERN); int curPos = startPos; for (int i = 0; i < words.length; i++) { if (words[i].length() == 0) { } else { if (type.equals("c")) { if (cKeywordMap.get(words[i]) != null) { marker.add(new Highlighter(curPos, words[i].length(), "keyword")); } } else if (type.equals("cpp")) { if (cppKeywordMap.get(words[i]) != null) { marker.add(new Highlighter(curPos, words[i].length(), "keyword")); } } else if (type.equals("java")) { if (javaKeywordMap.get(words[i]) != null) { marker.add(new Highlighter(curPos, words[i].length(), "keyword")); } } else if (type.equals("fortranfixed") || type.equals("fortranfree")) { if (fortran95KeywordMap.get(words[i].toLowerCase()) != null) { marker.add(new Highlighter(curPos, words[i].length(), "keyword")); } } } if (i < words.length - 1) { curPos += words[i].length() + 1; } } } } // render code before which /* is not seen public void renderCode(int start, int end) { if (start >= end) { return; } codeBegin = start; codeEnd = end; while (codeBegin != end) { if (text.charAt(codeBegin) != ' ') { break; } codeBegin++; } if (type.equals("fortranfixed")) { if ((text.charAt(start) == 'c' || text.charAt(start) == 'C' || text.charAt(start) == '*') && start + 1 < end && text.charAt(start + 1) != '$') { renderComment(start, end); return; } } boolean seenQuote = false; boolean seenCommentStart = false; int startPos = -1; int endPos = start; int tail = 1; if (type.equals("fortranfixed") || type.equals("fortranfree")) { tail = 0; } for (int i = start; i < end - tail; i++) { if (text.charAt(i) == '"') { boolean isQuote = true; int k = i - 1; int slashNum = 0; while (k >= 0 && text.charAt(k) == '\\') { slashNum++; k--; } if (slashNum % 2 != 0) { isQuote = false; } if (isQuote && !seenCommentStart) { seenQuote = !seenQuote; } } if (type.equals("fortranfixed") || type.equals("fortranfree")) { if (text.charAt(i) == '!' && i + 1 < end && text.charAt(i + 1) != '$') { if (!seenQuote && !seenCommentStart) { renderNonMLComment(endPos, i); renderComment(i, end); return; } } } else if (type.equals("c") || type.equals("cpp") || type.equals("java")) { if (text.charAt(i) == '/' && text.charAt(i + 1) == '*') { if (!seenQuote && !seenCommentStart) { seenCommentStart = true; startPos = i; renderNonMLComment(endPos, startPos); i++; continue; } } if (text.charAt(i) == '*' && text.charAt(i + 1) == '/' && (i == 0 || text.charAt(i - 1) != '/')) { if (!seenQuote && seenCommentStart) { seenCommentStart = false; endPos = i + 2; renderComment(startPos, endPos); i++; continue; } } if (text.charAt(i) == '/' && text.charAt(i + 1) == '/') { if (!seenQuote && !seenCommentStart) { renderNonMLComment(endPos, i); renderComment(i, end); return; } } } } if (seenCommentStart) { renderComment(startPos, end); srcInComment = true; } else { renderNonMLComment(endPos, end); } } public void renderCode() { int lineBegin = text.indexOf('.'); if (lineBegin == -1) { lineBegin = 0; } else { lineNo = Integer.parseInt(text.substring(0, lineBegin).trim()); lineNoToRow.put(lineNo, curRow); lineBegin += 2; } marker.add(new Highlighter(0, lineBegin, "lineno")); if (type.equals("fortranfixed") || type.equals("fortranfree")) { // assume fortran has no comment inside /**/ renderCode(lineBegin, text.length()); return; } // detect comments inside /**/ or after // if (srcInComment) { String[] nonQuote = text.split("\""); int commentEndPos = 0; boolean foundEnd = false; for (int i = 0; i < nonQuote.length; i += 2) { // only look at "*/" outside pairs of "\"" if (i > 0) { commentEndPos += nonQuote[i - 2].length() + nonQuote[i - 1].length() + 2; } int idx = nonQuote[i].indexOf("*/"); if (idx != -1) { commentEndPos += idx + 2; foundEnd = true; break; } } if (foundEnd) { renderComment(lineBegin, commentEndPos); srcInComment = false; renderCode(commentEndPos, text.length()); } else { renderComment(lineBegin, text.length()); } return; } renderCode(lineBegin, text.length()); } } protected class UnderlineHighlighter extends DefaultHighlighter { // Painter used for this highlighter protected Highlighter.HighlightPainter painter; public UnderlineHighlighter(Color c) { painter = new UnderlineHighlightPainter(c); } // Convenience method to add a highlight with // the default painter. public Object addHighlight(int p0, int p1) throws BadLocationException { return addHighlight(p0, p1, painter); } public void setDrawsLayeredHighlights(boolean newValue) { // Illegal if false - we only support layered highlights if (newValue == false) { throw new IllegalArgumentException("UnderlineHighlighter only draws layered highlights"); } super.setDrawsLayeredHighlights(true); } // Painter for underlined highlights public class UnderlineHighlightPainter extends LayeredHighlighter.LayerPainter { public UnderlineHighlightPainter(Color c) { color = c; } public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) { // Do nothing: this method will never be called } public Shape paintLayer( Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c, View view) { g.setColor(color == null ? c.getSelectionColor() : color); Rectangle alloc = null; if (offs0 == view.getStartOffset() && offs1 == view.getEndOffset()) { if (bounds instanceof Rectangle) { alloc = (Rectangle) bounds; } else { alloc = bounds.getBounds(); } } else { try { Shape shape = view.modelToView( offs0, Position.Bias.Forward, offs1, Position.Bias.Backward, bounds); alloc = (shape instanceof Rectangle) ? (Rectangle) shape : shape.getBounds(); } catch (BadLocationException e) { // System.err.println("BadLocationException: " + e); // e.printStackTrace(); return null; } } FontMetrics fm = c.getFontMetrics(c.getFont()); int baseline = alloc.y + alloc.height - fm.getDescent(); int lowShift = 1; g.drawLine(alloc.x, baseline + lowShift, alloc.x + alloc.width, baseline + lowShift); return alloc; } protected Color color; // The color for the underline } } protected void goToCallee(int row, MouseEvent e) { if (calleeInfo == null || calleeInfo.get(row) == null) { return; } SrcTextPane dt = srcPaneCreated.get(mapRow(row)); if (dt != null) { if (caretLinePosition >= dt.textMarker.codeBegin && caretLinePosition < dt.textMarker.codeEnd) { ArrayList<SelObjInfo> callees = calleeInfo.get(row); if (callees.size() > 1) { // pop up context menu JPopupMenu popup = fl_table.getMenuListener().initPopup(e); if (popup != null) { popup.show(e.getComponent(), e.getX(), e.getY()); boolean pressDown = false; for (int i = 0; i < 3; i++) { // XXXX ugly assumption that the "show callee source" is the 3rd item if (!popup.getComponent(i).isEnabled()) { continue; } popup.dispatchEvent( new KeyEvent(popup, KeyEvent.KEY_PRESSED, 0, 0, KeyEvent.VK_DOWN, '\0')); pressDown = true; } if (pressDown) { popup.dispatchEvent( new KeyEvent(popup, KeyEvent.KEY_PRESSED, 0, 0, KeyEvent.VK_RIGHT, '\0')); } } } else if (callees.size() == 1) { long funcId = callees.get(0).id; Integer targetRow = functionIdToRow.get(funcId); Object progressBarHandle = fl_table .getAnParent() .window .getSystemProgressPanel() .progressBarStart(AnLocale.getString("Callee")); // add new obj to history if it's different from current fl_table.getNavigationHistoryPool().getHistory().goToSrcNew(row); // change selected object fl_table.getAnParent().window.getSelectedObject().setSelObjV2(funcId); if (targetRow != null) { int targetFuncRow = (targetRow - 1 >= 0) ? (targetRow - 1) : 0; fl_table.getNavigationHistoryPool().getHistory().enabled = false; fl_table.setSelectedRow(targetFuncRow); fl_table.getNavigationHistoryPool().getHistory().enabled = true; fl_table.fireAnEvent(new AnEvent(fl_table, AnEvent.EVT_SELECT, targetFuncRow, null)); tryAddNewObj(); fl_table.getAnParent().updateToolBar(); } else { fl_table.getAnParent().setComputed(false); fl_table.getAnParent().computeOnAWorkerThread(); } fl_table.updateAnTable(AnTable.STR_ACTION_SHOW_CALLEE_SOURCE); fl_table .getAnParent() .window .getSystemProgressPanel() .progressBarStop(progressBarHandle); } } } } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/SourceView.java����������������������������������������������������0000644�0001750�0001750�00000011066�14517772113�016677� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.settings.AnSettingChangeEvent; public final class SourceView extends AnCompDisp implements AnChangeListener { public SourceView() { super(AnWindow.getInstance(), AnDisplay.DSP_Source, AnVariable.HELP_TabsSource); setAccessibility(AnLocale.getString("Source")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("SourceView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: setComputed(false); clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: addExperiment(); if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: if (selected) { filterChanged(); } setComputed(false); if (selected) { computeOnAWorkerThread(); } break; case SOURCE_FINDING_CHANGED: setComputed(false); if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SETTING_CHANGING: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.SRC_DIS || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.SEARCH_PATH || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.PATH_MAP || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { setComputed(false); if (oneDispPanel != null) { oneDispPanel.forceCompute = true; // ?????? } if (selected) { computeOnAWorkerThread(); } } break; case SELECTED_OBJECT_CHANGED: if (selected) { computeOnAWorkerThread(); } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void setComputed(boolean set) { super.setComputed(set); AnWindow.getInstance().getCalledByCallsSourceView().setComputed(set); } @Override protected void setAvailable(boolean set) { super.setAvailable(set); AnWindow.getInstance().getCalledByCallsSourceView().setAvailable(set); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/IPC.java�����������������������������������������������������������0000644�0001750�0001750�00000013055�14517772113�015217� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.ipc.IPCCancelledException; import org.gprofng.mpmt.ipc.IPCContext; import org.gprofng.mpmt.ipc.IPCErrorReader; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCReader; import org.gprofng.mpmt.ipc.IPCResult; import java.io.InputStream; import java.io.OutputStream; public final class IPC { public static final Object lock; public static String host; public static int port; protected InputStream processOutput, processError; protected OutputStream processInput; private IPCProcess thisProcess; private Process delegate; private Analyzer parent_Analyzer; private String cmd; // gp-display-text path + option private IPCHandle ipcHandle = null; private IPCResult ipcResult = null; private IPCReader ipcReader; private IPCErrorReader ipcErrorReader; static { lock = new Object(); } IPC(Analyzer parent) { parent_Analyzer = parent; } public InputStream getInputStream() { return processOutput; } public OutputStream getOutputStream() { return processInput; } public InputStream getErrorStream() { return processError; } public IPCReader getIPCReader() { return ipcReader; } public IPCErrorReader getIPCErrorReader() { return ipcErrorReader; } /** * @return trimmed gp-display-text command path plus IPC argument */ public String getCmd() { return cmd.trim(); } public void init(final String cmd, boolean run) throws Exception { this.cmd = cmd; final Runtime rt = Runtime.getRuntime(); delegate = rt.exec(cmd); processOutput = delegate.getInputStream(); processInput = delegate.getOutputStream(); processError = delegate.getErrorStream(); thisProcess = new IPCProcess(parent_Analyzer, delegate, processInput, processOutput, processError); if (thisProcess.monitor != null) { thisProcess.monitor.interrupt(); thisProcess.monitor = null; } thisProcess.setExitListener(); // NM Temporary solution for remote analyzer: pass flag "run" to IPCReader ipcReader = new IPCReader(this, run); ipcErrorReader = new IPCErrorReader(this, true); } public void destroyIPCProc() { if (thisProcess != null) { thisProcess.removeExitListener(); parent_Analyzer.IPC_started = false; thisProcess.destroy(); if (ipcReader != null) { ipcReader.stopThread(); } if (ipcErrorReader != null) { ipcErrorReader.stopThread(); } } } public int recvInt() { sendIPCRequest(); if (ipcResult.getCC() != IPCResult.CC.SUCCESS) { System.out.append("\nrecvInt cancelled..."); throw new IPCCancelledException(); } return ipcResult.getInt(); } public String recvString() { sendIPCRequest(); if (ipcResult.getCC() != IPCResult.CC.SUCCESS) { System.out.append("\nrecvString cancelled..."); throw new IPCCancelledException(); } return ipcResult.getString(); } public long recvLong() { sendIPCRequest(); if (ipcResult.getCC() != IPCResult.CC.SUCCESS) { System.out.append("\nrecvLong cancelled..."); throw new IPCCancelledException(); } return ipcResult.getLong(); } public boolean recvBoolean() { sendIPCRequest(); if (ipcResult.getCC() != IPCResult.CC.SUCCESS) { System.out.append("\nrecvBoolean cancelled..."); throw new IPCCancelledException(); } return ipcResult.getBoolean(); } public Object recvObject() { sendIPCRequest(); if (ipcResult.getCC() != IPCResult.CC.SUCCESS) { System.out.append("\nrecvObject cancelled..."); throw new IPCCancelledException(); } return ipcResult.getObject(); } public void recvVoid() { sendIPCRequest(); if (ipcResult.getCC() != IPCResult.CC.SUCCESS) { System.out.append("\nrecvVoid cancelled..."); throw new IPCCancelledException(); } ipcResult.getVoid(); // <=== FIXUP: is this needed???? } private IPCHandle getIPCHandle() { if (ipcHandle == null) { ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE, IPCContext.getCurrentContext()); } return ipcHandle; } private void sendIPCRequest() { if (ipcHandle != null) { ipcResult = ipcHandle.sendRequest(); } else { System.err.println("********************ERROR: IPC: ipcRequest==null"); assert false; } ipcHandle = null; } public void send(final int i) { getIPCHandle().append(i); } public void send(final long l) { getIPCHandle().append(l); } public void send(final boolean b) { getIPCHandle().append(b); } public void send(final String s) { getIPCHandle().append(s); } public void send(final Object object) { getIPCHandle().append(object); } public static final class AnIPCException extends RuntimeException { public AnIPCException() { super(); } public AnIPCException(final Throwable thr) { super(thr); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnObject.java������������������������������������������������������0000644�0001750�0001750�00000013166�14517772113�016274� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; // Analyzer object public abstract class AnObject { public static final String quote_space = " "; public static final String zero_decimal = new DecimalFormat("0. ").format(0.); public static final String zero_sdecimal = new DecimalFormat("+0. ").format(0.); public static final String zero_percent = new DecimalFormat("0. ").format(0.); public static final DecimalFormat format_decimal = new DecimalFormat("0.000"); public static final DecimalFormat format_sdecimal = new DecimalFormat("+0.000;-0.000"); public static final DecimalFormat format_percent = new DecimalFormat("0.00"); public static final DecimalFormat format_group_decimal; public static final DecimalFormat format_group_sdecimal; public static final DecimalFormat format_group_integer; public static final DecimalFormat format_group_sinteger; static { DecimalFormatSymbols df_sym; df_sym = new DecimalFormatSymbols(); df_sym.setGroupingSeparator('@'); format_group_decimal = new DecimalFormat("#,##0.000", df_sym); format_group_sdecimal = new DecimalFormat("#,##0.000", df_sym); format_group_integer = new DecimalFormat("#,##0", df_sym); format_group_sinteger = new DecimalFormat("#,##0", df_sym); format_group_sinteger.setPositivePrefix("+"); format_group_sdecimal.setPositivePrefix("+"); } protected boolean showZero = true; protected boolean sign = false; protected String xtimes = ""; protected String get_zero_decimal() { // if (sign) { // Why do we want +0. ?? // return zero_sdecimal; // } return zero_decimal; } // Analyzer double value public double doubleValue() { return 0.0; } // Analyzer printing format public abstract String toString(); // Analyzer formatted printing format public String toFormString() { return toString(); } // Time printing public String toTime(final double clock) { if (xtimes.compareTo("") != 0) { // for ratio comparison, don't rescale by clock return toString(); } else { // is this code path ever reached? what is it for? return ""; } } // Time formatted printing format public String toFormTime(final double clock) { return toTime(clock); } // Percent printing public String toPercent(final double total) { return ""; } // Percent printing public final String percentToString(final double val) { if (val == 0.0) { return (showZero) ? zero_percent : quote_space; } return format_percent.format(val); } // Percent printing with quote public final String toPercentQuote(final double percent) { String s = toString(); if (percent == 0.0) { if (showZero) { return String.format("%s (%6s%%)", toString(), zero_percent); } return toQuoteSpace(); } return String.format("%s (%6.2f%%)", toString(), percent); } // Don't show percentage public final String toQuoteSpace() { String s = toString(); return s + " "; } // To show or not to show zero public final void showZero(boolean show) { showZero = show; } public final void showSign(boolean show) { sign = show; } public final void showXtimes(boolean show) { if (show) { xtimes = "x"; } else { xtimes = ""; } } /* * Updates Total and Max values. * Note: Total is not used, so only Maximum is updated. */ public static Object[][] updateMaxValues(final Object[][] data, Object[][] maxValues) { if (maxValues == null) { maxValues = new Object[2][data.length]; } if (maxValues[1].length != data.length) { maxValues = new Object[2][data.length]; } String strTotal = "<Total>"; String strLocalizedTotal = AnLocale.getString("<Total>"); int totalColumn = -1; for (int i = 0; i < data.length; i++) { int maxlen = 0; Object obj = maxValues[1][i]; if (obj != null) { maxlen = obj.toString().length(); } Object[] d = data[i]; for (int j = 0; j < d.length; j++) { int len = d[j].toString().length(); if (maxlen < len) { maxlen = len; obj = d[j]; } } maxValues[1][i] = obj; if (data[i] instanceof String[]) { String snames[] = (String[]) data[i]; for (int j = 0; j < snames.length; j++) { if ((snames[j].equals(strLocalizedTotal)) || (snames[j].equals(strTotal))) { totalColumn = j; break; } } } } if ((totalColumn != -1)) { for (int i = 0; i < data.length; i++) { Object[] d = data[i]; maxValues[0][i] = d[totalColumn]; } } // make sure there are no null elements in maxValues for (int i = 0; i < data.length; i++) { if (maxValues[0][i] == null) { maxValues[0][i] = new AnDouble(0.0); } if (maxValues[1][i] == null) { maxValues[1][i] = ""; } } return maxValues; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ViewDisplayPanel.java����������������������������������������������0000644�0001750�0001750�00000006014�14517772113�020021� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.settings.ViewsSetting; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.KeyStroke; public class ViewDisplayPanel extends JPanel { private ViewsSetting.View currentView = null; public ViewDisplayPanel() { setOpaque(false); setBorder(null); setLayout(new BorderLayout()); // Focus final KeyStroke viewsFocusShortCut = KeyboardShortcuts.viewsFocusShortCut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(viewsFocusShortCut, viewsFocusShortCut); getActionMap() .put( viewsFocusShortCut, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().getNavigationPanel().getViewsPanel().requestFocus(); } }); // Focus KeyStroke mainViewFocusShortcut = KeyboardShortcuts.mainViewFocusShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(mainViewFocusShortcut, mainViewFocusShortcut); getActionMap() .put( mainViewFocusShortcut, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { getCurrentViewDisplay().requestFocus(); } }); } public AnDisplay getCurrentViewDisplay() { AnDisplay ad = null; if (currentView != null) { ad = currentView.getAnDispTab().getTComp(); } return ad; } public String getCurrentViewName() { String ad = null; if (currentView != null) { ad = currentView.getAnDispTab().getTCmd(); } return ad; } public boolean viewComponent(String cmd) { if (cmd == null) { return false; } if (currentView != null && currentView.getAnDispTab().getTCmd().equals(cmd)) { return false; } ViewsSetting.View view = AnWindow.getInstance().getSettings().getViewsSetting().findView(cmd); if (view == null) { return false; } removeAll(); add(view.getAnDispTab().getTComp(), BorderLayout.CENTER); currentView = view; view.getAnDispTab() .getTComp() .repaint(); // Necessary, otherwise views don't paint correctly if changing views // rapitly.... return true; } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/mainview/����������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�015652� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/mainview/BorderPanel.form������������������������������������������0000644�0001750�0001750�00000003741�14517772113�020643� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Form> �������������������������������gprofng-gui-1.0/org/gprofng/mpmt/mainview/SubviewAreaPanel.java�������������������������������������0000644�0001750�0001750�00000016343�14517772113�021623� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.mainview; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.CalledByCallsDisp; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.mainview.MainViewPanel.SubviewArea; import org.gprofng.mpmt.util.gui.AnTabbedPane; import java.awt.Component; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JComponent; import javax.swing.KeyStroke; public class SubviewAreaPanel extends BorderPanel { private final SubviewArea subviewArea; private final AnTabbedPane tabbedPane; protected SubviewAreaPanel(SubviewArea subviewArea) { this.subviewArea = subviewArea; tabbedPane = new AnTabbedPane(); tabbedPane.setBorder(null); add(tabbedPane); setBackground(AnEnvironment.SUBVIEW_PANEL_BACKGROUND); // Focus keyboard shortcuts if (subviewArea == SubviewArea.SUBVIEW_AREA_1) { KeyStroke keyStroke = KeyboardShortcuts.subviewArea1FocusShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, keyStroke); getActionMap().put(keyStroke, new FocusDefaultAction()); } else if (subviewArea == SubviewArea.SUBVIEW_AREA_2) { // Special case caller/callee tables KeyStroke keyStroke = KeyboardShortcuts.subviewArea2CallerFocusShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, keyStroke); getActionMap().put(keyStroke, new FocusCallerAction()); keyStroke = KeyboardShortcuts.subviewArea2CalleeFocusShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, keyStroke); getActionMap().put(keyStroke, new FocusCalleeAction()); } else if (subviewArea == SubviewArea.SUBVIEW_AREA_3) { KeyStroke keyStroke = KeyboardShortcuts.subviewArea3FocusShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, keyStroke); getActionMap().put(keyStroke, new FocusDefaultAction()); } } static class FocusDefaultAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { SubviewAreaPanel subviewAreaPanel = (SubviewAreaPanel) e.getSource(); AnTabbedPane tabbedPane = subviewAreaPanel.getTabbedPane(); if (tabbedPane != null) { tabbedPane.requestFocus(); } } } static class FocusCallerAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { SubviewAreaPanel subviewAreaPanel = (SubviewAreaPanel) e.getSource(); AnTabbedPane tabbedPane = subviewAreaPanel.getTabbedPane(); if (tabbedPane != null && tabbedPane.getTabCount() > 0) { Subview subview = (Subview) tabbedPane.getComponentAt(0); Component component = subview.getComponent(); if (component instanceof CalledByCallsDisp) { CalledByCallsDisp calledByCallsDisp = (CalledByCallsDisp) component; if (calledByCallsDisp.getCallerTable().getSelectedRow() < 0) { calledByCallsDisp.getCallerTable().setSelectedRow(0); } calledByCallsDisp.getCallerTable().requestFocus(); } } } } static class FocusCalleeAction extends AbstractAction { @Override public void actionPerformed(ActionEvent e) { SubviewAreaPanel subviewAreaPanel = (SubviewAreaPanel) e.getSource(); AnTabbedPane tabbedPane = subviewAreaPanel.getTabbedPane(); if (tabbedPane != null && tabbedPane.getTabCount() > 0) { Subview subview = (Subview) tabbedPane.getComponentAt(0); Component component = subview.getComponent(); if (component instanceof CalledByCallsDisp) { CalledByCallsDisp calledByCallsDisp = (CalledByCallsDisp) component; if (calledByCallsDisp.getCalleeTable().getSelectedRow() < 0) { calledByCallsDisp.getCalleeTable().setSelectedRow(0); } calledByCallsDisp.getCalleeTable().requestFocus(); } } } } protected AnTabbedPane getTabbedPane() { return tabbedPane; } protected void addSubview(Subview subview) { getTabbedPane().addTab(subview.getDisplayName(), subview); } protected void setHidden(Subview subview, boolean hidden) { int index = getTabbedPane().indexOfComponent(subview); if (hidden && index >= 0) { getTabbedPane().remove(subview); } if (!hidden && index < 0) { addSubview(subview); } } protected void remove(Subview subview) { getTabbedPane().remove(subview); } protected void setSelected(Subview subview) { int index = getTabbedPane().indexOfComponent(subview); if (index >= 0) { getTabbedPane().setSelectedComponent(subview); } } protected boolean isSelected(Subview subview) { Subview selectedSubview = (Subview) getTabbedPane().getSelectedComponent(); return selectedSubview == subview; } protected int getTabCount() { return getTabbedPane().getTabCount(); } /** Dump contents of subviews. Used in unit tests. */ public String dumpSubviews() { StringBuilder buf = new StringBuilder(); buf.append("\n"); buf.append(subviewArea); buf.append("\n"); buf.append("\n"); Component selectedComponent = tabbedPane.getSelectedComponent(); for (Component outerComponent : tabbedPane.getComponents()) { if (outerComponent instanceof Subview) { buf.append(((Subview) outerComponent).getDisplayName()); buf.append("\n"); buf.append("\n"); if (outerComponent == selectedComponent) { Component innerComponent = ((Subview) outerComponent).getComponent(); if (innerComponent instanceof ExportSupport && ((ExportSupport) innerComponent) .getSupportedExportFormats() .contains(ExportSupport.ExportFormat.TEXT)) { buf.append( ((ExportSupport) innerComponent) .exportAsText(0, ExportSupport.ExportFormat.TEXT, null)); } else { buf.append(((Subview) outerComponent).exportAsText()); } } } } return buf.toString(); } /** Dump views structure. Used in unit tests. */ public String dumpSubviewsVisibility() { StringBuilder buf = new StringBuilder(); buf.append(subviewArea); buf.append("\n"); Component selectedComponent = tabbedPane.getSelectedComponent(); for (Component component : tabbedPane.getComponents()) { if (component instanceof Subview) { if (component == selectedComponent) { buf.append(" *"); } else { buf.append(" "); } buf.append(((Subview) component).dumpName()); } } return buf.toString(); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/mainview/MainViewPanel.form����������������������������������������0000644�0001750�0001750�00000003742�14517772113�021146� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-108"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Form> ������������������������������gprofng-gui-1.0/org/gprofng/mpmt/mainview/Subview.java����������������������������������������������0000644�0001750�0001750�00000012251�14517772113�020044� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.mainview; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.mainview.MainViewPanel.SubviewArea; import org.gprofng.mpmt.util.gui.AnJScrollPane; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.KeyStroke; public class Subview extends AnJScrollPane { private final String viewName; private final String displayName; private final SubviewArea subviewArea; private boolean readyToShow = true; private Component component; private final JPanel internalPanel; public Subview( String viewName, String displayName, final Component component, SubviewArea subviewArea) { this.viewName = viewName; this.displayName = displayName; this.subviewArea = subviewArea; setBackground(AnEnvironment.SUBVIEW_PANEL_BACKGROUND); setBorder(null); internalPanel = new JPanel(); internalPanel.setLayout(new BorderLayout()); internalPanel.setBackground(AnEnvironment.SUBVIEW_PANEL_BACKGROUND); setComponent(component); setViewportView(internalPanel); getMainViewPanel().addSubview(this); getVerticalScrollBar().setUnitIncrement(6); registerKeyboardAction( new SubviewHelpAction(), "help", KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); } public static final class SubviewHelpAction implements ActionListener { @Override public void actionPerformed(final ActionEvent event) { // Delegate help to current view. AnWindow.getInstance().getViews().getCurrentViewDisplay().showHelp(); } } public String exportAsText() { StringBuilder buf = new StringBuilder(); // buf.append(displayName); // buf.append("\n"); exportAsText(buf, this); return buf.toString(); } private void exportAsText(StringBuilder buf, Component component) { if (component instanceof JLabel) { buf.append("Label:" + ((JLabel) component).getText()); buf.append("\n"); } if (component instanceof JTextField) { buf.append("TextField:" + ((JTextField) component).getText()); buf.append("\n"); } if (component instanceof JTextArea) { buf.append("JTextArea:" + ((JTextArea) component).getText()); buf.append("\n"); } if (component instanceof JList) { JList list = (JList) component; for (int i = 0; i < list.getModel().getSize(); i++) { buf.append(list.getModel().getElementAt(i).toString()); buf.append("\n"); } } if (component instanceof Container) { Component[] components = ((Container) component).getComponents(); for (Component c : components) { exportAsText(buf, c); } } } public String getViewName() { return viewName; } public String getDisplayName() { return displayName; } public void setComponent(Component component) { internalPanel.removeAll(); if (component != null) { internalPanel.add(component, BorderLayout.CENTER); } this.component = component; } public void removeComponent() { remove(component); this.component = null; } public Component getComponent() { return component; } public SubviewArea getSubviewArea() { return subviewArea; } public void setHidden(boolean hidden) { getMainViewPanel().setHidden(subviewArea, this, hidden); } public void setSelected() { getMainViewPanel().setSelected(subviewArea, this); } public boolean isSelected() { return getMainViewPanel().isSelected(subviewArea, this); } private MainViewPanel getMainViewPanel() { return AnWindow.getInstance().getMainViewPanel(); } /** * @return the readyToShow */ public boolean isReadyToShow() { return readyToShow; } /** * @param readyToShow the readyToShow to set */ public void setReadyToShow(boolean readyToShow) { this.readyToShow = readyToShow; } public void showSubview(boolean show) { boolean toShow = isReadyToShow() && show; setHidden(!toShow); } /** Dump views structure. Used in unit tests. */ public String dumpName() { StringBuilder buf = new StringBuilder(); buf.append(getViewName()); buf.append("\n"); return buf.toString(); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/mainview/BorderPanel.java������������������������������������������0000644�0001750�0001750�00000003205�14517772113�020614� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.mainview; import org.gprofng.analyzer.AnEnvironment; import java.awt.BorderLayout; import javax.swing.BorderFactory; public class BorderPanel extends javax.swing.JPanel { public BorderPanel() { initComponents(); setBorder(BorderFactory.createLineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR, 1)); setBackground(AnEnvironment.TABBED_PANE_BACKGROUND_COLOR); setLayout(new BorderLayout()); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.BorderLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/mainview/Panel.java������������������������������������������������0000644�0001750�0001750�00000001721�14517772113�017457� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.mainview; import org.gprofng.analyzer.AnEnvironment; import java.awt.BorderLayout; import javax.swing.JPanel; public class Panel extends JPanel { public Panel() { setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); setBorder(null); setLayout(new BorderLayout()); } } �����������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/mainview/MainViewPanel.java����������������������������������������0000644�0001750�0001750�00000021774�14517772113�021131� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.mainview; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnSplitPaneFixedRightSize; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.swing.JPanel; import javax.swing.JSplitPane; // +----------+-------------------------------------------------+---------------+ // | N | M | S1 | // | | | | // | | | | // | | | | // | | D1 | // | | | | // | | | | // | | | | // | | +-D3------------+ // | | | S3 | // | | | | // | | | | // | | | | // | | | | // | | | | // | +-D2----------------------------------------------+ | // | | S2 | | // | | | | // +----------+-------------------------------------------------+---------------+ // // MainViewPanel manages the M+S1+S2+S3 area // public class MainViewPanel extends javax.swing.JPanel { public enum SubviewArea { SUBVIEW_AREA_1(0), SUBVIEW_AREA_2(1), SUBVIEW_AREA_3(2); private final int index; SubviewArea(int index) { this.index = index; } public int index() { return index; } }; // Areas private final BorderPanel mainviewArea = new BorderPanel(); private final SubviewAreaPanel subviewArea1 = new SubviewAreaPanel(SubviewArea.SUBVIEW_AREA_1); private final SubviewAreaPanel subviewArea2 = new SubviewAreaPanel(SubviewArea.SUBVIEW_AREA_2); private final SubviewAreaPanel subviewArea3 = new SubviewAreaPanel(SubviewArea.SUBVIEW_AREA_3); private final List<SubviewAreaPanel> subviewAreas = new ArrayList<SubviewAreaPanel>(Arrays.asList(subviewArea1, subviewArea2, subviewArea3)); // List of all added subviews (including custom subviews) private final List<Subview> subviews = new ArrayList<Subview>(); private final AnSplitPaneFixedRightSize splitPane1; private final AnSplitPaneFixedRightSize splitPane2; private final AnSplitPaneFixedRightSize splitPane3; public MainViewPanel() { initComponents(); setBackground(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); setBorder(null); setLayout(new GridBagLayout()); splitPane3 = new AnSplitPaneFixedRightSize( JSplitPane.VERTICAL_SPLIT, subviewArea1, subviewArea3, UserPref.getInstance().getSplitPane3().getSize(), UserPref.getInstance().getSplitPane3().getDefaultSize()); splitPane2 = new AnSplitPaneFixedRightSize( JSplitPane.VERTICAL_SPLIT, mainviewArea, subviewArea2, UserPref.getInstance().getSplitPane2().getSize(), UserPref.getInstance().getSplitPane2().getDefaultSize()); splitPane1 = new AnSplitPaneFixedRightSize( JSplitPane.HORIZONTAL_SPLIT, splitPane2, splitPane3, UserPref.getInstance().getSplitPane1().getSize(), UserPref.getInstance().getSplitPane1().getDefaultSize()); splitPane1.setHidden(true); splitPane2.setHidden(true); splitPane3.setHidden(true); GridBagConstraints gridBagConstraints = new GridBagConstraints(); // gridBagConstraints.insets = new Insets(5, 0, 5, 4); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(splitPane1, gridBagConstraints); } /** * @return the mainviewArea */ public JPanel getMainview() { return mainviewArea; } /** * @return the splitPane1 */ public AnSplitPaneFixedRightSize getSplitPane1() { return splitPane1; } /** * @return the splitPane2 */ public AnSplitPaneFixedRightSize getSplitPane2() { return splitPane2; } /** * @return the splitPane3 */ public AnSplitPaneFixedRightSize getSplitPane3() { return splitPane3; } public final void addSubview(Subview subview) { subviewAreas.get(subview.getSubviewArea().index()).addSubview(subview); subviews.add(subview); } public final Subview findSubview(String viewName) { Subview subview = null; for (Subview sv : subviews) { if (sv.getViewName().equals(viewName)) { subview = sv; break; } } return subview; } public final Subview findSubview(Component component) { Subview subview = null; for (Subview sv : subviews) { if (sv.getComponent() == component) { subview = sv; break; } } return subview; } public void hideAllSubviews() { for (Subview subview : subviews) { subview.setHidden(true); } } /** Show/hide subviews area depending on any tabs are visible */ public void showHideSubviewAreas() { // For now deal only with subviewArea2.... getSplitPane1().setHidden(subviewArea1.getTabCount() == 0); getSplitPane2().setHidden(subviewArea2.getTabCount() == 0); getSplitPane3().setHidden(subviewArea3.getTabCount() == 0); } public void setHidden(SubviewArea subviewArea, Subview subview, boolean hidden) { subviewAreas.get(subviewArea.index()).setHidden(subview, hidden); } public void setSelected(SubviewArea subviewArea, Subview subview) { subviewAreas.get(subviewArea.index()).setSelected(subview); } public boolean isSelected(SubviewArea subviewArea, Subview subview) { return subviewAreas.get(subviewArea.index()).isSelected(subview); } /** Dump views structure. Used in unit tests. */ public String dumpMainviewAreaVisibility() { StringBuilder buf = new StringBuilder(); buf.append("MAINVIEW_AREA\n"); buf.append(" "); buf.append(AnWindow.getInstance().getViews().getCurrentViewDisplay().getAnDispTab().getTCmd()); buf.append("\n"); return buf.toString(); } /** Dump contents of subviews. Used in unit tests. */ public String dumpSubviews() { StringBuilder buf = new StringBuilder(); if (!getSplitPane1().isHidden()) { buf.append(subviewArea1.dumpSubviews()); if (!getSplitPane3().isHidden()) { buf.append(subviewArea3.dumpSubviews()); } } if (!getSplitPane2().isHidden()) { buf.append(subviewArea2.dumpSubviews()); } return buf.toString(); } /** Dump views structure. Used in unit tests. */ public String dumpSubviewAreasVisibility() { StringBuilder buf = new StringBuilder(); if (!getSplitPane1().isHidden()) { buf.append(subviewArea1.dumpSubviewsVisibility()); if (!getSplitPane3().isHidden()) { buf.append(subviewArea3.dumpSubviewsVisibility()); } } if (!getSplitPane2().isHidden()) { buf.append(subviewArea2.dumpSubviewsVisibility()); } return buf.toString(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.GridBagLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ����gprofng-gui-1.0/org/gprofng/mpmt/ResolveFilePathPanel.form������������������������������������������0000644�0001750�0001750�00000022037�14517772113�020642� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,2,102"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="infoLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="2" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="unResolvedLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="unResolvedTextField"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="text" type="java.lang.String" value="222"/> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="null"/> </Property> <Property name="opaque" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="resolvedLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="resolvedTextField"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="text" type="java.lang.String" value="111"/> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="null"/> </Property> <Property name="opaque" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="4" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="pathTextField"> <Properties> <Property name="columns" type="int" value="50"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="5" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="browseButton"> <Properties> <Property name="text" type="java.lang.String" value="..."/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="5" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JCheckBox" name="archiveCheckBox"> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="archiveCheckBoxActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="6" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JCheckBox" name="thisFileOnlyCheckBox"> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="thisFileOnlyCheckBoxActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="7" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="17" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="errorLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="9" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnMemoryManager.java�����������������������������������������������0000644�0001750�0001750�00000014213�14517772113�017623� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.statuspanel.StatusHandleFactory; import org.gprofng.mpmt.statuspanel.StatusLabelValueHandle; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.SwingUtilities; /** * @author tpreisle */ public class AnMemoryManager { private static final long MB = 1024 * 1024; private static AnMemoryManager instance = null; private static StatusLabelValueHandle memoryStatusHandle = null; private static long max = 0; private static long total = 0; private static long free = 0; private static long leftThreshold = 0; private static long visibleThreshold = 0; private static long used = 0; private static long left = 0; private static boolean warned = false; public AnMemoryManager() {} public static AnMemoryManager getInstance() { if (instance == null) { instance = new AnMemoryManager(); } if (memoryStatusHandle == null && AnWindow.getInstance() != null && AnWindow.getInstance().getStatusPanel() != null) { memoryStatusHandle = StatusHandleFactory.createStatusLabelValue( AnWindow.getInstance(), null, null, AnLocale.getString("Available Memory"), new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.err.println("---------------Memory Usage"); System.err.println(statusText()); } }); memoryStatusHandle.setVisible(false); } return instance; } public boolean checkMemoryThreshold() { max = Runtime.getRuntime().maxMemory(); total = Runtime.getRuntime().totalMemory(); free = Runtime.getRuntime().freeMemory(); leftThreshold = Math.max(max / 8, 20 * MB); visibleThreshold = max / 2; used = total - free; left = max - used; if (left < visibleThreshold) { return true; } return false; } public void checkMemoryUsage() { max = Runtime.getRuntime().maxMemory(); total = Runtime.getRuntime().totalMemory(); free = Runtime.getRuntime().freeMemory(); leftThreshold = Math.max(max / 8, 20 * MB); visibleThreshold = max / 2; used = total - free; left = max - used; if (left < leftThreshold && !warned) { warning(); warned = true; } if (!(left < leftThreshold)) { warned = false; } if (memoryStatusHandle != null) { if ((used / MB) > visibleThreshold) { memoryStatusHandle.setVisible(true); } if (memoryStatusHandle.isVisible()) { final String labelValueText = (used / MB + "/" + max / MB + " MB"); // System.err.println(labelValueText); final String labelToolTip = statusTT(); final StatusLabelValueHandle.Mode mode = left < leftThreshold ? StatusLabelValueHandle.Mode.ERROR : StatusLabelValueHandle.Mode.DEFAULT; final ImageIcon icon = left < leftThreshold ? AnUtility.warningIcon : null; SwingUtilities.invokeLater( new Runnable() { @Override public void run() { memoryStatusHandle.update(labelValueText, mode); memoryStatusHandle.updateToolTip(labelToolTip); memoryStatusHandle.update(icon); } }); } } } private void warning() { String warning = "============================> LOW MEMORY WARNING"; String status = statusText(); StringBuilder stacktrace = new StringBuilder(); StackTraceElement[] se = new Exception().getStackTrace(); stacktrace.append(Thread.currentThread().getName()); stacktrace.append("\n"); for (StackTraceElement se1 : se) { stacktrace.append(se1.toString()); stacktrace.append("\n"); } AnLog.log(warning); AnLog.log(status); AnLog.log(stacktrace.toString()); System.err.println(warning); // FIXUP: should be removed System.err.println(status); // FIXUP: should be removed } private static String statusTT() { StringBuilder buf = new StringBuilder(); buf.append("<html>"); buf.append("<b>Memory Usage</b> (used/available): " + used / MB + "/" + max / MB + " MB"); buf.append("<br>"); buf.append("<b>max</b>: " + max / MB + " MB"); buf.append("<br>"); buf.append("<b>total</b>: " + total / MB + " MB"); buf.append("<br>"); buf.append("<b>free</b>: " + free / MB + " MB"); buf.append("<br>"); buf.append("<b>used</b>: " + used / MB + " MB"); buf.append("<br>"); buf.append("<b>leftThreshold</b>: " + leftThreshold / MB + " MB"); buf.append("<br>"); buf.append("<b>visibleThreshold</b>: " + visibleThreshold / MB + " MB"); buf.append("<br>"); buf.append("<b>left</b>: " + left / MB + " MB"); buf.append("<br>"); buf.append("</html>"); return buf.toString(); } private static String statusText() { StringBuilder buf = new StringBuilder(); buf.append("max: " + max / MB + " MB"); buf.append("\n"); buf.append("total: " + total / MB + " MB"); buf.append("\n"); buf.append("free: " + free / MB + " MB"); buf.append("\n"); buf.append("used: " + used / MB + " MB"); buf.append("\n"); buf.append("leftThreshold: " + leftThreshold / MB + " MB"); buf.append("\n"); buf.append("left: " + left / MB + " B"); return buf.toString(); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/FunctionsView.java�������������������������������������������������0000644�0001750�0001750�00000011155�14517772113�017406� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.util.gui.AnUtility; public final class FunctionsView extends FuncListDisp implements AnChangeListener { public FunctionsView() { super(AnWindow.getInstance(), AnDisplay.DSP_Functions, 0, AnVariable.HELP_TabsFunctions); setAccessibility(AnLocale.getString("Functions")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("FunctionsView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: setComputed(false); clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: setComputed(false); if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTION_CHANGING: case SELECTION_CHANGED: // Nothing break; case SELECTION_UPDATE: ignoreSelected = true; computeOnAWorkerThread(); // This will recompute if necessary and fire a SELECTION_CHANGED // event. break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { setComputed(false); if (selected) { computeOnAWorkerThread(); } } break; case SELECTED_OBJECT_CHANGED: if (selected) { computeOnAWorkerThread(); } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void setComputed(boolean set) { super.setComputed(set); AnWindow.getInstance().getCalledByCallsFunctionsView().setComputed(set); } @Override protected void setAvailable(boolean set) { super.setAvailable(set); AnWindow.getInstance().getCalledByCallsFunctionsView().setAvailable(set); } /** * Ensure Functions View has been computed (even if not selected) Note: must directly or * indirectly be called from another view's doCompute */ public void computeIfNeeded() { AnUtility.checkIfOnAWTThread(false); ignoreSelected = true; updateSummary = false; boolean savedComputed = computed; doCompute(); computed = savedComputed; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/PsParser.java������������������������������������������������������0000644�0001750�0001750�00000056544�14517772113�016355� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import java.util.ArrayList; import java.util.List; import java.util.logging.Logger; import java.util.regex.Pattern; /** * A service for accessing 'ps'. * * <pre> * Typical usage: * * PsParser psParser = PsParser.getDefault("Solaris"); // or "Linux" * psParser.setPsOutput(psOutput); // String psOutput is 'ps -ef' output * Vector<String> th = psParser.getData(true).header(); * java.util.regex.Pattern re = java.util.regex.Pattern.compile("."); * Vector<Vector<String>> tp = psParser.getData(true).processes(re); * (javax.swing.table.DefaultTableModel)jTable.getModel().setDataVector(tp, th); * * </pre> */ public abstract class PsParser { private static final Logger logger = Logger.getLogger(PsParser.class.getName()); public final class PsData { private List<List<String>> processes = new ArrayList<List<String>>(); private List<String> header = null; /** Translated header names in the table */ public List<String> header() { return header; } void setHeader(List<String> header) { this.header = header; } public int commandColumnIdx() { return commandColumnIndex(); } public int pidColumnIdx() { return pidColumnIndex(); } // public FileMapper getFileMapper() { // return PsProvider.this.getFileMapper(); // } /** filter lines and convert to columns */ public List<List<String>> processes(Pattern re) { List<List<String>> res = new ArrayList<List<String>>(); // Do filtering outer: for (List<String> proc : processes) { for (String field : proc) { if (re.matcher(field).find()) { res.add(proc); continue outer; } } } return res; } void addProcess(String line) { int offset = 0; List<String> columns = new ArrayList<String>(headerStr().length - 3); for (int cx = 0; cx < headerStr().length; cx++) { String s = null; if (cx == 7) { s = line.substring(offset + fields[cx][0]); } else // extra check for UID if (headerStr()[cx].contains("UID")) { assert offset == 0; int end = fields[cx][1]; while (line.charAt(end + 1) != ' ') { end++; } s = line.substring(fields[cx][0], end + 1); offset = end - fields[cx][1]; } else { s = line.substring(offset + fields[cx][0], offset + fields[cx][1] + 1); } if (cx != 3 && cx != 5 /* && cx != 6 */) { // No "C", "TTY" and /* "TIME" */columns columns.add(s.trim()); } } processes.add(columns); } private void updateCommand(String pid, String command) { for (List<String> proc : processes) { if (pid.equals(proc.get(pidColumnIdx()))) { proc.set(commandColumnIdx(), command); } } } } // can't be static, for format of ps output is different from host to host private List<String> parsedHeader = null; protected static final String zero = "0"; private String uid = null; private int fields[][] = new int[8][2]; /** Specialization of PsParser for Solaris */ static class SolarisPsParser extends PsParser { private static final String header_str_solaris[] = { "UID", "PID", "PPID", "C", // skipped "STIME", "TTY ", // skipped " TIME", // skipped "CMD", }; public SolarisPsParser(/* NM Host host */ ) { super(/* NM host */ ); } @Override public int commandColumnIndex() { return 4; } @Override public int pidColumnIndex() { return 1; } @Override public String[] headerStr() { return header_str_solaris; } /* * for executor, not used now, * in the future if we want to get uid from remote host * this is will be used. */ // protected String[] uidCommand1() { // String [] args = new String[2]; // args[0] = "/usr/xpg4/bin/id"; // args[1] = "-u"; // return args; // } @Override protected String uidCommand() { return "/usr/xpg4/bin/id -u"; } /* OLD protected String[] psCommand1(String uid) { if (Log.Ps.null_uid) uid = null; if ( (uid == null) || (uid.equals(zero)) ) { // uid=0 => root; use ps -ef // OLD return "LANG=C /bin/ps -www -o pid,tty,time,cmd"; String [] args = new String[2]; args[0] = "/usr/bin/ps"; args[1] = "-ef" ; return args; // return "LANG=C /usr/bin/ps -ef"; } else { String [] args = new String[3]; args[0] = "/usr/bin/ps"; args[1] = "-fu"; args[2] = uid; return args; // return "LANG=C /usr/bin/ps -fu " + uid; } } */ @Override protected String psCommand(String uid) { // SHOULD set LC_ALL=C here since we're depending // on column widths to get to the individual ps items! // (moved to getData) // if (Log.Ps.null_uid) // uid = null; if ((uid == null) || (uid.equals(zero))) { // uid=0 => root; use ps -ef return "/usr/bin/ps -ef"; } else { return "/usr/bin/ps -fu " + uid; } } @Override public PsData getData(boolean allProcesses) { PsData res = super.getData(allProcesses); // pargs call if needed // if (res != null && !DISABLE_PARGS && !res.processes.isEmpty()) { // NativeProcessBuilder pargsBuilder = // NativeProcessBuilder.newProcessBuilder(exEnv); // pargsBuilder.setExecutable("/usr/bin/pargs").redirectError(); // pargsBuilder.getEnvironment().put("LC_ALL", "C"); // String[] pargs_args = new String[res.processes.size()+1]; // pargs_args[0] = "-Fl"; // int idx = 1; // for (Vector<String> proc : res.processes) { // pargs_args[idx++] = proc.get(pidColumnIndex()); // } // pargsBuilder.setArguments(pargs_args); // // try { // List<String> pargsOutput = // ProcessUtils.readProcessOutput(pargsBuilder.call()); // updatePargsData(res, pargs_args, pargsOutput); // } catch (IOException ex) { // Exceptions.printStackTrace(ex); // } // } return res; } } // static void updatePargsData(PsData res, String[] pargs_args, List<String> pargsOutput) { // int idx = 1; // for (String procArgs : pargsOutput) { // if (procArgs.isEmpty() || // procArgs.startsWith("pargs: Warning") || // procArgs.startsWith("pargs: Couldn't determine locale of target process") || // procArgs.startsWith("pargs: Some strings may not be displayed properly")) { // continue; // } // if (!procArgs.startsWith("pargs:")) { // res.updateCommand(pargs_args[idx], procArgs); // } // idx++; // } // if ( (idx-1) != res.processes.size()) { // we should check if the operation has been // applied to all processes // throw new AssertionError("Process list:" + res.processes.toString() + "\npargs // output:" + pargsOutput.toString()); // } // } /** Specialization of PsParser for Linux */ static class LinuxPsParser extends PsParser { private static final String header_str_linux[] = { "UID ", "PID", "PPID", "C", // skipped "STIME", "TTY ", // skipped " TIME", // skipped "CMD", }; public LinuxPsParser(/*NM Host host */ ) { super(/*NM host */ ); } @Override public int commandColumnIndex() { return 4; } @Override public int pidColumnIndex() { return 1; } @Override public String[] headerStr() { return header_str_linux; } /* * for executor, not used, * in the future if we want to get uid from remote host * this is will be used. */ // protected String [] uidCommand1() { // String [] args = new String[2]; // args[0] = "/usr/bin/id"; // args[1] = "-u"; // return args; // } @Override protected String uidCommand() { return "/usr/bin/id -u"; } /* OLD protected String[] psCommand1(String uid) { if (Log.Ps.null_uid) uid = null; if ( (uid == null) || (uid.equals(zero)) ) { // uid=0 => root; use ps -ef // OLD return "LANG=C /bin/ps -www -o pid,tty,time,cmd"; String [] args = new String[2]; args[0] = "/bin/ps"; args[1] = "-ef"; return args; } else { String [] args = new String[3]; args[0] = "/bin/ps"; args[1] = "-fu"; args[2] = uid; return args; } } */ @Override protected String psCommand(String uid) { // SHOULD set LC_ALL=C here since we're depending // on column widths to get to the individual ps items! // (moved to getData) // if (Log.Ps.null_uid) // uid = null; if ((uid == null) || (uid.equals(zero))) { // uid=0 => root; use ps -ef // OLD return "LANG=C /bin/ps -www -o pid,tty,time,cmd"; return "/bin/ps -ef"; } else { return "/bin/ps -fu " + uid + " --width 1024"; } } } // static class MacOSPsProvider extends LinuxPsProvider { // private final static String header_str_mac[] = { // " UID", // " PID", // " PPID", // " C", // skipped // "STIME", // "TTY ", // skipped // " TIME", // skipped // "CMD", // }; // // @Override // public String[] headerStr() { // return header_str_mac; // } // // public MacOSPsProvider(Host host) { // super(host); // } // // @Override // protected String psCommand(String uid) { // if ( (uid == null) || (uid.equals(zero)) ) { // return "/bin/ps -ef"; // } else { // return "/bin/ps -fu " + uid; // } // } // } /** Specialization of PsProvider for Windows */ // static class WindowsPsProvider extends PsProvider { // private FileMapper fileMapper = FileMapper.getDefault(); // // private final static String header_str_windows[] = { // "PID", // "PPID", // "PGID", // "WINPID", // "TTY", // skipped // "UID", // "STIME", // "COMMAND", // }; // // public WindowsPsProvider(Host host) { // super(host); // } // // public int commandColumnIndex() { // return 4; // } // // // see IZ 193741 - skip status column // @Override // protected int firstPosition() { // return 1; // } // // public int pidColumnIndex() { // return 0; // } // // public String[] headerStr() { // return header_str_windows; // } // // protected String uidCommand() { // return getUtilityPath("id") + " -u"; // } // // protected String psCommand(String uid) { // // SHOULD set LC_ALL=C here since we're depending // // on column widths to get to the individual ps items! // // (moved to getData) // // if (Log.Ps.null_uid) // uid = null; // // // Always show all processes on Windows (-W option), see IZ 193743 // if ( (uid == null) || (uid.equals(zero)) ) { // // uid=0 => root; use ps -ef // return getUtilityPath("ps") + " -W"; // } else { // return getUtilityPath("ps") + " -u " + uid + " -W"; // } // } // // private String getUtilityPath(String util) { // File file = new File(CompilerSetUtils.getCygwinBase() + "/bin", util + ".exe"); // if (file.exists()) { // fileMapper = FileMapper.getByType(FileMapper.Type.CYGWIN); // } else { // fileMapper = FileMapper.getByType(FileMapper.Type.MSYS); // file = new File(CompilerSetUtils.getCommandFolder(null), util + ".exe"); // } // if (file.exists()) { // return file.getAbsolutePath(); // } // return util; // } // // @Override // public FileMapper getFileMapper() { // return fileMapper; // } // } // public static synchronized PsProvider getDefault(Host host) { // PsProvider psProvider = host.getResource(PsProvider.class); // if (psProvider == null) { // ExecutionEnvironment exEnv = host.executionEnvironment(); // if (!ConnectionManager.getInstance().connect(exEnv)) { // return null; // } // try { // HostInfo hostInfo = HostInfoUtils.getHostInfo(exEnv); // switch (hostInfo.getOSFamily()) { // case LINUX: // psProvider = new LinuxPsProvider(host); // break; // case WINDOWS: // psProvider = new WindowsPsProvider(host); // break; // case MACOSX: // psProvider = new MacOSPsProvider(host); // break; // default: // psProvider = new SolarisPsProvider(host); // } // } catch (CancellationException e) { // // user cancelled connection attempt // } catch (Exception e) { // Exceptions.printStackTrace(e); // } // host.putResource(PsProvider.class, psProvider); // } // return psProvider; // } public static synchronized PsParser getDefault(String OSFamily) { PsParser psParser = null; if ("Linux".equals(OSFamily)) { psParser = new LinuxPsParser(); } if ("Solaris".equals(OSFamily)) { psParser = new SolarisPsParser(); } return psParser; } /** Return index of the CMD column. */ protected abstract int commandColumnIndex(); protected abstract int pidColumnIndex(); protected abstract String[] headerStr(); // protected abstract String[] uidCommand1(); // for executor, not used protected abstract String psCommand(String root); // OLD protected abstract String[] psCommand1(String root); // for executor protected abstract String uidCommand(); // for Runtime.exe protected int firstPosition() { return 0; } // return file mapper (important only on Windows) // public FileMapper getFileMapper() { // return FileMapper.getDefault(); // } // // protected final ExecutionEnvironment exEnv; // // private PsProvider(Host host) { // exEnv = host.executionEnvironment(); // } // "host" for getUid is usually "localhost" private String getUid() { // if (uid == null) { // try { // NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(exEnv); // npb.setCommandLine(uidCommand()); // NativeProcess process; // try { // process = npb.call(); // } catch (Exception e) { // logger.log(Level.WARNING, "Failed to exec id command", e); // return exEnv.getUser(); // } // // String res = ProcessUtils.readProcessOutputLine(process); // // int exitCode = process.waitFor(); // if (exitCode != 0) { // String msg = "id command failed with " + exitCode; // logger.log(Level.WARNING, msg); // return exEnv.getUser(); // } // if (!res.isEmpty()) { // uid = res; // } else { // uid = exEnv.getUser(); // } // } catch (Exception e) { // ErrorManager.getDefault().annotate(e, "Failed to parse OutputStream of uid // command"); // ErrorManager.getDefault().notify(e); // } // } return uid; } /** Debugging method for printing column boundaries as discovered by parseHeader(). */ private void printFields(String str) { System.out.printf("------------------------------------------------\n"); System.out.printf("%s\n", str); for (int sx = 0; sx < str.length(); sx++) { boolean found = false; for (int cx = 0; cx < headerStr().length; cx++) { if (fields[cx][0] == sx) { System.out.printf("%d", cx); found = true; } else if (fields[cx][1] == sx) { System.out.printf("%d", cx); found = true; } } if (!found) { System.out.printf(" "); } } System.out.printf("\n"); System.out.printf("------------------------------------------------\n"); } /** * Return a Vector of headers based on the first line emitted by 'ps' and populate 'fields' as a * side-effect. * * <p>First lines look like this on solaris: * * <p>| UID PID PPID C STIME TTY TIME CMD | ivan 1501 1483 0 Nov 26 console 0:07 xterm -name * edit-left * * <p>and like this on linux: * * <p>|UID PID PPID C STIME TTY TIME CMD |ivan 11585 11583 0 12:39 pts/2 00:00:00 -csh * * <p>Field justifications are as follows: * * <p>field solaris linux ------------------------------ UID right left PID right right PPID right * right C 1 character 1 STIME right left TTY left left TIME right right CMD left left * * <p>The current column boundary determination is as follows: for solaris * |------------------------------------------------ | UID PID PPID C STIME TTY TIME CMD |0 01 12 * 23 34 45 56 67 7 |------------------------------------------------ ... and linux ...: * |------------------------------------------------ |UID PID PPID C STIME TTY TIME CMD |0 01 12 * 23 34 45 56 67 7 |------------------------------------------------ * * <p>The left side of left-aligned columns is one column too much to the left (STIME, C, TTY and * CMD). This is no problem as long as the left edge of this columns is next to a right-aligned * column. It should just be a space and get eaten up by 'trim'. TTY on linux is the only one * which doesn't abide by this. But I'm going to wing it for now and postpone making this column * discovery even more involved. */ List<String> parseHeader(String str) { /* OLD // parsedHeader is static so we only do this once if (parsedHeader != null) return parsedHeader; */ // if (Log.Ps.debug) // System.out.printf("parseHeader: '%s'\n", str); parsedHeader = new ArrayList<String>(headerStr().length - 3); for (int cx = 0; cx < headerStr().length; cx++) { String s = null; int i; i = str.indexOf(headerStr()[cx]); // fields[cx][0] the begining of this column // fields[cx][1] the end of this column if (i >= 0) { // found if (cx == 0) // first column { fields[cx][0] = firstPosition(); } fields[cx][1] = i + headerStr()[cx].length() - 1; } if (cx == 7) { // last one s = str.substring(fields[cx][0]); } else { s = str.substring(fields[cx][0], fields[cx][1] + 1); fields[cx + 1][0] = i + headerStr()[cx].length(); } // if (Log.Ps.debug) // System.out.println("fields : " + fields[cx][0] + " " + fields[cx][1]); if (cx != 3 && cx != 5 /* && cx != 6 */) // No "C", "TTY" and /* "TIME" */ columns { parsedHeader.add(s.trim()); } } // if (Log.Ps.debug) // printFields(str); // translate header for (int hx = 0; hx < parsedHeader.size(); hx++) { String h = parsedHeader.get(hx); // NM parsedHeader.set(hx, Catalog.get("PS_HDR_" + h)); parsedHeader.set(hx, h); } return parsedHeader; } /** * Execute a ps command and return the data. * * <p>Executes a ps command, captures the output, remembers the first line as the 'parsedHeader', * stuffs the rest of the lines into 'PsData.lines'. PsData will columnize lines later. */ public PsData getData(boolean allProcesses) { PsData psData = new PsData(); String luid = allProcesses ? null : getUid(); // try { // //FIXME // NativeProcessBuilder npb = NativeProcessBuilder.newProcessBuilder(exEnv); // npb.setCommandLine(psCommand(luid)); // npb.getEnvironment().put("LANG", "C"); // // NativeProcess process; // try { // process = npb.call(); // } catch (Exception e) { // logger.log(Level.WARNING, "Failed to exec ps command", e); // return null; // } int lineNo = 0; // NM for (String line : ProcessUtils.readProcessOutput(process)) { for (String line : getPsOutput()) { // if (Log.Ps.debug) // System.out.printf("PsOutput: '%s'\n", line); if (line.indexOf("UID", 0) != -1) { // first line psData.setHeader(parseHeader(line)); lineNo++; } else if (lineNo++ > 0) { psData.addProcess(line); } } // int exitCode = process.waitFor(); // if (exitCode != 0) { // String msg = "ps command failed with " + exitCode; // logger.log(Level.WARNING, msg); // return null; // } // // } catch (Exception e) { // ErrorManager.getDefault().annotate(e, "Failed to parse OutputStream of ps command"); // ErrorManager.getDefault().notify(e); // } // // if (psData.processes.isEmpty()) { // ErrorManager.getDefault().log(ErrorManager.EXCEPTION, // "No lines from "); // } return psData; } // TEMPORARY private String psOutput = null; public void setPsOutput(String s) { psOutput = s; } String[] getPsOutput() { String[] s = {""}; // TEMPORARY List<String> v = new ArrayList(); if (null != psOutput) { for (int n = 0; n < psOutput.length(); ) { int k = psOutput.indexOf('\n', n); if (k < n) { break; // ignore incomplete line } String line = psOutput.substring(n, k); v.add(line); n = k + 1; } } int len = v.size(); if (len > 0) { s = new String[len]; for (int i = 0; i < len; i++) { s[i] = v.get(i); } } return s; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/picklist/����������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�015654� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/picklist/StringPickListElement.java��������������������������������0000644�0001750�0001750�00000002170�14517772113�022645� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.picklist; public class StringPickListElement implements PickListElement { private String elem; public StringPickListElement(String elem) { this.elem = elem; } public String getString() { return elem; } /** Compares two PicklistElement for equality. Returns true if equal, otherwise false. */ @Override public boolean equals(PickListElement elem) { return ((StringPickListElement) elem).getString().equals(this.elem); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/picklist/PickListEvent.java����������������������������������������0000644�0001750�0001750�00000002767�14517772113�021162� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.picklist; import java.util.EventObject; /** Defines an event that encapsulates changes to a Picklist. */ public class PickListEvent extends EventObject { /** Identifies one or more changes in the lists contents. */ public static final int CONTENTS_CHANGED = 0; /** * The type of this event; */ private int type; /** * Constructs a PicklistDataEvent object. * * @param source the source Object (typically <code>this</code>) * @param type an int specifying {@link #CONTENTS_CHANGED} */ public PickListEvent(Object source, int type) { super(source); this.type = type; } /** * Returns the event type. The possible values are: * * <ul> * <li>{@link #CONTENTS_CHANGED} * </ul> * * @return an int representing the type value */ public int getType() { return type; } } ���������gprofng-gui-1.0/org/gprofng/mpmt/picklist/PickListListener.java�������������������������������������0000644�0001750�0001750�00000001732�14517772113�021655� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.picklist; import java.util.EventListener; public interface PickListListener extends EventListener { /** * Sent when the contents of the list has changed. * * @param e a <code>PicklistDataEvent</code> encapsulating the event information */ void contentsChanged(PickListEvent e); } ��������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/picklist/PickList.java���������������������������������������������0000644�0001750�0001750�00000020633�14517772113�020150� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.picklist; import java.util.ArrayList; import java.util.List; import javax.swing.event.EventListenerList; public class PickList { /** Default max size of Picklist */ private int maxSize = 8; /** Increase size of Picklist, if variable sized */ private static int increaseSize = 8; /** The list itself and it's current size */ private PickListElement[] picklist = null; private int picklistSize = 0; /** Holds list of event listeners */ protected EventListenerList listenerList = null; /** Creates a new variable sized Picklist */ public PickList() { initialize(0); } /** Creates a new Picklist with maximux 'max' elements. 'max' <= 0 means variable sized list. */ public PickList(int max) { initialize(max); } private EventListenerList getListenerList() { if (listenerList == null) { listenerList = new EventListenerList(); } return listenerList; } /** Initializing data */ private void initialize(int max) { if (max <= 0) { maxSize = 0; // Open-ended ... picklist = new PickListElement[increaseSize]; } else { maxSize = max; // Fixed sized picklist = new PickListElement[increaseSize]; } } /** * Adds the specified component to the beginning of this list, increasing its size by one. * * @param elem the component to be added. */ public void addElement(PickListElement elem) { addElement(elem, true); // notify listener of a change fireContentsChanged(this); } public void addElements(List<PickListElement> list) { for (PickListElement elem : list) { addElement(elem, true); } // notify listener of a change fireContentsChanged(this); } /** * Adds the specified component to the beginning of this list, increasing its size by one. * * @param elem the component to be added. */ private synchronized void addElement(PickListElement elem, boolean check) { // Is this the only method that needs to synchronized??? FIXUP // first check if element already in the list int foundAt = contains(elem); int shiftDownFrom = 0; if (check && foundAt >= 0) { shiftDownFrom = foundAt; picklistSize--; } else { // Open-ended list if (picklistSize == picklist.length) { // Need to increate the size of picklist PickListElement[] picklist2 = new PickListElement[picklist.length + increaseSize]; for (int i = 0; i < picklist.length; i++) { picklist2[i] = picklist[i]; } picklist = picklist2; } shiftDownFrom = picklistSize; } // Shift down elements for (int i = shiftDownFrom; i > 0; i--) { picklist[i] = picklist[i - 1]; } // insert at top and increase size picklist[0] = elem; picklistSize++; // if fixed-sizes list, check size and possile delete last element if (maxSize > 0 && picklistSize >= maxSize) { picklistSize--; } } /** * Tests if the specified element is a component in this list. * * @param elem an object. * @return index of the specified element in the list if it exists as determined by the * <tt>equals</tt> method; <code>-1</code> otherwise. */ public int contains(PickListElement elem) { int foundAt = -1; if (elem != null) { for (int i = 0; i < picklistSize; i++) { if (picklist[i].equals(elem)) { foundAt = i; break; } } } return foundAt; } /** * Returns the value at the specified index. * * @param index the requested index * @return the value at <code>index</code> */ public PickListElement getElementAt(int index) { if (index >= 0 && index < picklistSize) { return picklist[index]; } else { return null; } } public List<PickListElement> getElements() { List<PickListElement> ret = new ArrayList<PickListElement>(); for (PickListElement picklistElement : picklist) { if (picklistElement != null) { ret.add(picklistElement); } } return ret; } /** * Returns the max length of the list, 0 being variable sized. * * @return the max length of the list, 0 being variable sized */ public int getMaxSize() { return maxSize; } /** * Returns the top-most element in the list if not empty, otherwise null. * * @return the top-most element in the list */ public PickListElement getMostRecentUsedElement() { if (picklistSize > 0) { return picklist[0]; } else { return null; } } /** * Returns the length of the list. * * @return the length of the list */ public int getSize() { return picklistSize; } /** Removes all elements from this list and sets its size to zero. */ public void removeAllElements() { for (int i = 0; i < picklist.length; i++) { picklist[i] = null; } picklistSize = 0; // notify listener of a change fireContentsChanged(this); } /** * Removes the first (lowest-indexed) occurrence of the argument from this list. * * @param elem the element to be removed. * @return the element removed if found, null otherwise. */ public PickListElement removeElement(PickListElement elem) { return removeElementAt(contains(elem)); } /** * Removes the element at the specified index from the list. Each element in this list with an * index greater or equal to the specified <code>index</code> is shifted downward to have an index * one smaller than the value it had previously. The size of this list is decreased by <tt>1</tt>. * * <p>The index must be a value greater than or equal to <code>0</code> and less than the current * size of the list. * * <p> * * @param index the index of the object to remove. * @return the element removed if index valid, null otherwise. */ public PickListElement removeElementAt(int index) { PickListElement toBeRemoved = null; if (index < 0 || index >= picklistSize) { return toBeRemoved; } toBeRemoved = picklist[index]; for (int i = index; i < picklistSize - 1; i++) { picklist[i] = picklist[i + 1]; } picklistSize--; // notify listener of a change fireContentsChanged(this); return toBeRemoved; } /** * Replaces the element at the specified index with the one specified. * * @param index the index of the object to remove. * @return the element replaced if index valid, null otherwise. */ public PickListElement replaceElementAt(PickListElement elem, int index) { PickListElement toBeReplaced = null; if (index < 0 || index >= picklistSize) { return toBeReplaced; } toBeReplaced = picklist[index]; picklist[index] = elem; // notify listener of a change fireContentsChanged(this); return toBeReplaced; } /** * Adds a listener to the list that's notified each time a change to the data model occurs. * * @param l the <code>PicklistDataListener</code> to be added */ public void addPicklistListener(PickListListener l) { getListenerList().add(PickListListener.class, l); } /** * Removes a listener from the list that's notified each time a change to the data model occurs. * * @param l the <code>PicklistDataListener</code> to be removed */ public void removePicklistListener(PickListListener l) { getListenerList().remove(PickListListener.class, l); } private void fireContentsChanged(Object source) { Object[] listeners = getListenerList().getListenerList(); PickListEvent e = null; for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == PickListListener.class) { if (e == null) { e = new PickListEvent(source, PickListEvent.CONTENTS_CHANGED); } ((PickListListener) listeners[i + 1]).contentsChanged(e); } } } } �����������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/picklist/PickListElement.java��������������������������������������0000644�0001750�0001750�00000001554�14517772113�021463� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.picklist; public interface PickListElement { /** Compares two PicklistElement for equality. Returns true if equal, otherwise false. */ public boolean equals(PickListElement elem); } ����������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/picklist/StringPickList.java���������������������������������������0000644�0001750�0001750�00000002710�14517772113�021333� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.picklist; import java.util.ArrayList; import java.util.List; public class StringPickList extends PickList { /** Creates a new variable sized Picklist */ public StringPickList() { super(); } /** Creates a new Picklist with maximux 'max' elements. 'max' <= 0 means variable sized list. */ public StringPickList(int max) { super(max); } public void addElement(String elem) { super.addElement(new StringPickListElement(elem)); } public List<StringPickListElement> getStringElements() { List<StringPickListElement> list = new ArrayList<StringPickListElement>(); List<PickListElement> mostRecentExperiments = getElements(); for (PickListElement ple : mostRecentExperiments) { list.add((StringPickListElement) ple); } return list; } } ��������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnVariable.java����������������������������������������������������0000644�0001750�0001750�00000024157�14517772113�016615� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import java.awt.Color; import java.awt.Dimension; import java.awt.Insets; import java.awt.Toolkit; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.EmptyBorder; import javax.swing.border.LineBorder; public final class AnVariable { public static final Object mainFlowLock = new Object(); // Runtime environment public static final Dimension SCREEN_SIZE = Toolkit.getDefaultToolkit().getScreenSize(); // Preferred color public static final Color LABEL_COLOR = Color.black; // regular label public static final Color CCOMP_COLOR = new Color(46, 146, 199); // comp-comm public static final Color DISRC_COLOR = new Color(117, 117, 117); // src for dis public static final Color QUOTE_COLOR = new Color(199, 0, 0); // quote public static final Color HILIT_COLOR = Color.ORANGE; // flagged public static final Color HILIT_INC_COLOR = new Color(255, 245, 0); // flagged public static final Color HOTLINE_COLOR = new Color(255, 165, 0); // flagged public static final Color WARMLINE_COLOR = new Color(215, 215, 225); // flagged public static final Color COMENTARY_COLOR = new Color(233, 239, 248); // background color for commentary public static final Color SRCDIS_COLOR = new Color(245, 245, 245); // background color for source in disasm view public static final Color KEYWORD_COLOR = new Color(0, 0, 230); // syntax highlighting public static final Color COMMENT_COLOR = new Color(155, 155, 155); // syntax highlighting public static final Color DIRECTIVE_COLOR = new Color(0, 155, 0); // syntax highlighting public static final Color STRING_COLOR = new Color(206, 123, 0); // syntax highlighting public static final Color LINENO_COLOR = new Color(155, 155, 183); // syntax highlighting public static final Color LINENO_COLOR_BOLD = new Color(95, 95, 123); // syntax highlighting public static final Color OPCODE_COLOR = new Color(0, 155, 0); // syntax highlighting public static final Color OPRANDREG_COLOR = new Color(46, 146, 199); // syntax highlighting public static final Color OPRANDVALUE_COLOR = new Color(153, 51, 204); // syntax highlighting public static final Color REGSEL_COLOR = new Color(135, 206, 250); // background color for selected reg public static final Color WARNINGPANEL_COLOR = new Color(255, 255, 199); // background color for warning panel public static final Color JMPOTHER_COLOR = new Color(0, 185, 0); // forground color for jump forward address public static final Color JMPBACK_COLOR = new Color(243, 143, 0); // forground color for jump back address public static final Color JMPOUTSIDE_COLOR = Color.RED; // forground color for jump outside function address // Preferred windows size public static final int WIN_WIDTH, WIN_HEIGHT; private static final int INFO_PRF_WIDTH, INFO_MIN_WIDTH; private static final int FVIEW_WIDTH, FVIEW_HEIGHT; public static final Dimension WIN_SIZE; public static final Dimension INFO_PRF_SIZE; public static final Dimension INFO_MIN_SIZE; public static final Dimension FVIEW_SIZE; static { WIN_WIDTH = 850; INFO_PRF_WIDTH = 370; WIN_HEIGHT = 450; INFO_MIN_WIDTH = 200; FVIEW_WIDTH = 650; FVIEW_HEIGHT = 400; WIN_SIZE = new Dimension(WIN_WIDTH, WIN_HEIGHT); INFO_PRF_SIZE = new Dimension(INFO_PRF_WIDTH, WIN_HEIGHT); INFO_MIN_SIZE = new Dimension(INFO_MIN_WIDTH, WIN_HEIGHT); FVIEW_SIZE = new Dimension(FVIEW_WIDTH, FVIEW_HEIGHT); } private static final int HELP_WIDTH = 600; private static final int HELP_HEIGHT = 700; public static final Dimension HELP_SIZE = new Dimension(HELP_WIDTH, HELP_HEIGHT); // Label with left/right margin space private static final int sizeLabel = 4; public static final int sizeIcon = 1; public static final Border labelBorder = new EmptyBorder(0, sizeLabel, 0, sizeLabel); public static final Border fieldBorder = new EmptyBorder(sizeLabel, 0, sizeLabel, 0); public static final Border iconBorder = new EmptyBorder(0, sizeIcon, 0, sizeIcon); public static final Border boxBorder = new EmptyBorder(sizeLabel, sizeLabel, sizeLabel, sizeLabel); public static final Border textBorder = UIManager.getBorder("TextField.border"); public static final Border noFocusBorder = new EmptyBorder(1, 1, 1, 1); public static final Border listFocusBorder = UIManager.getBorder("List.focusCellHighlightBorder"); public static final Border tableFocusBorder = UIManager.getBorder("Table.focusCellHighlightBorder"); public static final Border treeFocusBorder = new LineBorder(UIManager.getColor("Tree.selectionBorderColor")); // Button margin public static final Insets buttonMargin = new Insets(1, 1, 1, 1); // All chars public static final String all_chars = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "1234567890-=\\`[];',./" + "!@#$%^&*()_+|~{}:\"<>?"; // Help mapIDs public static final String HELP_WelcomeAnalyzer = "Welcome_Analyzer"; public static final String HELP_InformationMap = "Information"; public static final String HELP_NewFeatures = "Welcome_WhatsNew"; public static final String HELP_QuickReference = "Navigate_QuickRef"; public static final String HELP_KeyboardShortcuts = "Navigate_Keyboard"; public static final String HELP_HelpShortcuts = "Navigate_KbdNavHelp"; public static final String HELP_Troubleshooting = "Trouble_Trouble"; public static final String HELP_Welcome = "WelcomeView"; // "Tabs_Welcome"; public static final String HELP_Export = null; // "Tabs_Welcome"; public static final String HELP_Overview = "Tabs_Overview"; public static final String HELP_TabsFunctions = "Tabs_Functions"; public static final String HELP_TabsCallersCallees = "Tabs_CallersCallees"; public static final String HELP_CallFlameChart = "CallFlameChart"; public static final String HELP_TabsCallTree = "Tabs_CallTree"; public static final String HELP_TabsSource = "Tabs_Source"; public static final String HELP_TabsLines = "Tabs_Lines"; public static final String HELP_TabsDisassembly = "Tabs_Disassembly"; public static final String HELP_TabsPCs = "Tabs_PCs"; public static final String HELP_TabsDataLayout = "Tabs_DataLayout"; public static final String HELP_TabsDataObjects = "Tabs_DataObjects"; public static final String HELP_TabsTimeline = "Tabs_Timeline"; public static final String HELP_TabsStatistics = "Tabs_Statistics"; public static final String HELP_TabsExperiments = "Tabs_Experiments"; public static final String HELP_TabsExperimentIDs = "Tabs_ExperimentIDs"; public static final String HELP_TabsLeaklist = "Tabs_Leaklist"; public static final String HELP_TabsHeap = "Tabs_Heap"; public static final String HELP_TabsMemObj = "Tabs_MemObj"; public static final String HELP_TabsIndxObj = "Tabs_IndxObj"; public static final String HELP_TabsIFreq = "Tabs_IFreq"; public static final String HELP_TabsSummary = "Tabs_Summary"; public static final String HELP_TabsEvent = "Tabs_Event"; public static final String HELP_TabsLegend = "Tabs_Legend"; public static final String HELP_TabsLeak = "Tabs_Leak"; public static final String HELP_TabsProcesses = "Tabs_Processes"; public static final String HELP_TabsRaceList = "Tabs_RaceList"; public static final String HELP_TabsRaceDetails = "Tabs_RaceDetails"; public static final String HELP_TabsRaceDualSrc = "DualSource"; public static final String HELP_TabsSrcDisassm = "Tabs_SrcDisassm"; public static final String HELP_TabsThreads = "Threads"; public static final String HELP_TabsCPUs = "CPUs"; public static final String HELP_TabsSamples = "Samples"; public static final String HELP_TabsSeconds = "Seconds"; public static final String HELP_TabsThreadsChart = "Threads"; public static final String HELP_TabsDeadlockDetails = "Tabs_DeadlockDetails"; public static final String HELP_TabsDeadlocksList = "Tabs_DeadlocksList"; public static final String HELP_TabsIOActivity = "Tabs_IOActivity"; public static final String HELP_TabsMPITimeline = "MPITimeline"; public static final String HELP_TabsMPIChart = "MPIChart"; public static final String HELP_TabsOMPParallelRegions = "Tabs_OMPParallelRegions"; // new tag????? public static final String HELP_TabsOpenMPTasks = "Tabs_OpenMPTasks"; public static final String HELP_Settings = "Data_SetPref"; public static final String HELP_Filter = "CustomFilters"; public static final String HELP_ShowHideFunctions = "Data_ShowHide"; public static final String HELP_CollectDialog = "CollectAnalyzer"; public static final String HELP_CollectRunningDialog = "CollectRunning"; public static final String HELP_CollectKernelDialog = "ProfileKernel"; public static final String HELP_MachModel = "LoadMachModel"; public static final String HELP_MachineModelBrowser = "BrowseMachModel"; public static final String HELP_CustomMemTab = "AddCustomMemTab"; public static final String HELP_CustomIndxTab = "AddCustomIndxTab"; public static final String HELP_DataSize = "Tabs_DataSize"; public static final String HELP_Duration = "Tabs_Duration"; public static final String HELP_Compare = "Compare"; public static final String HELP_Aggregate = "Aggregate"; // public final static String HELP_RemoteAnalyzer = "RemoteAnalyzer"; public static final String HELP_ConnectRemoteHost = "ConnectToRemoteHost"; public static final String HELP_ConnectAuthentication = "Managing_Auth"; public static final String HELP_ExportSettings = "ExportSettings"; // FIXUP public static final String HELP_ResolveSourceFile = "ResolveSourceFile"; // FIXUP } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnHotGap.java������������������������������������������������������0000644�0001750�0001750�00000054636�14517772113�016257� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Cursor; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.awt.geom.Rectangle2D; import java.util.Vector; import javax.accessibility.AccessibleContext; import javax.swing.AbstractAction; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.ToolTipManager; import javax.swing.event.PopupMenuEvent; /** * A component that lets the user navigate between hot lines clicking on an appropriate colored * rect. due to rfe #4487681 () */ public final class AnHotGap extends JPanel implements MouseListener, MouseMotionListener { // Hot Rect constants private AnMenuListener menuListener; private AnTable table; private /*final*/ double box_height = 2.; // height of rect public static final int HOTGAP_WIDTH = 18; private final double box_width = HOTGAP_WIDTH - 6; // width of rect private final double height_adjustment = 16; // height of the scrollbare arrow private final double handle_adjustment = 8; // half height of the handle private final double x_left = (HOTGAP_WIDTH - box_width) / 2 - 1; // left rect indentation private Vector hots, vect; // hots - list of hot lines; vect - list of hot rects private Vector warm_lines; // warm_lines - list of warm lines (a metric value > 0) private int warm_lines_count = 0; // count of warm lines private boolean show_warm_lines = true; private FuncListDisp disp = null; // SRC or DIS display private int hots_count = 0; // Count of hot lines private int row_count; // count of the table lines private int curr_line = 0; // Current line private boolean isHotRect = false; // indicates hot rect private String text = null; // Tooltip text for hot rect private Rectangle2D.Double rect, rect_shadow; private Rectangle r; private ToolTipManager tm; // Tooltip manager private AnTable.FListTableModel model; // table model private final BasicStroke stroke = new BasicStroke(BasicStroke.JOIN_ROUND); private static final String prefix_msg = AnLocale.getString("Non-Zero-Metric item at: "); private final String updateView = AnLocale.getString("Updating the view"); // Menu actions public static final String STR_ACTION_NEXT_HOT_LINE = AnLocale.getString("Next Hot Line"); public static final String STR_ACTION_NEXT_NZ_LINE = AnLocale.getString("Next Non-zero Metric Line"); public static final String STR_ACTION_PREV_HOT_LINE = AnLocale.getString("Previous Hot Line"); public static final String STR_ACTION_PREV_NZ_LINE = AnLocale.getString("Previous Non-zero Metric Line"); public static final String STR_ACTION_SHOW_NZ_LINE = AnLocale.getString("Show Non-zero Metric Line"); public static final String STR_ACTION_HIDE_NZ_LINE = AnLocale.getString("Hide Non-zero Metric Line"); /** Creates hot rects panel */ public AnHotGap(FuncListDisp disp, int headerHeight) { init(disp, disp.table, headerHeight); } public AnHotGap(final FuncListDisp disp, final AnTable table, int headerHeight) { init(disp, table, headerHeight); } private void init(final FuncListDisp disp, AnTable table, int headerHeight) { this.disp = disp; this.table = table; table.gap = this; model = table.getTableModel(); setLayout(new java.awt.GridLayout()); java.awt.Dimension dim = new java.awt.Dimension(HOTGAP_WIDTH, table.getPreferredSize().height - headerHeight); setPreferredSize(dim); dim = new java.awt.Dimension(HOTGAP_WIDTH, table.getMaximumSize().height - headerHeight); setMaximumSize(dim); dim = new java.awt.Dimension(HOTGAP_WIDTH, table.getMinimumSize().height - headerHeight); setMinimumSize(dim); addMouseMotionListener(this); addMouseListener(this); tm = ToolTipManager.sharedInstance(); tm.registerComponent(this); // Popup menu menuListener = new AnMenuListener(); this.addMouseListener(menuListener); } /** Updates hot rects panel and sets required flags and variables */ public void update() { synchronized (updateView) { row_count = model.getRowCount(); if (row_count == 0) { hots_count = 0; repaint(); return; } if (show_warm_lines) { warm_lines = new Vector(); for (int i = 0; i < row_count; i++) { int mcc = model.getColumnCount(); int j, k = model.getNameCol(); String s; for (j = 0; j < mcc; j++) { if (j == k) { continue; } s = (String) model.getValueAt(i, j).toString(); if (s.matches(".*[1-9].*")) { warm_lines.add(new Integer(i)); break; } } } warm_lines_count = warm_lines.size(); } else { warm_lines_count = 0; } hots = new Vector(); for (int i = 0; i < row_count; i++) { int j; if ((j = model.getSrcType(i)) < 0) { hots.add(new Integer(i)); } } hots_count = hots.size(); repaint(); } } /** Paints this component. */ @Override protected void paintComponent(final Graphics g) { update(g); } /** * Updates this component. * * @param g the specified context to use for updating * @see #paint * @see #repaint() */ @Override public void update(final Graphics g) { synchronized (updateView) { double y; int line; int line_height = 0; final Graphics2D g2 = (Graphics2D) g; // Clean old markers java.awt.Dimension dim = getSize(); r = new Rectangle(0, 0, dim.height, dim.height); g2.setPaint(java.awt.Color.WHITE /* AnVariable.BG_COLOR */); g2.fill(r); g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_SPEED); if ((hots_count == 0) && (warm_lines_count == 0)) { return; } double gap_height = table.getVerticalScrollBar().getSize().height - 2 * height_adjustment - handle_adjustment; double inc = (gap_height / row_count); double rowHeight = table.getRowHeight(); if (inc > rowHeight) { gap_height = gap_height * rowHeight / inc; inc = rowHeight; } // Calculate minimum line height if (row_count > 0) { line_height = (dim.height / row_count); } vect = new Vector(hots_count + warm_lines_count); int addRow = 0; Rectangle2D.Double cur_rect_warm = null; int current_line = table.getSelectedRow(); for (int i = 0; i < warm_lines_count; i++) { line = ((Integer) warm_lines.get(i)).intValue(); y = addRow + height_adjustment + inc * line; rect = new java.awt.geom.Rectangle2D.Double(x_left, y, box_width, box_height); g2.setPaint(AnVariable.WARMLINE_COLOR); g2.setStroke(stroke); g2.draw(rect); g2.fill(rect); r = rect.getBounds(); r = new Rectangle(r.x, r.y, r.width + 2, r.height + 1); vect.add(new RectData(r, line)); // Highlight current line if (line == current_line) { // rect = new java.awt.geom.Rectangle2D.Double(x_left-4, y, box_width/2+4, box_height+2); rect_shadow = new java.awt.geom.Rectangle2D.Double( x_left - 1, y - 1, box_width + 2, box_height + 2); cur_rect_warm = rect; } } Rectangle2D.Double cur_rect_hot = null; for (int i = 0; i < hots_count; i++) { line = ((Integer) hots.get(i)).intValue(); y = addRow + height_adjustment + inc * line; rect = new java.awt.geom.Rectangle2D.Double(x_left, y, box_width, box_height); g2.setPaint(AnVariable.HOTLINE_COLOR); g2.setStroke(stroke); g2.draw(rect); g2.fill(rect); r = rect.getBounds(); r = new Rectangle(r.x, r.y, r.width + 2, r.height + 1); vect.add(new RectData(r, line)); // , model.getSrcLine(line))); // Highlight current line if (line == current_line) { // rect = new java.awt.geom.Rectangle2D.Double(x_left-4, y, box_width/2+4, box_height+2); rect_shadow = new java.awt.geom.Rectangle2D.Double( x_left - 1, y - 1, box_width + 2, box_height + 2); cur_rect_hot = rect; } } if (cur_rect_warm != null) { g2.setPaint(Color.BLACK); g2.draw(rect_shadow); g2.fill(rect_shadow); g2.setPaint(AnVariable.WARMLINE_COLOR); g2.setStroke(stroke); g2.draw(cur_rect_warm); g2.fill(cur_rect_warm); } if (cur_rect_hot != null) { g2.setPaint(Color.BLACK); g2.draw(rect_shadow); g2.fill(rect_shadow); g2.setPaint(AnVariable.HOTLINE_COLOR); g2.setStroke(stroke); g2.draw(cur_rect_hot); g2.fill(cur_rect_hot); } } } private void goToLine(int line) { disp.goToLine(table, line); update(); } /** * Returns hot line for the current hot rect * * @return current hot line */ private int getLine() { return curr_line; } /** * Checks selected point if that is from hot rect and sets approproiate flags and vars * * @param p point being checked * @return <code>true</code> if point belongs hot rect */ private boolean checkRect(final Point p) { isHotRect = false; curr_line = 0; final int size = vect.size(); if (size == 0) { return false; } RectData data; Vector<Integer> candidates = new Vector<Integer>(); for (int i = 0; i < size; i++) { data = (RectData) vect.get(i); if (data.getRect().contains(p)) { candidates.add(i); } } for (int i = 0; i < candidates.size(); i++) { data = (RectData) vect.get(candidates.get(i)); for (int j = 0; j < hots_count; j++) { int line = ((Integer) hots.get(j)).intValue(); if (line == data.getLine()) { setText(data.getHint()); isHotRect = true; curr_line = data.getLine(); return true; } } } for (int i = 0; i < candidates.size(); i++) { data = (RectData) vect.get(candidates.get(i)); setText(data.getHint()); isHotRect = true; curr_line = data.getLine(); return true; } return false; } /** * Sets tooltip text for hot rects * * @param str tooltip text */ private void setText(final String str) { text = str; } /** * Returns tooltip text for hot rect (overrides method in <code>javax.swing.JComponent</code>) * * @param event Mouse event */ @Override public String getToolTipText(final MouseEvent event) { return text; } /** * Returns tooltip location for hot rect (overrides method in <code>javax.swing.JComponent</code>) * * @param event Mouse event */ @Override public Point getToolTipLocation(final MouseEvent event) { final Point p = event.getPoint(); if (getSize().getHeight() - p.getY() <= 25) { p.setLocation(0, p.y - (20 + box_height)); } else { p.setLocation(0, p.y + 15); } return p; } // This methods are required by MouseMotionListener. public void mouseMoved(final MouseEvent e) { synchronized (updateView) { final Point mp = e.getPoint(); if (vect == null) { return; } if (checkRect(mp)) { tm.setEnabled(true); this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); } else { tm.setEnabled(false); this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } } } public void mouseDragged(final MouseEvent e) {} // This methods are required by MouseListener. public void mouseClicked(final MouseEvent e) { if (!isHotRect) { return; } goToLine(getLine()); } public void mouseExited(final MouseEvent e) { tm.setEnabled(true); } public void mouseEntered(final MouseEvent e) {} public void mousePressed(final MouseEvent e) {} public void mouseReleased(final MouseEvent e) {} /** Inner class to represent hot rect data */ private final class RectData { private final Rectangle r; private final int line; /** * Constructor of hot rect data * * @param r hot rectangle * @param line hot line */ public RectData(final Rectangle r, final int line /*, final String hint*/) { this.r = r; this.line = line; } public Rectangle getRect() { return r; } public String getHint() { return prefix_msg + model.getSrcLine(line); } public int getLine() { return line; } } /** * Navigate in Hot Gap Possible actions: Next Hot Line - go to next Hot Line Next Non-zero Metric * Line - go to next Non-zero Metric Line Previous Hot Line - go to Previous Hot Line Previous * Non-zero Metric Line - got to Previous Non-zero Metric Line */ private void HG_Action(String actionName, ActionEvent ev) { if (actionName.equals(STR_ACTION_NEXT_HOT_LINE)) { HG_Next_Hot_Line(); } if (actionName.equals(STR_ACTION_NEXT_NZ_LINE)) { HG_Next_NZ_Line(); } if (actionName.equals(STR_ACTION_PREV_HOT_LINE)) { HG_Prev_Hot_Line(); } if (actionName.equals(STR_ACTION_PREV_NZ_LINE)) { HG_Prev_NZ_Line(); } if (actionName.equals(STR_ACTION_SHOW_NZ_LINE)) { show_warm_lines = true; update(); } if (actionName.equals(STR_ACTION_HIDE_NZ_LINE)) { show_warm_lines = false; update(); } } /** Navigate to Next Hot Line */ public void HG_Next_Hot_Line() { int current_line = table.getSelectedRow(); for (int i = 0; i < hots_count; i++) { int line = ((Integer) hots.get(i)).intValue(); if (current_line >= line) { continue; } goToLine(line); repaint(); break; } } /** Navigate to Previous Hot Line */ public void HG_Prev_Hot_Line() { int current_line = table.getSelectedRow(); for (int i = hots_count - 1; i >= 0; i--) { int line = ((Integer) hots.get(i)).intValue(); if (current_line <= line) { continue; } goToLine(line); repaint(); break; } } /** Navigate to Next Non-Zero Metric Line */ public void HG_Next_NZ_Line() { int next_hot_line = -1; int next_nz_line = -1; int current_line = table.getSelectedRow(); for (int i = 0; i < hots_count; i++) { int line = ((Integer) hots.get(i)).intValue(); if (current_line >= line) { continue; } next_hot_line = line; break; } for (int i = 0; i < warm_lines_count; i++) { int line = ((Integer) warm_lines.get(i)).intValue(); if (current_line >= line) { continue; } next_nz_line = line; break; } if ((next_hot_line < 0) && (next_nz_line < 0)) { return; } if (next_hot_line < 0) { next_hot_line = next_nz_line; } if (next_nz_line < 0) { next_nz_line = next_hot_line; } if (next_hot_line < next_nz_line) { next_nz_line = next_hot_line; } goToLine(next_nz_line); repaint(); } /** Navigate to Previous Non-Zero Metric Line */ public void HG_Prev_NZ_Line() { int next_hot_line = -1; int next_nz_line = -1; int current_line = table.getSelectedRow(); for (int i = hots_count - 1; i >= 0; i--) { int line = ((Integer) hots.get(i)).intValue(); if (current_line <= line) { continue; } next_hot_line = line; break; } for (int i = warm_lines_count - 1; i >= 0; i--) { int line = ((Integer) warm_lines.get(i)).intValue(); if (current_line <= line) { continue; } next_nz_line = line; break; } if ((next_hot_line < 0) && (next_nz_line < 0)) { return; } if (next_hot_line < 0) { next_hot_line = next_nz_line; } if (next_nz_line < 0) { next_nz_line = next_hot_line; } if (next_hot_line > next_nz_line) { next_nz_line = next_hot_line; } goToLine(next_nz_line); repaint(); } /** Is navigation to Next Hot Metric Line available? */ public boolean HG_Is_Next_Hot_Line() { int current_line = table.getSelectedRow(); for (int i = 0; i < hots_count; i++) { int line = ((Integer) hots.get(i)).intValue(); if (current_line >= line) { continue; } return true; } return false; } /** Is navigation to Previous Hot Metric Line available? */ public boolean HG_Is_Prev_Hot_Line() { int current_line = table.getSelectedRow(); for (int i = hots_count - 1; i >= 0; i--) { int line = ((Integer) hots.get(i)).intValue(); if (current_line <= line) { continue; } return true; } return false; } /** Is navigation to Next Non-Zero Metric Line available? */ public boolean HG_Is_Next_NZ_Line() { int next_hot_line = -1; int next_nz_line = -1; if (!show_warm_lines) { return false; } int current_line = table.getSelectedRow(); for (int i = 0; i < hots_count; i++) { int line = ((Integer) hots.get(i)).intValue(); if (current_line >= line) { continue; } next_hot_line = line; break; } for (int i = 0; i < warm_lines_count; i++) { int line = ((Integer) warm_lines.get(i)).intValue(); if (current_line >= line) { continue; } next_nz_line = line; break; } if ((next_hot_line < 0) && (next_nz_line < 0)) { return false; } return true; } /** Is navigation to Previous Non-Zero Metric Line available? */ public boolean HG_Is_Prev_NZ_Line() { int next_hot_line = -1; int next_nz_line = -1; if (!show_warm_lines) { return false; } int current_line = table.getSelectedRow(); for (int i = hots_count - 1; i >= 0; i--) { int line = ((Integer) hots.get(i)).intValue(); if (current_line <= line) { continue; } next_hot_line = line; break; } for (int i = warm_lines_count - 1; i >= 0; i--) { int line = ((Integer) warm_lines.get(i)).intValue(); if (current_line <= line) { continue; } next_nz_line = line; break; } if ((next_hot_line < 0) && (next_nz_line < 0)) { return false; } return true; } // ------- Private classes to implement popup menu items ------- // private class AnMenuListener extends MouseAdapter { private boolean debug; AnMenuListener() { debug = false; } public JPopupMenu initPopup(MouseEvent event) { return init_popup(); } public JPopupMenu init_popup() { AccessibleContext ac; JMenuItem mi; JPopupMenu popup = new JPopupMenu(); String txt; // Add "Previous Hot Line" action txt = STR_ACTION_PREV_HOT_LINE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(HG_Is_Prev_Hot_Line()); popup.add(mi); // Add "Next Hot Line" action txt = STR_ACTION_NEXT_HOT_LINE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(HG_Is_Next_Hot_Line()); popup.add(mi); // Add separator popup.addSeparator(); // Add "Previous Non-zero Metric Line" action txt = STR_ACTION_PREV_NZ_LINE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(HG_Is_Prev_NZ_Line()); popup.add(mi); // Add "Next Non-zero Metric Line" action txt = STR_ACTION_NEXT_NZ_LINE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(HG_Is_Next_NZ_Line()); popup.add(mi); // Add separator popup.addSeparator(); // Add "Show Non-zero Metric Line" action txt = STR_ACTION_SHOW_NZ_LINE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(!show_warm_lines); popup.add(mi); // Add "Hide Non-zero Metric Line" action txt = STR_ACTION_HIDE_NZ_LINE; mi = new JMenuItem(new UpdateAction(txt)); ac = mi.getAccessibleContext(); ac.setAccessibleDescription(txt); mi.setEnabled(show_warm_lines); popup.add(mi); return popup; } public void mousePressed(MouseEvent e) { maybeShowPopup(e); } public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { JPopupMenu popup = initPopup(e); if (popup != null) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeInvisible(" + e + ")"); } } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeVisible(" + e + ")"); } } public void popupMenuCanceled(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuCanceled(" + e + ")"); } } } /** Generic action for context menu items. Action name is passed as String. */ class UpdateAction extends AbstractAction { String actionName = null; public UpdateAction(String txt) { super(txt); actionName = txt; } @Override public void actionPerformed(ActionEvent ev) { HG_Action(actionName, ev); } } } ��������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/HeapView.java������������������������������������������������������0000644�0001750�0001750�00000112577�14517772113�016325� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.AnDisplay.DSP_Heap; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.statecolors.StackView; import org.gprofng.mpmt.statecolors.StackViewState; import org.gprofng.mpmt.statecolors.StateColorMap; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnSplitPaneInternal; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.util.ArrayList; import java.util.EventObject; import java.util.List; import java.util.Vector; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JViewport; import javax.swing.SwingUtilities; import javax.swing.border.LineBorder; import javax.swing.border.TitledBorder; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; public final class HeapView extends FuncListDisp implements AnListener, MouseListener, AdjustmentListener, ListSelectionListener, AnChangeListener { private boolean inCompute = false; // protected AnTable table; // Don't use your own local copy. Use the 'table' from // FuncListDisp. private JScrollPane errorPane = null; private Object[][] tableDataCalStk; private long[] dataCalStkIds = null; private JPanel statPanel; private AnJScrollPane statScrollPane; private String[][] statisticsData; private JComponent eventPane; private JComponent stackViewPane; private StackView stack_view; // Right-hand Tab's Event Stack Display private final StateColorMap clmap; private int stackRowId; private final int HEAPSIZE = 0; private final int ALLOC = 1; private final int LEAK = 2; private boolean updateIfNotSort; private StackView.StackViewPopupListener stackViewPopupListener; /** Keeps last warning to avoid showing the same warning message many times */ // Constructor public HeapView() { super(AnWindow.getInstance(), AnDisplay.DSP_Heap, 0, AnVariable.HELP_TabsHeap); clmap = window.getColorChooser().getColorMap(); clmap.addAnListener(this); initTab(); stackViewPopupListener = stack_view.new StackViewPopupListener(window); setAccessibility(AnLocale.getString("Heap")); AnEventManager.getInstance().addListener(this); updateIfNotSort = true; } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public JPanel getToolbarPanel() { return null; } private void initTab() { // Event Pane eventPane = new FocusPanel(); eventPane.setLayout(new BorderLayout()); TitledBorder titledBorder = new TitledBorder(AnLocale.getString("Heap Activity")); titledBorder.setBorder(new LineBorder(eventPane.getBackground())); // Event Pane: Call Stack stack_view = new StackView(clmap); stack_view.addMouseListener(this); stack_view.addListSelectionListener(this); stackViewPane = new JPanel(); stackViewPane.setBackground(Color.WHITE); stackViewPane.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(2, 2, 2, 2); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weighty = 1.0; gridBagConstraints.weightx = 1.0; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; stackViewPane.add(stack_view, gridBagConstraints); stackViewPane.setVisible(false); stackViewPane.revalidate(); stackViewPane.repaint(); eventPane.add(stackViewPane, BorderLayout.CENTER); eventPane.revalidate(); } class FocusPanel extends JPanel { @Override public void requestFocus() { if (stack_view != null) { stack_view.requestFocus(); } } } @Override public JPopupMenu getFilterPopup() { return table.initPopup(true); } // tab to populate right-side info area public JComponent getStackInfoTabComp() { return eventPane; } // name for tab in right-side info area public String getStackInfoTabName() { return AnLocale.getString("Call Stack - Heap"); } public JComponent getStackViewPane() { return stackViewPane; } @Override public void setSelected(final boolean set) { super.setSelected(set); // Show right pane if we get selected // if (set) { // window.showRightPane(); // } } // Initialize GUI components @Override protected void initComponents() { setLayout(new BorderLayout()); String acName = null; String acDesc = null; JLabel acLabel = null; acName = AnLocale.getString("HeapActivity"); acDesc = AnLocale.getString("Show heap activity for selected application"); if (acName != null) { acLabel = new JLabel(acName, JLabel.RIGHT); } table = new AnTable(type, true, true, can_sort, false, true, true, true, acName, acDesc, acLabel); table.setParent(this); if (acLabel != null) { acLabel.setVisible(false); // acLabel.setDisplayedMnemonic(acName.charAt(0)); table.add(acLabel); } table.addAnListener(new TableHandler()); statPanel = new JPanel(); statPanel.setLayout(new GridBagLayout()); statPanel.setBackground(Color.white); statScrollPane = new AnJScrollPane(statPanel); statScrollPane.setPreferredSize(new Dimension(100, 100)); JSplitPane sp = new AnSplitPaneInternal(JSplitPane.VERTICAL_SPLIT, table, statScrollPane); sp.setResizeWeight(.75); add(sp, BorderLayout.CENTER); } // Compute & update function list table @Override public void doCompute() { AnUtility.checkIfOnAWTThread(false); MetricLabel[] label; final String pwarnstr; // Not selected if (!selected) { return; } // XXXX show error when compare is on, needs simplified, // but the situation is different for different views if (window.getSettings().getCompareModeSetting().comparingExperiments()) { JLabel error_label = new JLabel(); error_label.setHorizontalAlignment(JLabel.CENTER); error_label.getAccessibleContext().setAccessibleName(AnLocale.getString("Error message")); error_label .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Error message")); JViewport error_view = new JViewport(); error_view.setView(error_label); String msg = AnLocale.getString("Not available when comparing experiments"); error_label.setText(msg); if (errorPane == null) { errorPane = new AnJScrollPane(); add(errorPane, BorderLayout.CENTER); } errorPane.setViewportView(error_view); errorPane.setVisible(true); statScrollPane.setVisible(false); return; } if (errorPane != null) { errorPane.setVisible(false); } statScrollPane.setVisible(true); if (inCompute) { return; } else { inCompute = true; } int typeForPresentation = type; if (!computed) { // need re-compute reset(); tableDataCalStk = null; dataCalStkIds = null; stack_view.reset(); table.setViewport(); final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(type); Object[] raw_data_with_ids = window.getTableDataV2("MET_HEAP", "ALL", "HEAPCALLSTACK", "" + subtype, null); tableDataCalStk = localProcessData(mlist, raw_data_with_ids); dataCalStkIds = current_ids; if (updateIfNotSort) { statisticsData = getHeapStatistics(); AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { statPanel.removeAll(); displayStatisticsData(statisticsData); } }); } updateIfNotSort = true; names = getNames(type, 0); // IPC call, don't do on AWT AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { MetricLabel[] label = getSettings().getMetricsSetting().getLabel(tableDataCalStk, null, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); int sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); table.setData(label, tableDataCalStk, names, null, 0, name_col, sort_ind); table.setSelectedRow(stackRowId); table.showSelectedRow(); window.showSubview(window.getHeapCallStackSubview(), true); if (table.getTable().getColumnCount() == 1) { table.showMessage(new NoMetricsSelectedPanel(type)); inCompute = false; return; } } }); } // else if (!isUpdated()) { // Object[] gtm = getTotalMax(); // label = getSettings().getMetricsSetting().getLabel(table.getTableData(), gtm, // typeForPresentation, table); // // if (label != null) { // table.setLabel(label); // } // } AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { if (stackRowId >= dataCalStkIds.length) { stackRowId = dataCalStkIds.length - 1; } long id = dataCalStkIds[stackRowId]; int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_Heap); window.getSelectionManager().updateSelection(ids, DSP_Heap, subtype, 1); } updateStackView(id); } }); computed = true; // pstatstr = window.getMsg(AnUtility.PSTAT_MSG); pwarnstr = window.getMsg(AnUtility.PWARN_MSG); // if (pstatstr != null) { // window.appendLog(pstatstr); // } if (pwarnstr != null) { window.showProcessorWarning(pwarnstr); } inCompute = false; } public int getDisplayMode() { return DSP_Heap; } public long[] getSelectedIds(int selectedIndices[], int displayMode) { // FIXUP: REARCH long[] ids = null; if (selectedIndices.length >= 1) { ids = new long[selectedIndices.length]; for (int i = 0; i < selectedIndices.length; i++) { ids[i] = dataCalStkIds[selectedIndices[i]]; } } return ids; } private String exportStatisticsData(final String[][] raw_data) { if (raw_data == null) { return null; } StringBuilder strBuild = new StringBuilder(); strBuild.append("\n"); if (!AnWindow.getInstance().getFilters().anyFilters()) { strBuild.append(AnLocale.getString("Heap Data Statistics For <Total>")); strBuild.append("\n\n"); } else { strBuild.append(AnLocale.getString("Heap Data Statistics For <Total> (filters on)")); strBuild.append("\n\n"); } if (raw_data[HEAPSIZE].length > 1) { strBuild.append(raw_data[HEAPSIZE][0]); strBuild.append("\n"); for (int i = 1; i < raw_data[HEAPSIZE].length; i++) { strBuild.append(raw_data[HEAPSIZE][i]); strBuild.append("\t\t\t"); i++; strBuild.append(raw_data[HEAPSIZE][i]); strBuild.append("\n"); } strBuild.append("\n"); } if (raw_data[ALLOC].length > 1) { strBuild.append(raw_data[ALLOC][0]); strBuild.append("\n"); strBuild.append(AnLocale.getString("Allocation Size Range")); strBuild.append("\t\t"); strBuild.append(AnLocale.getString("Allocations")); strBuild.append("\n"); for (int i = 1; i < raw_data[ALLOC].length; i++) { if (raw_data[ALLOC][i].trim().indexOf('-') > 0) { strBuild.append(" "); } strBuild.append(raw_data[ALLOC][i]); if (raw_data[ALLOC][i].trim().indexOf('-') > 0) { strBuild.append("\t\t\t"); } else { strBuild.append("\t"); } i++; strBuild.append(raw_data[ALLOC][i]); strBuild.append("\n"); } strBuild.append("\n"); } if (raw_data[LEAK].length > 1) { strBuild.append(raw_data[LEAK][0]); strBuild.append("\n"); strBuild.append(AnLocale.getString("Leak Size Range")); strBuild.append("\t\t\t"); strBuild.append(AnLocale.getString("Leaks")); strBuild.append("\n"); for (int i = 1; i < raw_data[LEAK].length; i++) { if (raw_data[LEAK][i].trim().indexOf('-') > 0) { strBuild.append(" "); } strBuild.append(raw_data[LEAK][i]); if (raw_data[LEAK][i].trim().indexOf('-') > 0) { strBuild.append("\t\t\t"); } else { strBuild.append("\t\t"); } i++; strBuild.append(raw_data[LEAK][i]); strBuild.append("\n"); } strBuild.append("\n"); } return strBuild.toString(); } private void displayStatisticsData(final String[][] raw_data) { if (raw_data == null) { return; } GridBagConstraints gridBagConstraints = new GridBagConstraints(); Color color = new Color(240, 240, 240); if (!AnWindow.getInstance().getFilters().anyFilters()) { JLabel label = new JLabel(AnLocale.getString("Heap Data Statistics For <Total>")); label.setFont(table.getFont().deriveFont(Font.BOLD)); label.setOpaque(true); label.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets.left = 0; gridBagConstraints.insets.bottom = 10; statPanel.add(label, gridBagConstraints); } else { JLabel label = new JLabel(AnLocale.getString("Heap Data Statistics For <Total> (filters on)")); label.setFont(table.getFont().deriveFont(Font.BOLD)); label.setOpaque(true); label.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets.left = 0; gridBagConstraints.insets.bottom = 10; statPanel.add(label, gridBagConstraints); } gridBagConstraints.insets.bottom = 0; if (raw_data[HEAPSIZE].length > 1) { JPanel heapSizePanel = new JPanel(); heapSizePanel.setLayout(new GridBagLayout()); heapSizePanel.setBackground(Color.WHITE); GridBagConstraints gridBagConstraintsHeapSize = new GridBagConstraints(); JLabel label1 = new JLabel(raw_data[HEAPSIZE][0]); label1.setFont(table.getFont().deriveFont(Font.BOLD)); label1.setOpaque(true); label1.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.gridwidth = 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets.bottom = 0; gridBagConstraints.insets.top = 0; gridBagConstraints.insets.left = 0; statPanel.add(label1, gridBagConstraints); gridBagConstraintsHeapSize.gridwidth = 1; for (int i = 1; i < raw_data[HEAPSIZE].length; i++) { JLabel label2 = new JLabel(raw_data[HEAPSIZE][i]); label2.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsHeapSize.weightx = 1; gridBagConstraintsHeapSize.weighty = 0; gridBagConstraintsHeapSize.gridx = 0; gridBagConstraintsHeapSize.gridy = gridBagConstraintsHeapSize.gridy + 1; gridBagConstraintsHeapSize.anchor = GridBagConstraints.LINE_START; gridBagConstraintsHeapSize.fill = GridBagConstraints.NONE; gridBagConstraintsHeapSize.insets.left = 0; heapSizePanel.add(label2, gridBagConstraintsHeapSize); i++; JLabel label3 = new JLabel(raw_data[HEAPSIZE][i]); label3.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsHeapSize.weightx = 1; gridBagConstraintsHeapSize.weighty = 0; gridBagConstraintsHeapSize.gridx = gridBagConstraintsHeapSize.gridx + 1; gridBagConstraintsHeapSize.anchor = GridBagConstraints.LINE_START; gridBagConstraintsHeapSize.fill = GridBagConstraints.NONE; gridBagConstraintsHeapSize.insets.left = 170; heapSizePanel.add(label3, gridBagConstraintsHeapSize); } gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.REMAINDER; gridBagConstraints.insets.bottom = 10; statPanel.add(heapSizePanel, gridBagConstraints); } if (raw_data[ALLOC].length > 1) { JPanel allocPanel = new JPanel(); allocPanel.setLayout(new GridBagLayout()); allocPanel.setBackground(Color.WHITE); GridBagConstraints gridBagConstraintsAlloc = new GridBagConstraints(); JLabel label1 = new JLabel(raw_data[ALLOC][0]); label1.setFont(table.getFont().deriveFont(Font.BOLD)); label1.setOpaque(true); label1.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.gridwidth = 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets.bottom = 0; gridBagConstraints.insets.top = 0; gridBagConstraints.insets.left = 0; statPanel.add(label1, gridBagConstraints); gridBagConstraintsAlloc.gridwidth = 1; JLabel label2 = new JLabel(AnLocale.getString("Allocation Size Range")); label2.setFont(table.getFont().deriveFont(Font.BOLD)); gridBagConstraintsAlloc.weightx = 1; gridBagConstraintsAlloc.weighty = 0; gridBagConstraintsAlloc.gridx = 0; gridBagConstraintsAlloc.gridy = 1; gridBagConstraintsAlloc.anchor = GridBagConstraints.LINE_START; gridBagConstraintsAlloc.fill = GridBagConstraints.NONE; gridBagConstraintsAlloc.insets.bottom = 1; gridBagConstraintsAlloc.insets.top = 0; gridBagConstraintsAlloc.insets.left = 0; allocPanel.add(label2, gridBagConstraintsAlloc); JLabel label3 = new JLabel(AnLocale.getString("Allocations")); label3.setFont(table.getFont().deriveFont(Font.BOLD)); gridBagConstraintsAlloc.weightx = 1; gridBagConstraintsAlloc.weighty = 0; gridBagConstraintsAlloc.gridx = gridBagConstraintsAlloc.gridx + 1; gridBagConstraintsAlloc.gridy = 1; gridBagConstraintsAlloc.anchor = GridBagConstraints.LINE_START; gridBagConstraintsAlloc.fill = GridBagConstraints.NONE; gridBagConstraintsAlloc.insets.bottom = 1; gridBagConstraintsAlloc.insets.top = 0; gridBagConstraintsAlloc.insets.left = 120; allocPanel.add(label3, gridBagConstraintsAlloc); for (int i = 1; i < raw_data[ALLOC].length; i++) { JLabel label4 = new JLabel(raw_data[ALLOC][i]); label4.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsAlloc.weightx = 1; gridBagConstraintsAlloc.weighty = 0; gridBagConstraintsAlloc.gridx = 0; gridBagConstraintsAlloc.gridy = gridBagConstraintsAlloc.gridy + 1; gridBagConstraintsAlloc.anchor = GridBagConstraints.LINE_START; gridBagConstraintsAlloc.fill = GridBagConstraints.NONE; gridBagConstraintsAlloc.insets.bottom = 0; gridBagConstraintsAlloc.insets.top = 0; if (raw_data[ALLOC][i].trim().indexOf('-') > 0) { gridBagConstraintsAlloc.insets.left = 5; } else { gridBagConstraintsAlloc.insets.left = 0; } allocPanel.add(label4, gridBagConstraintsAlloc); i++; JLabel label5 = new JLabel(raw_data[ALLOC][i]); label5.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsAlloc.weightx = 1; gridBagConstraintsAlloc.weighty = 0; gridBagConstraintsAlloc.gridx = gridBagConstraintsAlloc.gridx + 1; gridBagConstraintsAlloc.anchor = GridBagConstraints.LINE_START; gridBagConstraintsAlloc.fill = GridBagConstraints.NONE; gridBagConstraintsAlloc.insets.left = 120; gridBagConstraintsAlloc.insets.bottom = 0; allocPanel.add(label5, gridBagConstraintsAlloc); } gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.REMAINDER; gridBagConstraints.insets.bottom = 10; statPanel.add(allocPanel, gridBagConstraints); } if (raw_data[LEAK].length > 1) { JPanel leakPanel = new JPanel(); leakPanel.setLayout(new GridBagLayout()); leakPanel.setBackground(Color.WHITE); GridBagConstraints gridBagConstraintsLeak = new GridBagConstraints(); JLabel label1 = new JLabel(raw_data[LEAK][0]); label1.setFont(table.getFont().deriveFont(Font.BOLD)); label1.setOpaque(true); label1.setBackground(color); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.gridwidth = 1; gridBagConstraints.insets.bottom = 0; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; statPanel.add(label1, gridBagConstraints); gridBagConstraintsLeak.gridwidth = 1; JLabel label2 = new JLabel(AnLocale.getString("Leak Size Range")); label2.setFont(table.getFont().deriveFont(Font.BOLD)); gridBagConstraintsLeak.weightx = 1; gridBagConstraintsLeak.weighty = 0; gridBagConstraintsLeak.gridx = 0; gridBagConstraintsLeak.gridy = 1; gridBagConstraintsLeak.anchor = GridBagConstraints.LINE_START; gridBagConstraintsLeak.fill = GridBagConstraints.NONE; gridBagConstraintsLeak.insets.bottom = 1; leakPanel.add(label2, gridBagConstraintsLeak); JLabel label3 = new JLabel(AnLocale.getString("Leaks")); label3.setFont(table.getFont().deriveFont(Font.BOLD)); gridBagConstraintsLeak.weightx = 1; gridBagConstraintsLeak.weighty = 0; gridBagConstraintsLeak.gridx = gridBagConstraintsLeak.gridx + 1; gridBagConstraintsLeak.gridy = 1; gridBagConstraintsLeak.anchor = GridBagConstraints.LINE_START; gridBagConstraintsLeak.fill = GridBagConstraints.NONE; gridBagConstraintsLeak.insets.bottom = 1; gridBagConstraintsLeak.insets.left = 135; leakPanel.add(label3, gridBagConstraintsLeak); for (int i = 1; i < raw_data[LEAK].length; i++) { JLabel label4 = new JLabel(raw_data[LEAK][i]); label4.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsLeak.weightx = 1; gridBagConstraintsLeak.weighty = 0; gridBagConstraintsLeak.gridx = 0; gridBagConstraintsLeak.gridy = gridBagConstraintsLeak.gridy + 1; gridBagConstraintsLeak.anchor = GridBagConstraints.LINE_START; gridBagConstraintsLeak.fill = GridBagConstraints.NONE; gridBagConstraintsLeak.insets.bottom = 0; gridBagConstraintsLeak.insets.top = 0; if (raw_data[LEAK][i].trim().indexOf('-') > 0) { gridBagConstraintsLeak.insets.left = 5; } else { gridBagConstraintsLeak.insets.left = 0; } leakPanel.add(label4, gridBagConstraintsLeak); i++; JLabel label5 = new JLabel(raw_data[LEAK][i]); label5.setFont(table.getFont().deriveFont(Font.PLAIN)); gridBagConstraintsLeak.weightx = 1; gridBagConstraintsLeak.weighty = 0; gridBagConstraintsLeak.gridx = gridBagConstraintsLeak.gridx + 1; gridBagConstraintsLeak.anchor = GridBagConstraints.LINE_START; gridBagConstraintsLeak.fill = GridBagConstraints.NONE; gridBagConstraintsLeak.insets.left = 135; gridBagConstraintsLeak.insets.bottom = 0; leakPanel.add(label5, gridBagConstraintsLeak); } gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.REMAINDER; gridBagConstraints.insets.bottom = 10; statPanel.add(leakPanel, gridBagConstraints); } // The last component. It will push everything up. JLabel label = new JLabel(""); gridBagConstraints.weightx = 1; gridBagConstraints.weighty = 1; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridBagConstraints.gridy + 1; gridBagConstraints.anchor = GridBagConstraints.FIRST_LINE_START; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; statPanel.add(label, gridBagConstraints); statPanel.invalidate(); statPanel.validate(); statPanel.repaint(); } public void updateStackView(long stackId) { if (stackId == 0 /*null*/) { stack_view.reset(); // update stack in right-hand tab return; // Request for details about uninstrumented code is not supported yet. } AnUtility.checkIPCOnWrongThread(false); long[] pcs = window.getStackPCs(stackId); // IPC! String[] pcnames = window.getStackNames(stackId); // IPC! long[] funcs = window.getStackFunctions(stackId); // IPC! String[] fnames = window.getFuncNames(funcs); // IPC! AnUtility.checkIPCOnWrongThread(true); Vector<StackState> state_vec = new Vector<StackState>(); int i; for (i = 0; i < funcs.length; i++) { StackViewState svstate = new StackViewState(fnames[i], pcnames[i], funcs[i], pcs[i]); state_vec.add(svstate); } final int selected_frame = funcs.length - 1; clmap.addStates(state_vec); stack_view.setStates(state_vec, selected_frame); // update stack in right-hand tab stack_view.setStackId(stackId); stackViewPane.setVisible(true); stackViewPane.revalidate(); AnWindow.getInstance().setSubviewReadyToShow("heapCallStackSubview", true); } // Listener for updating table private final class TableHandler implements AnListener { @Override public void valueChanged(final AnEvent event) { switch (event.getType()) { case AnEvent.EVT_SELECT: // Selecting stackRowId = event.getValue(); computed = false; AnUtility.dispatchOnSwingThread( new Runnable() { // @Override @Override public void run() { long id = dataCalStkIds[stackRowId]; int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, DSP_Heap); window.getSelectionManager().updateSelection(ids, DSP_Heap, subtype, 1); } updateStackView(id); } }); break; case AnEvent.EVT_SORT: // Sorting // save current scroll location updateIfNotSort = false; getSettings() .getMetricsSetting() .setSortMetricByDType(this, ((Integer) event.getAux()).intValue(), type); break; case AnEvent.EVT_COPY_ALL: // Copy all lines copyAll(); break; case AnEvent.EVT_COPY_SEL: // Copy selected lines copySelected(); break; case AnEvent.EVT_SWITCH: // Column switching if (table != null) { table.columnsSaved = false; } int from = event.getValue(); int to = ((Integer) event.getAux()).intValue(); getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, type); break; case AnEvent.EVT_UPDATE: // setUpdated(false); break; case AnEvent.EVT_COMPUTE: computed = false; break; } } } // color change(s) @Override public void valueChanged(AnEvent e) { // setUpdated(false); stack_view.repaint(); } // Set selected function private void updateSummary(final StackState tmpstate) { if (!(tmpstate instanceof StackViewState)) { System.err.println("XXXmpview heapactivitydisp: not StackViewState"); return; } StackViewState state = (StackViewState) tmpstate; final long sel_func; final long sel_pc; sel_func = state.getNumber(); sel_pc = state.getPC(); long sel_obj = window.getSelectedObject().getObject(sel_func, sel_pc); if (sel_obj != 0L) { window.getSelectedObject().setSelObj(sel_obj, AnDisplay.DSP_Heap, 0); // lazy computing may be needed for if Summary is not been selected if (window.getViews().getCurrentViewDisplay() == window.getHeapView()) { int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, getDisplayMode()); window.getSelectionManager().updateSelection(ids, getDisplayMode(), 0, 1); } } else { AnWindow.getInstance() .getViews() .getCurrentViewDisplay() .computeOnAWorkerThread(); // Update selection. FIXUP: Views that react on selections // should change selction on SELECTION_CHANGED or // SELECTED_OBJECT_CHANGED events if not from own view } } } @Override public void adjustmentValueChanged(final AdjustmentEvent e) { revalidate(); } @Override public void mouseClicked(final MouseEvent event) { if (SwingUtilities.isLeftMouseButton(event)) { funcChanged(event); } if (SwingUtilities.isRightMouseButton(event)) { stackViewPopupListener.maybeShowPopup(event); } } @Override public void mouseEntered(final MouseEvent event) {} @Override public void mouseExited(final MouseEvent event) {} @Override public void mousePressed(final MouseEvent event) {} @Override public void mouseReleased(final MouseEvent event) {} // Will be needed if I want to update summary tab based on selection @Override public void valueChanged(final ListSelectionEvent event) { funcChanged(event); } // (MUST BE CALLED ON AWT THREAD) public void funcChanged(EventObject event) { final JList list; StackState state = null; if (event instanceof MouseEvent) { if (window.getColorChooser().isVisible()) { window.getColorChooser().setVisible(true); } if (((MouseEvent) event).getClickCount() > 1) { window.setSelectedView(AnDisplay.DSP_Source); } } else { if (window.getColorChooser().isVisible()) { window.getColorChooser().setVisible(true); } } if (event.getSource() instanceof StackView) { list = stack_view; state = (StackState) list.getSelectedValue(); } else { // XXXmpview, figure this out... // System.err.println("XXXmpview heapactivitydisp: eventsource unknown"); return; } if (state == null) { return; } stack_view.setSelectedFunction(state.getNumber()); // is this redundant? window.getColorChooser().setSelectedFunction(state.getNumber()); updateSummary(state); } @Override protected boolean supportsFindText() { return true; } // Find @Override public int find(final String str, final boolean next, boolean caseSensitive) { int find_row; if ((str == null) || (str.length() == 0)) { return -1; } find_row = table.findAfter(str, next, caseSensitive); if (find_row == -1) { find_row = table.findBefore(str, next, caseSensitive); } // Update summary display if (find_row != -1) { goToLine(table, find_row); } return find_row; } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String text = super.exportAsText(limit, format, delimiter); // exports the main table // Export lower panel if format is TEXT if (format == ExportFormat.TEXT && (limit == null || limit >= 0)) { statisticsData = getHeapStatistics(); text += exportStatisticsData(statisticsData); } return text; } // Native methods from liber_dbe.so private String[][] getHeapStatistics() { synchronized (IPC.lock) { window.IPC().send("getHeapStatistics"); window.IPC().send(0); return (String[][]) window.IPC().recvObject(); } } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); list.add(window.getHeapCallStackSubview()); return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); list.add(window.getHeapCallStackSubview()); return list; } @Override public void goToLine(final AnTable tbl, final int row) { tbl.setSelectedRow(row); int[] rows = table.getSelectedRows(); if (rows != null) { long[] ids = getSelectedIds(rows, getDisplayMode()); window.getSelectionManager().updateSelection(ids, getDisplayMode(), subtype, 1); long id = dataCalStkIds[row]; updateStackView(id); } } } ���������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnDouble.java������������������������������������������������������0000644�0001750�0001750�00000005472�14517772113�016301� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; // Analyzer Double object import static org.gprofng.mpmt.AnObject.format_group_decimal; import static org.gprofng.mpmt.AnObject.format_sdecimal; import static org.gprofng.mpmt.AnObject.zero_decimal; public final class AnDouble extends AnObject implements Comparable { private double value; private Double obj; // Constructor public AnDouble(double value) { this.value = value; obj = new Double(this.value); } // Analyzer Double printing format @Override public String toString() { if (value > 99.999 && xtimes.compareTo("") != 0) { return ">99.999" + xtimes; } if (value == 0.0) { return get_zero_decimal() + xtimes; } if (sign) { return format_sdecimal.format(value) + xtimes; } return format_decimal.format(value) + xtimes; } // Analyzer formatted printing format @Override public String toFormString() { if (value > 99.999 && xtimes.compareTo("") != 0) { return ">99.999" + xtimes; } if (value == 0.0) { if (showZero) { return zero_decimal + xtimes; } else { return quote_space + xtimes; } } if (sign) { return format_group_sdecimal.format(value) + xtimes; } return format_group_decimal.format(value) + xtimes; } // Percent printing @Override public String toPercent(double total) { if (value == 0.0) { if (showZero) { return zero_percent; } else { return quote_space; } } double percent = value * total; if (percent > 100.0) { percent = 100.0; } return format_percent.format(percent); } // To Double public Double toDouble() { return obj; } // To double @Override public double doubleValue() { return value; } // As Double.compareTo @Override public int compareTo(Object o) { return obj.compareTo(((AnDouble) o).toDouble()); } // Convert double[] to AnDouble[] public static AnDouble[] toArray(double[] list) { int length = list.length; AnDouble[] new_list = new AnDouble[length]; for (int i = 0; i < length; i++) { new_list[i] = new AnDouble(list[i]); } return new_list; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/��������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�015007� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/����������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�015574� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnMenuBar.java��������������������������������������������0000644�0001750�0001750�00000003145�14517772113�020154� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import javax.swing.JMenuBar; /** * @author tpreisle */ public class AnMenuBar extends JMenuBar { public AnMenuBar() { super(); AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Tabbed Pane")); } @Override protected void paintComponent(Graphics g) { int width = getWidth(); int height = getHeight(); Graphics2D g2d = (Graphics2D) g; GradientPaint gp; gp = new GradientPaint( 0, 0, AnEnvironment.MENUBAR_BACKGROUND_COLOR1, 0, height, AnEnvironment.MENUBAR_BACKGROUND_COLOR2); g2d.setPaint(gp); g2d.fillRect(0, 0, width, height); g.setColor(AnEnvironment.MENUBAR_BORDER_COLOR); g.drawLine(0, 0, width - 1, 0); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnDialog2.java��������������������������������������������0000644�0001750�0001750�00000011340�14517772113�020100� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.KeyboardShortcuts; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.Dialog; import java.awt.Font; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JPanel; import javax.swing.KeyStroke; public class AnDialog2 extends JDialog { private Font font = null; private AnDialogOuterPanel anDialogOuterPanel; public enum Status { OK, CANCEL }; private Status status = Status.CANCEL; private Component relativeToComponent; private boolean locationSet = false; public AnDialog2(Frame owner, Component relativeToComponent, String title) { super(owner, title); init(relativeToComponent); } public AnDialog2(Dialog owner, Component relativeToComponent, String title) { super(owner, title); init(relativeToComponent); } private void init(Component relativeToComponent) { this.relativeToComponent = relativeToComponent; setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); anDialogOuterPanel = new AnDialogOuterPanel(this); AnInsetsPanel anInsetsPanel = new AnInsetsPanel(anDialogOuterPanel, 12, 12, 12, 12); anInsetsPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); anDialogOuterPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); Container contentPane = getContentPane(); contentPane.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); contentPane.setLayout(new BorderLayout()); contentPane.add(anInsetsPanel, BorderLayout.CENTER); setModal(true); // close/dispose when ESC getRootPane() .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "esc"); // NOI18N getRootPane() .getActionMap() .put( "esc", new AbstractAction() { // NOI18N @Override public void actionPerformed(ActionEvent e) { setVisible(false); } }); pack(); } public void setCustomPanel(JPanel customPanel) { anDialogOuterPanel.setCustomPanel(customPanel); pack(); } public void addAuxButton(JButton auxButton) { anDialogOuterPanel.addAuxButton(auxButton); } public void setHelpTag(final String helpTag) { anDialogOuterPanel.setHelpTag(helpTag); if (helpTag != null) { // F1 help getRootPane() .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put( KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); // NOI18N getRootPane() .getActionMap() .put( KeyboardShortcuts.helpActionShortcut, new AbstractAction() { // NOI18N private final String helpId = helpTag; @Override public void actionPerformed(ActionEvent e) { Analyzer.showHelp(helpId); } }); } pack(); } /** * @return the status */ public Status getStatus() { return status; } /** * @param status the status to set */ protected void setStatus(Status status) { this.status = status; } public JButton getOKButton() { return anDialogOuterPanel.getOKButton(); } public JButton getCancelButton() { return anDialogOuterPanel.getCancelButton(); } public JButton getHelpButton() { return anDialogOuterPanel.getHelpButton(); } public Font getDialogFont() { if (font == null) { font = getFont().deriveFont(Font.PLAIN); } return font; } public void busyCursor(boolean set) { setCursor(set ? AnUtility.wait_cursor : AnUtility.norm_cursor); } @Override public void setVisible(boolean b) { if (b && !locationSet) { setLocationRelativeTo(relativeToComponent); locationSet = true; } super.setVisible(b); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnTextIcon.java�������������������������������������������0000644�0001750�0001750�00000002046�14517772113�020357� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import javax.swing.*; public final class AnTextIcon { private final String text; private final Icon icon; // Constructor public AnTextIcon(final String text, final Icon icon) { this.text = text; this.icon = icon; } // Get text public String getText() { return text; } // Get icon public Icon getIcon() { return icon; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnUtility.java��������������������������������������������0000644�0001750�0001750�00000125316�14517772113�020273� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.collect.CollectUtility; import org.gprofng.mpmt.metrics.MetricColors; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; import java.io.BufferedInputStream; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.WeakReference; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.accessibility.AccessibleContext; import javax.imageio.ImageIO; import javax.swing.BoundedRangeModel; import javax.swing.Icon; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; import javax.swing.event.MouseInputAdapter; public final class AnUtility { private static boolean checkIPCOnWrongThread = true; // Checks ony if true private static int checkIPCOnWrongThreadCounter = 0; // Checks only if counter == 0 private static final int TEXT_LEFT = 1; // public final static int TEXT_CENTER = 2; // public final static int TEXT_RIGHT = 3; public static final int ERROR_MSG = 1; public static final int WARNING_MSG = 2; public static final int PSTAT_MSG = 3; public static final int PWARN_MSG = 4; // mime types for files public static final int MIME_ELF_EXECUTABLE = 0x7f454c46; public static final int MIME_JAVA_CLASS_FILE = 0xcafebabe; public static final int MIME_JAR_FILE = 0x504b0304; private static final int MIME_UNKNOWN_FILE_TYPE = 0x00000000; public static final int MIME_CANNOT_READ_FILE = 0xFFFFFFFF; public static final Cursor norm_cursor = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR); public static final Cursor wait_cursor = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR); private static final String package_mpmt = "org/gprofng/mpmt/icons/"; // NOI18N private static final String green_bar_image = "green100.png"; // NOI18N // Icons public static final ImageIcon addColumnIcon = getImageIcon("addtablecolumns.png"); // NOI18N public static final ImageIcon add_icon = getImageIcon("add.png"); // NOI18N public static final ImageIcon appl_filt_icon = getImageIcon("apply_filter.png"); // NOI18N public static final ImageIcon attr_icon = getImageIcon("attributed.png"); // NOI18N public static final ImageIcon back_filt_icon = getImageIcon("back_filter.png"); // NOI18N public static final ImageIcon back_icon = getImageIcon("backward.png"); // NOI18N public static final ImageIcon blankIcon = getImageIcon("blank.png"); // NOI18N public static final ImageIcon bubble_icon = getImageIcon("bubble_icon_16.png"); // NOI18N public static final ImageIcon cale_icon = getImageIcon("callee.png"); // NOI18N public static final ImageIcon calr_icon = getImageIcon("caller.png"); // NOI18N public static final ImageIcon cls_icon = getImageIcon("class.png"); // NOI18N public static final ImageIcon collect_icon = getImageIcon("collect.png"); // NOI18N public static final ImageIcon colr_icon = getImageIcon("color.png"); // NOI18N public static final ImageIcon compare_icon = getImageIcon("compare.png"); // NOI18N public static final ImageIcon connect_icon = getImageIcon("connect.png"); // NOI18NNOI18N public static final ImageIcon data_icon = getImageIcon("data.png"); // NOI18N public static final ImageIcon del_icon = getImageIcon("delete.png"); // NOI18N public static final ImageIcon down_icon = getImageIcon("down.png"); // NOI18N public static final ImageIcon ebad_icon = getImageIcon("badexperiment.png"); // NOI18N public static final ImageIcon egrp_icon = getImageIcon("expgroup.png"); // NOI18N public static final ImageIcon elf_icon = getImageIcon("exe_elf.png"); // NOI18N public static final ImageIcon eold_icon = getImageIcon("oldexperiment.png"); // NOI18N public static final ImageIcon epcl_icon = getImageIcon("expandcollaps.png"); // NOI18N public static final ImageIcon circleBlueIcon = getImageIcon("circleBlue.gif"); // NOI18N public static final ImageIcon circleRedIcon = getImageIcon("circleRed.gif"); // NOI18NNOI18N public static final ImageIcon circleGreenIcon = getImageIcon("circleGreen.gif"); // NOI18N public static final ImageIcon circleOrangeIcon = getImageIcon("circleOrange.gif"); // NOI18N public static final ImageIcon ewarn_icon = getImageIcon("warnexperiment.png"); // NOI18N public static final ImageIcon excl_icon = getImageIcon("exclusive.png"); // NOI18N public static final ImageIcon expt_icon = getImageIcon("experiment.png"); // NOI18N public static final ImageIcon fileResolved = getImageIcon("fileResolved.png"); // NOI18N public static final ImageIcon fileUnResolved = getImageIcon("fileUnResolved.png"); // NOI18N public static final ImageIcon filt_icon = getImageIcon("filter.png"); // NOI18N public static final ImageIcon forw_icon = getImageIcon("forward.png"); // NOI18N public static final ImageIcon func_icon = getImageIcon("func_item.png"); // NOI18N public static final ImageIcon fwd_filt_icon = getImageIcon("forward_filter.png"); // NOI18N public static final ImageIcon gear_icon = getImageIcon("gear.png"); // NOI18N public static final ImageIcon goBackwardIcon = getImageIcon("gobackward.png"); // NOI18N public static final ImageIcon goDownIcon = getImageIcon("godown.png"); // NOI18N public static final ImageIcon goForwardIcon = getImageIcon("goforward.png"); // NOI18N public static final ImageIcon goUpIcon = getImageIcon("goup.png"); // NOI18N public static final ImageIcon hamburgerFocusedIcon = getImageIcon("hamburgerFocused.png"); // NOI18N public static final ImageIcon hamburgerIcon = getImageIcon("hamburger.png"); // NOI18N public static final ImageIcon hamburgerBlankIcon = getImageIcon("hamburgerBlank.png"); // NOI18N public static final ImageIcon heap_icon = getImageIcon("heaptrace.png"); // NOI18N public static final ImageIcon hollowArrowDownIcon = getImageIcon("hollowArrowDown.png"); // NOI18N public static final ImageIcon hollowArrowLeftIcon = getImageIcon("hollowArrowLeft.png"); // NOI18N public static final ImageIcon hollowArrowRightIcon = getImageIcon("hollowArrowRight.png"); // NOI18N public static final ImageIcon hollowArrowUpIcon = getImageIcon("hollowArrowUp.png"); // NOI18N public static final ImageIcon hot_icon = getImageIcon("hot.png"); // NOI18N public static final ImageIcon hwc_icon = getImageIcon("hwc.png"); // NOI18N public static final ImageIcon incl_icon = getImageIcon("inclusive.png"); // NOI18N public static final ImageIcon iotrace_icon = getImageIcon("i_o_usage_16.png"); // NOI18N public static final ImageIcon jar_icon = getImageIcon("jar.png"); // NOI18N public static final ImageIcon mpi_icon = getImageIcon("mpitrace.png"); // NOI18N public static final ImageIcon mtall_icon = getImageIcon("apply_mtrs.png"); // NOI18N public static final ImageIcon moreIcon = getImageIcon("more_icon.png"); // NOI18N public static final ImageIcon next_icon = getImageIcon("find_next.png"); // NOI18N public static final ImageIcon open_icon = getImageIcon("open.png"); // NOI18N public static final ImageIcon panhand_icon = getImageIcon("panhand.png"); // NOI18N public static final ImageIcon prev_icon = getImageIcon("find_prev.png"); // NOI18N public static final ImageIcon prof_icon = getImageIcon("profile.png"); // NOI18N public static final ImageIcon races_icon = getImageIcon("races.png"); // NOI18N public static final ImageIcon redo_icon = getImageIcon("redo.png"); // NOI18N public static final ImageIcon removeFocusedIcon = getImageIcon("removeFocused.png"); // NOI18N public static final ImageIcon removeIcon = getImageIcon("remove.png"); // NOI18N public static final ImageIcon removeIconBlank = getImageIcon("removeBlank.png"); // NOI18N public static final ImageIcon restore_icon = getImageIcon("stop.png"); // NOI18N public static final ImageIcon rset_icon = getImageIcon("reset.png"); // NOI18N public static final ImageIcon samp_icon = getImageIcon("sample.png"); // NOI18N public static final ImageIcon save_icon = getImageIcon("save.png"); // NOI18N public static final ImageIcon smallArrowBlankIcon = getImageIcon("smallBlank.png"); // NOI18N public static final ImageIcon smallArrowDownFocusedIcon = getImageIcon("small_down_focused.png"); // NOI18N public static final ImageIcon smallArrowUpFocusedIcon = getImageIcon("small_up_focused.png"); // NOI18N public static final ImageIcon smallArrowDownIcon = getImageIcon("small_down.png"); // NOI18N public static final ImageIcon smallArrowLeftIcon = getImageIcon("small_left.png"); // NOI18N public static final ImageIcon smallArrowRightIcon = getImageIcon("small_right.png"); // NOI18N public static final ImageIcon smallArrowUpIcon = getImageIcon("small_up.png"); // NOI18N public static final ImageIcon sodn_icon = getImageIcon("sort_dn.png"); // NOI18N public static final ImageIcon soup_icon = getImageIcon("sort_up.png"); // NOI18N public static final ImageIcon sync_icon = getImageIcon("synctrace.png"); // NOI18N public static final ImageIcon undo_icon = getImageIcon("undo.png"); // NOI18N public static final ImageIcon up_icon = getImageIcon("up.png"); // NOI18N public static final ImageIcon valuesIcon = getImageIcon("values.png"); // NOI18N public static final ImageIcon warningIcon = getImageIcon("warning.png"); // NOI18N public static final ImageIcon errorIcon = getImageIcon("error.png"); // NOI18N public static final ImageIcon warningNewIcon = getImageIcon("warningNew.png"); // NOI18N public static final ImageIcon errorNewIcon = getImageIcon("errorNew.png"); // NOI18N public static final ImageIcon errorWarningNewIcon = getImageIcon("errorWarningNew.png"); // NOI18N public static final ImageIcon zmin_icon = getImageIcon("zoom_in.png"); // NOI18N public static final ImageIcon zmot_icon = getImageIcon("zoom_out.png"); // NOI18N public static final ImageIcon numberIcon = getImageIcon("number.png"); // NOI18N public static final ImageIcon timeIcon = getImageIcon("time.png"); // NOI18N public static final ImageIcon percentIcon = getImageIcon("percent.png"); // NOI18N public static final ImageIcon nextViewIcon = getImageIcon("nextview.png"); // NOI18N public static final ImageIcon previousViewIcon = getImageIcon("previousview.png"); // NOI18N public static final ImageIcon base1Icon = getImageIcon("base1.png"); // NOI18N public static final ImageIcon base2Icon = getImageIcon("base2.png"); // NOI18N public static final ImageIcon compareAbsoluteIcon = getImageIcon("compareAbsolute.png"); // NOI18N public static final ImageIcon compareDeltaIcon = getImageIcon("compareDelta.png"); // NOI18N public static final ImageIcon compareRatioIcon = getImageIcon("compareRatio.png"); // NOI18N public static final ImageIcon compareReverseIcon = getImageIcon("compareReverse.png"); // NOI18N public static final ImageIcon compareHamburgerIcon = getImageIcon("compareHamburger.png"); // NOI18N // Other icons public static final ImageIcon analyzer_icon = getImageIcon("analyzer64.png"); // NOI18N private static final int chkbox_height = (new JLabel(" ")).getPreferredSize().height; // NOI18N; private static WeakReference wrEnv, wrSigMap; private static boolean lib_path_set = false; private static AnThreadGroup threadGroup = new AnThreadGroup(); public static int getMimeFormat(final File file) { try { if (!file.isFile()) { return MIME_UNKNOWN_FILE_TYPE; } final DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream(file))); int iMagicNumber = dis.readInt(); if (iMagicNumber == MIME_ELF_EXECUTABLE) { // reading elf header dis.skipBytes(12); final int elf_type = dis.readShort(); // check for elf executable if (elf_type != 0x0002 && elf_type != 0x0200) // Not MSB or LSB elf executable { iMagicNumber = MIME_UNKNOWN_FILE_TYPE; } } dis.close(); return iMagicNumber; } catch (IOException e) { return MIME_CANNOT_READ_FILE; } } public static boolean isTarget(final File file) { final int type = getMimeFormat(file); return (type == MIME_ELF_EXECUTABLE || type == MIME_JAVA_CLASS_FILE || type == MIME_JAR_FILE); } // General check box public static final class AnCheckBox extends JCheckBox { public AnCheckBox(final String text) { this(text, false); } public AnCheckBox(final String text, final boolean selected) { super(text, selected); final Dimension psize; setMargin(AnVariable.buttonMargin); setHorizontalAlignment(JCheckBox.CENTER); psize = getPreferredSize(); psize.height = chkbox_height; setPreferredSize(psize); setOpaque(false); if (text != null) { getAccessibleContext().setAccessibleDescription(text); getAccessibleContext().setAccessibleName(text); } } } public static final class AnRadioButton extends JRadioButton { public AnRadioButton() { super(); setOpaque(false); } public AnRadioButton(String text, boolean selected) { super(text, selected); setOpaque(false); getAccessibleContext().setAccessibleDescription(text); getAccessibleContext().setAccessibleName(text); } @Override public void paint(Graphics g) { super.paint(g); if (hasFocus() && getText().length() == 0) { // Accessibility g.setColor(new Color(194 - 40, 214 - 40, 233 - 40)); g.drawLine(getWidth() - 1, 4, getWidth() - 1, getHeight() - 5); } } } // General labels public static final class AnLabel extends JLabel { public AnLabel(final String text, final int alignment, final boolean init_a11y) { super(text, alignment); final float falignment; if (alignment == RIGHT) { falignment = RIGHT_ALIGNMENT; } else if (alignment == LEFT) { falignment = LEFT_ALIGNMENT; } else { falignment = CENTER_ALIGNMENT; } setAlignmentX(falignment); setForeground(AnVariable.LABEL_COLOR); setBorder(AnVariable.labelBorder); if (AnEnvironment.isLFNimbus()) { setFont(getFont().deriveFont(Font.BOLD)); } if (init_a11y) { initializeA11y(); } } public AnLabel( final String text, final Icon icon, final int alignment, final boolean init_a11y) { this(text, alignment, init_a11y); if (AnEnvironment.isLFNimbus()) { setFont(getFont().deriveFont(Font.BOLD)); } if (icon != null) { setIcon(icon); } } private void initializeA11y(final String accessibleName, final String accessibleDesc) { final AccessibleContext context = this.getAccessibleContext(); final String accName = (accessibleName != null && (!accessibleName.equals(""))) ? accessibleName : // NOI18N this.getText(); final String accDesc = (accessibleDesc != null && (!accessibleDesc.equals(""))) ? accessibleDesc : // NOI18N accName; context.setAccessibleName(accName); context.setAccessibleDescription(accDesc); } private void initializeA11y() { initializeA11y(this.getText(), this.getText()); } } // General textarea public static final class AnTextArea extends JTextArea { public AnTextArea(final String text, final boolean editable) { super(text); AnUtility.setAccessibleContext(this.getAccessibleContext(), ""); setBackground(CollectUtility.text_color); setEditable(editable); setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); setCaret( new javax.swing.text.DefaultCaret() { public void focusGained(final FocusEvent event) { if (getComponent().isEnabled()) { setVisible(true); } setSelectionVisible(true); // Don't use selectAll which will move Caret to the end. setCaretPosition(getDocument().getLength()); moveCaretPosition(0); } public void focusLost(final FocusEvent event) { super.focusLost(event); select(0, 0); } }); } } // General textfield public static final class AnText extends JTextField { int text_align; public AnText(final String text, final int columns, final int alignment) { super(text, columns); text_align = TEXT_LEFT; setFont(CollectUtility.text_font); setBackground(CollectUtility.text_color); if (AnEnvironment.isLFNimbus()) { setBackground(AnEnvironment.NIMBUS_PANEL_LIGHT_BACKGROUND); setBorder(null); } setEditable(false); setHorizontalAlignment(alignment); setCursor(Cursor.getPredefinedCursor(Cursor.TEXT_CURSOR)); this.getAccessibleContext().setAccessibleName(text); this.getAccessibleContext().setAccessibleDescription(text); setCaret( new javax.swing.text.DefaultCaret() { @Override public void focusGained(final FocusEvent event) { if (getComponent().isEnabled()) { setVisible(true); } setSelectionVisible(true); // Don't use selectAll which will move Caret to the end. if (text_align == TEXT_LEFT) { // This try/catch is an ugly workaround for fixing bug #5025668. // NPE caused because of java 1.4.2_02 DefaultCaret bug. // TODO: remove the workaround when java 1.5 becomes the default // one supported by analyzer. try { setDot(getDocument().getLength()); moveDot(0); } catch (NullPointerException npe) { /* do nothing; workaround*/ } } else { // Same code as selectAll setDot(0); moveDot(getDocument().getLength()); } } @Override public void focusLost(final FocusEvent event) { super.focusLost(event); setDot(text_align == TEXT_LEFT ? 0 : getDocument().getLength()); } }); } public void setVisibleAlign(final int text_align, final boolean delay) { this.text_align = text_align; if (delay) { setCaretPosition(text_align == TEXT_LEFT ? 0 : getDocument().getLength()); } else { // Don't use setCaretPosition which caused flash SwingUtilities.invokeLater( new Runnable() { @Override public void run() { BoundedRangeModel visibility; visibility = getHorizontalVisibility(); visibility.setValue( text_align == TEXT_LEFT ? visibility.getMinimum() : visibility.getMaximum()); } }); } } } public static JComponent getTextArea(final String text) { final AnTextArea text_area; text_area = new AnUtility.AnTextArea(text, false); text_area.setBorder(AnVariable.textBorder); return text_area; } public static JComponent getHeader(final String text) { return new AnLabel(text, JLabel.CENTER, true); } public static JComponent getHeader(final String text, final Icon icon) { return new AnLabel(text, icon, JLabel.CENTER, true); } public static JComponent getTitle(final String text) { return new AnLabel(text, JLabel.LEFT, true); } public static JComponent getTitle(final String text, final Icon icon) { return new AnLabel(text, icon, JLabel.LEFT, true); } public static JComponent getItem(final String text) { return new AnLabel(text, JLabel.RIGHT, true); } public static JComponent getText(final String text, final int columns) { return new AnText(text, columns == 0 ? 0 : columns + 2, JTextField.LEFT); } public static JComponent getNumber(final String text, final int columns) { return new AnText(text, columns == 0 ? 0 : columns + 2, JTextField.RIGHT); } // Class for button public static final class ResponseAction extends JButton { public ResponseAction( final String text, final Icon icon, final char mnemonic, final String tooltip, final Insets margin, final ActionListener listener) { super(text, icon); final AccessibleContext context = this.getAccessibleContext(); context.setAccessibleName(text); context.setAccessibleDescription(text); if (margin != null) { setMargin(AnVariable.buttonMargin); } if (mnemonic != '\0') { setMnemonic(mnemonic); } if (tooltip != null) { setToolTipText(tooltip); } if (text != null) { setActionCommand(text); } else if (tooltip != null) { setActionCommand(tooltip); } addActionListener(listener); } public ResponseAction( final Icon icon, final char mnemonic, final String tooltip, final ActionListener listener) { this(null, icon, mnemonic, tooltip, AnVariable.buttonMargin, listener); } public ResponseAction(final Icon icon, final String tooltip, final ActionListener listener) { this(null, icon, '\0', tooltip, AnVariable.buttonMargin, listener); } public ResponseAction( final Icon icon, final String tooltip, final String actionCommand, final ActionListener listener) { this(icon, tooltip, listener); setActionCommand(actionCommand); } public ResponseAction( final String text, final Icon icon, final char mnemonic, final ActionListener listener) { this(text, icon, mnemonic, null, AnVariable.buttonMargin, listener); } public ResponseAction(final String text, final char mnemonic, final ActionListener listener) { this(text, null, mnemonic, listener); } } // Get experiment list public static List<String> getExpList(final String[] args) { final List<String> exp_list = new ArrayList<String>(); final int size = args.length; for (int i = 0; i < size; i++) { List<String> list = getGroupList(args[i]); if (list.size() > 1) { exp_list.add(args[i]); } else { exp_list.addAll(list); } } return exp_list; } // Get experiment from group file public static List<String> getGroupList(String path) { String line; final List<String> exp_list = new ArrayList<String>(); BufferedReader br = null; try { br = new BufferedReader(new FileReader(path)); if (((line = br.readLine()) == null) || !line.equals("#analyzer experiment group")) // NOI18N { throw (new IOException()); } while ((line = br.readLine()) != null) { line = line.trim(); if (!line.startsWith("#") && !line.equals("")) // NOI18N { exp_list.add(line); } } } catch (IOException e) { if (path.endsWith("/")) // NOI18N { path = path.substring(0, path.length() - 1); } exp_list.add(path); } finally { try { if (br != null) { br.close(); } } catch (IOException e) { } } return exp_list; } // Get image from resource, from the default path public static ImageIcon getImageIcon(final String name) { final URL iconURL; iconURL = Analyzer.cls_loader.getResource(package_mpmt + name); if (iconURL == null) { return null; } else { return new ImageIcon(iconURL); } } /** * Get ImageIcon bar for specified metric * * @param metric - Use AnMetric.getComd() * @param width * @param height * @return ImageIcon */ public static ImageIcon getImageIconBar(String metric, int width, int height) { ImageIcon icon = null; BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = bi.createGraphics(); Color color = null; if (metric != null) { color = MetricColors.getColor(metric); } try { if (color == null) { // Read image final URL iconURL100 = Analyzer.cls_loader.getResource(package_mpmt + green_bar_image); BufferedImage in = ImageIO.read(iconURL100); g2.drawImage(in, 0, 0, null); } else { // Draw image g2.setColor(color); // g2.fill3DRect(0, 0, width, height, true /* raised */); g2.fillRect(0, 0, width, height); } g2.dispose(); } catch (Exception e) { return null; // cannot create } ; icon = new ImageIcon(bi); return icon; } // Remove the trailing new-line public static String trimNewLine(final String org) { int last; for (last = org.length() - 1; last >= 0; last--) { if (org.charAt(last) != '\n') // NOI18N { break; } } return org.substring(0, last + 1); } // Add the trailing new-line to the end of string if needed public static String addNewLine(final String org) { if (org.charAt(org.length() - 1) == '\n') { return org; } else { return new String(org + '\n'); } } // Find the class installed home location public static String findResourceHome(final ClassLoader loader, final String resource) { final URL url; final String file; String home; final int first, index; int last; if ((url = loader.getResource(resource)) == null) { return null; } file = url.getFile(); first = file.indexOf('/'); // NOI18N last = file.indexOf(".jar!", first); // NOI18N last = file.lastIndexOf('/', last); // NOI18N if ((first == -1) || (last == -1)) { try { home = (new File("../..")).getCanonicalPath(); // NOI18N } catch (IOException e) { home = "../.."; // NOI18N } } else { if ((index = file.lastIndexOf('/', last - 1)) != -1) // NOI18N { last = index; } home = file.substring(first, file.lastIndexOf('/', last - 1)); } return home; } // // Get Throwable stack trace // public static String getStackTrace(Throwable th) { // StringWriter str_writer; // // str_writer = new StringWriter(); // th.printStackTrace(new PrintWriter(str_writer)); // // return str_writer.toString(); // } // Add title in work area public static final JLabel setLabel(final JPanel panel, final String text) { final JComponent label; panel.add(label = AnUtility.getTitle(text), BorderLayout.NORTH); AccessibleContext context = panel.getAccessibleContext(); context.setAccessibleName(text); context.setAccessibleDescription(text); context = label.getAccessibleContext(); context.setAccessibleName(text); context.setAccessibleDescription(text); return (JLabel) label; } // Display dialog with message string public static void showMessage(final Component comp, final String msg, final int err_type) { if (msg != null) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { final String title; switch (err_type) { case JOptionPane.ERROR_MESSAGE: title = AnLocale.getString("Error"); // NOI18N break; case JOptionPane.WARNING_MESSAGE: title = AnLocale.getString("Warning"); // NOI18N break; case JOptionPane.INFORMATION_MESSAGE: title = AnLocale.getString("Information"); // NOI18N break; case JOptionPane.QUESTION_MESSAGE: title = AnLocale.getString("Question"); // NOI18N break; default: title = AnLocale.getString("Message"); // NOI18N break; } try { // XXX workaround for Swing bug 4254022 (fixed in JDK 1.6) // ie. don't display more than 500 lines in dialog box String message = msg; int count = 0; int ndx = 0; for (; ; ) { ndx = msg.indexOf('\n', ndx + 1); if (ndx < 0) { break; } count++; if (count > 500) { message = msg.substring(0, ndx + 1) + "..."; // NOI18N break; } } JOptionPane.showMessageDialog(comp, message, title, err_type); } catch (ArrayIndexOutOfBoundsException ae) { System.out.println("****Debug PROBLEM****IGNORING EXCP"); // NOI18N ae.printStackTrace(); } } }); } } // Returns numerical representation of the character signal value public static int getSignalValue(String signal) { int ret = -1; try { ret = Integer.parseInt(signal); } catch (NumberFormatException e) { Map sig_map = (wrSigMap == null) ? null : (Map) wrSigMap.get(); if (sig_map == null) { sig_map = new HashMap(100); sig_map.put("SIGHUP", 1); // NOI18N sig_map.put("SIGINT", 2); // NOI18N sig_map.put("SIGQUIT", 3); // NOI18N sig_map.put("SIGILL", 4); // NOI18N sig_map.put("SIGTRAP", 5); // NOI18N sig_map.put("SIGABRT", 6); // NOI18N sig_map.put("SIGIOT", 6); // NOI18N sig_map.put("SIGEMT", 7); // NOI18N sig_map.put("SIGFPE", 8); // NOI18N sig_map.put("SIGKILL", 9); // NOI18N sig_map.put("SIGBUS", 10); // NOI18N sig_map.put("SIGSEGV", 11); // NOI18N sig_map.put("SIGSYS", 12); // NOI18N sig_map.put("SIGPIPE", 13); // NOI18N sig_map.put("SIGALRM", 14); // NOI18N sig_map.put("SIGTERM", 15); // NOI18N sig_map.put("SIGUSR1", 16); // NOI18N - wrong number on Linux sig_map.put("SIGUSR2", 17); // NOI18N - wrong number on Linux sig_map.put("SIGCHLD", 18); // NOI18N sig_map.put("SIGCLD", 18); // NOI18N sig_map.put("SIGPWR", 19); // NOI18N sig_map.put("SIGWINCH", 20); // NOI18N sig_map.put("SIGURG", 21); // NOI18N sig_map.put("SIGIO", 22); // NOI18N sig_map.put("SIGSTOP", 23); // NOI18N sig_map.put("SIGTSTP", 24); // NOI18N sig_map.put("SIGCONT", 25); // NOI18N sig_map.put("SIGTTIN", 26); // NOI18N sig_map.put("SIGTTOU", 27); // NOI18N sig_map.put("SIGVTALRM", 28); // NOI18N sig_map.put("SIGPROF", 29); // NOI18N sig_map.put("SIGXCPU", 30); // NOI18N sig_map.put("SIGXFSZ", 31); // NOI18N wrSigMap = new WeakReference(sig_map); } signal = signal.trim(); if (!signal.startsWith("SIG")) { signal = "SIG" + signal; // NOI18N } ret = getSignalValueIPC(signal); if (ret > 0) { return ret; } final Integer obj = (Integer) sig_map.get(signal); if (obj != null) { ret = obj.intValue(); } } return ret; } public static void setLibPath() { if (!lib_path_set) { lib_path_set = true; } } /** Get the value of an environment variable */ public static String getenv(final String name) { return System.getenv(name); } // mouse enter/exit listener for buttons private static final MouseInputAdapter sharedMouseListener = new MouseInputAdapter() { @Override public void mouseEntered(MouseEvent evt) { JButton btn = (JButton) evt.getSource(); if (btn.isEnabled()) { btn.setBorderPainted(true); btn.setContentAreaFilled(true); } } @Override public void mouseExited(MouseEvent evt) { JButton btn = (JButton) evt.getSource(); if (btn.isEnabled()) { btn.setBorderPainted(false); btn.setContentAreaFilled(false); } } }; // set button look & feel to match mars IDE public static void setButtonLF(JButton button) { button.setBorderPainted(false); button.setContentAreaFilled(false); button.setFocusable(false); button.addMouseListener(sharedMouseListener); } public static String dirname(String path) { String name = path; int i = path.lastIndexOf("/"); // NOI18N if (i > 0) { name = path.substring(0, i); } return name; } public static String basename(String path) { String name = path; int i = path.lastIndexOf("/"); // NOI18N if (i >= 0 && i < (path.length() - 1)) { name = path.substring(i + 1); } return name; } public static void setAccessibleContext(AccessibleContext ac, String txt) { if (ac != null) { ac.setAccessibleName(txt); ac.setAccessibleDescription(txt); } } public static void setAccessibleContext(JLabel label) { setAccessibleContext(label.getAccessibleContext(), label.getText()); } public static void setTextAndAccessibleContext(JLabel label, String text) { label.setText(text); setAccessibleContext(label.getAccessibleContext(), text); } public static void setTextAndAccessibleContext(JCheckBox checkBox, String text) { checkBox.setText(text); setAccessibleContext(checkBox.getAccessibleContext(), text); } public static void setTextAndAccessibleContext(JButton button, String text) { button.setText(text); setAccessibleContext(button.getAccessibleContext(), text); } public static void setTTAndAccessibleContext(JComponent component, String text) { component.setToolTipText(text); setAccessibleContext(component.getAccessibleContext(), text); } /** * Dispatch a task to the AWT thread * * @param r */ public static void dispatchOnSwingThread(Runnable r) { if (SwingUtilities.isEventDispatchThread()) { r.run(); return; } try { SwingUtilities.invokeAndWait(r); } catch (Exception ex) { System.err.println("dispatchOnSwingThread exception: " + ex); // NOI18N ex.printStackTrace(); } } /** * Dispatch a task to the AWT thread * * @param r */ public static void invokeLaterOnSwingThread(Runnable r) { if (SwingUtilities.isEventDispatchThread()) { r.run(); } else { SwingUtilities.invokeLater(r); } } /** * Dispatch a task to a worker thread * * @param task * @param threadName */ public static Thread dispatchOnAWorkerThread(final Runnable task, String threadName) { final Thread worker; try { worker = new Thread(threadGroup, threadName) { @Override public void run() { task.run(); } }; worker.start(); return worker; } catch (Exception ex) { System.err.println("dispatchOnWorkerThread exception: " + ex); // NOI18N } return null; } private static class AnThreadGroup extends ThreadGroup { public AnThreadGroup() { super("analyzer_group"); // NOI18N } @Override public void uncaughtException(final Thread t, final Throwable e) { e.printStackTrace(); String tmp = e.getLocalizedMessage(); String msg = AnLocale.getString("Uncaught Exception: ") + e + '\n' + // NOI18N ((tmp == null) ? AnLocale.getString("gp-display-text exited due to internal error") + '\n' : "") + // NOI18N AnLocale.getString("Exception in thread ") + t.getName() + '.'; // NOI18N Analyzer.getInstance().endIPC(msg); } } public static boolean checkIfOnAWTThread(boolean shouldBe) { // FIXUP: enable after Beta boolean ok = true; if (SwingUtilities.isEventDispatchThread()) { if (!shouldBe) { reportWrongThread(shouldBe); ok = false; } } else if (shouldBe) { reportWrongThread(shouldBe); ok = false; } return ok; } private static void reportWrongThread(boolean shouldBe) { Exception awtException = new Exception(); StackTraceElement[] se = awtException.getStackTrace(); StringBuilder s = new StringBuilder(); String msg = shouldBe ? "Should be on AWT" : "Should not be on AWT"; s.append("*** Wrong Thread: " + msg + "\n"); s.append(Thread.currentThread().getName() + "\n"); for (int i = 0; i < se.length; i++) { s.append(se[i].toString() + "\n"); } AnLog.log(s.toString()); System.err.println( "analyzer: Invalid use of AWT thread. See log file: " + AnLog.getLogFilePath()); } public static void checkIPCOnWrongThread(boolean set) { if (set) { checkIPCOnWrongThreadCounter--; } else { checkIPCOnWrongThreadCounter++; } } public static boolean checkIPCOnWrongThread() { return checkIPCOnWrongThread && checkIPCOnWrongThreadCounter == 0; } public static String toFullPath(String path) { String ret = path; if (!path.startsWith("/")) { // NOI18N ret = Analyzer.getInstance().getWorkingDirectory() + "/" + path; // NOI18N } return ret; } public static String getShortString(String string, int maxLength) { int len = string.length(); if ((len - 1) <= maxLength) { return string; } else { return "..." + string.substring(len - maxLength); // NOI18N } } public static void copyDirectory(File fromDirectoryFile, File toDirectoryFile) throws IOException { if (fromDirectoryFile.exists() && fromDirectoryFile.isDirectory()) { if (!toDirectoryFile.exists()) { toDirectoryFile.mkdirs(); } String[] children = fromDirectoryFile.list(); for (String children1 : children) { File fromFile = new File(fromDirectoryFile, children1); File toFile = new File(toDirectoryFile, children1); if (fromFile.isDirectory()) { copyDirectory(fromFile, toFile); } else { copyFile(fromFile, toFile); } } } else { // FIXUP: do something reasonable } } public static void copyFile(File fromFile, File toFile) throws IOException { if (fromFile.exists() && !fromFile.isDirectory()) { InputStream inputStream = new FileInputStream(fromFile); OutputStream outputStream = new FileOutputStream(toFile); byte[] buffer = new byte[1024]; int nbytes; while ((nbytes = inputStream.read(buffer)) > 0) { outputStream.write(buffer, 0, nbytes); } inputStream.close(); outputStream.close(); } else { // FIXUP: do something reasonable } } public static String keyStrokeToStringFormatted(KeyStroke keyStroke) { return " (" + keyStrokeToString(keyStroke) + ")"; // NOI18N } /** Simple KeyStroke to String. Does not (yet) handle META, ALT modifiers and some other keys. */ public static String keyStrokeToString(KeyStroke keyStroke) { if (keyStroke == null) { return ""; } StringBuilder buf = new StringBuilder(); int modifiers = keyStroke.getModifiers(); if ((modifiers & InputEvent.CTRL_DOWN_MASK) != 0) { buf.append("Ctrl+"); // NOI18N } if ((modifiers & InputEvent.META_DOWN_MASK) != 0) { buf.append("Meta+"); // NOI18N } if ((modifiers & InputEvent.ALT_DOWN_MASK) != 0) { buf.append("Alt+"); // NOI18N } if ((modifiers & InputEvent.SHIFT_DOWN_MASK) != 0) { buf.append("Shift+"); // NOI18N } if (buf.length() > 0) { buf.deleteCharAt(buf.length() - 1); buf.append("-"); // NOI18N } int x = keyStroke.getKeyCode(); switch (x) { case KeyEvent.VK_F1: buf.append("F1"); break; case KeyEvent.VK_F2: buf.append("F2"); break; case KeyEvent.VK_F3: buf.append("F3"); break; case KeyEvent.VK_F4: buf.append("F4"); break; case KeyEvent.VK_F5: buf.append("F5"); break; case KeyEvent.VK_F6: buf.append("F6"); break; case KeyEvent.VK_F7: buf.append("F7"); break; case KeyEvent.VK_F8: buf.append("F8"); break; case KeyEvent.VK_F9: buf.append("F9"); break; case KeyEvent.VK_F10: buf.append("F10"); break; case KeyEvent.VK_F11: buf.append("F11"); break; case KeyEvent.VK_F12: buf.append("F21"); break; case KeyEvent.VK_UP: buf.append("Up"); break; case KeyEvent.VK_DOWN: buf.append("Down"); break; case KeyEvent.VK_LEFT: buf.append("Left"); break; case KeyEvent.VK_RIGHT: buf.append("Right"); break; case KeyEvent.VK_ENTER: buf.append("Enter"); break; case KeyEvent.VK_BACK_SPACE: buf.append("Backspace"); break; default: buf.append((char) (keyStroke.getKeyCode())); break; } return buf.toString(); } private static int getSignalValueIPC(final String signal) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getSignalValue"); // NOI18N anWindow.IPC().send(signal); return anWindow.IPC().recvInt(); } } public static String escapeSpecialHTMLCharacters(String s) { s = s.replace("&", "&"); // NOI18N s = s.replace("<", "<"); // NOI18N s = s.replace(">", ">"); // NOI18N s = s.replace("'", "'"); // NOI18N s = s.replace("\"", """); // NOI18N return s; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnDialogOuterPanel.java�����������������������������������0000644�0001750�0001750�00000014554�14517772113�022027� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.Analyzer; import java.awt.BorderLayout; import java.awt.GridBagConstraints; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.JButton; import javax.swing.JPanel; class AnDialogOuterPanel extends javax.swing.JPanel { private AnDialog2 dialog; private JPanel customPanel; private String helpTag; private int auxGridy = 0; public AnDialogOuterPanel(final AnDialog2 dialog) { this.dialog = dialog; initComponents(); helpButton.setVisible(false); panel.setLayout(new BorderLayout()); okButton.setText(AnLocale.getString("OK")); // NOI18N); // okButton.setMnemonic(AnLocale.getString('O', "EXPORT_DIALOG_OK_MN")); // NOI18N); okButton.setToolTipText(AnLocale.getString("OK")); // NOI18N); okButton.addActionListener( new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { dialog.setStatus(AnDialog2.Status.OK); dialog.setVisible(false); } }); cancelButton.setText(AnLocale.getString("Cancel")); // NOI18N); // cancelButton.setMnemonic(AnLocale.getString('C', "EXPORT_DIALOG_CANCEL_MN")); // // NOI18N); cancelButton.setToolTipText(AnLocale.getString("Cancel")); // NOI18N); cancelButton.addActionListener( new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { dialog.setStatus(AnDialog2.Status.CANCEL); dialog.setVisible(false); } }); helpButton.setText(AnLocale.getString("Help")); // NOI18N); helpButton.setMnemonic(AnLocale.getString('H', "EXPORT_DIALOG_HELP_MN")); // NOI18N); helpButton.setToolTipText(AnLocale.getString("Help")); // NOI18N); helpButton.addActionListener( new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { Analyzer.showHelp(helpTag); } }); dialog.getRootPane().setDefaultButton(okButton); // default action (Return key) } protected void setCustomPanel(JPanel customPanel) { this.customPanel = customPanel; panel.add(customPanel, BorderLayout.CENTER); } protected void setHelpTag(String helpTag) { this.helpTag = helpTag; helpButton.setVisible(helpTag != null); } protected JButton getOKButton() { return okButton; } protected JButton getCancelButton() { return cancelButton; } protected JButton getHelpButton() { return helpButton; } public void addAuxButton(JButton auxButton) { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(auxButton, gridBagConstraints); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; panel = new javax.swing.JPanel(); okButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); helpButton = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); javax.swing.GroupLayout panelLayout = new javax.swing.GroupLayout(panel); panel.setLayout(panelLayout); panelLayout.setHorizontalGroup( panelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 400, Short.MAX_VALUE)); panelLayout.setVerticalGroup( panelLayout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 266, Short.MAX_VALUE)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 5; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(panel, gridBagConstraints); okButton.setText("jButton1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(okButton, gridBagConstraints); cancelButton.setText("jButton2"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(8, 4, 0, 0); add(cancelButton, gridBagConstraints); helpButton.setText("jButton3"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(8, 4, 0, 0); add(helpButton, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton cancelButton; private javax.swing.JButton helpButton; private javax.swing.JButton okButton; private javax.swing.JPanel panel; // End of variables declaration//GEN-END:variables } ����������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/RainbowColorScale.java������������������������������������0000644�0001750�0001750�00000010011�14517772113�021702� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import java.awt.Color; /** * The RainbowColorScale maps a range of values to colors to use in a chart. The colors range from a * red for high values to green for moderate values to blue for low values. * * @author blewis */ public class RainbowColorScale { private static Color[] colors; private static final int MAX_RAINBOW_COLORS = 256; /** Instantiate a new RainbowColorScale object */ public RainbowColorScale() { initColors(); } /** Compute the colors */ void initColors() { if (colors != null) { return; } int height = MAX_RAINBOW_COLORS; if (height <= 0) { System.err.println("ERROR: RainbowColorScale.initColors(): height<=0, height=" + height); return; } Color colVector[] = new Color[height]; final double minr = 70.0, ming = 70.0, minb = 70.0; final double maxr = 255.0, maxg = 245.0, maxb = 250.0; final double medr = 220; double fr = maxr, fg = ming, fb = minb; int phase; double dstep; phase = 1; dstep = (maxg - ming) / (0.45 * height); // next: add green for 0.45 height for (int i = 0; i < height; i++) { Color c = new Color( new Double(fr).intValue(), new Double(fg).intValue(), new Double(fb).intValue()); int idx = height - i - 1; colVector[idx] = c; if (phase == 1) { // add green till we get to yellow fg += dstep; if (fg > maxg) { fg = maxg; phase++; dstep = (maxr - medr) / (0.1 * height); // next: subtract a little red for 0.1 } } else if (phase == 2) { // subtract red till yellow-green fr -= dstep; if (fr < medr) { fr = medr; phase++; dstep = (medr - minr) / (0.1 * height); // next: subtract remainder of red for 0.1 } } else if (phase == 3) { // subtract red till light green fr -= dstep; if (fr < minr) { fr = minr; phase++; dstep = (maxb - minb) / (0.25 * height); // next: add blue for 0.25 } } else if (phase == 4) { // add blue until full blue fb += dstep; fg -= dstep * 0.8; // start removing green if (fg < ming) { fg = ming; } fr -= dstep * 1.0; // continue removing red if (fr < 0.0) { fr = 0.0; } if (fb > maxb) { fb = maxb; phase++; // dstep // keep it the same, seems ok } } else if (phase == 5) { // intensify/darken the blue fr += dstep * 0.2; // add a bit of red fb -= dstep * 0.5; fg -= dstep * 0.8; // continue removing green if (fg < 0.0) { fg = 0.0; } } } colors = colVector; } /** Compute the color for a single value within a range */ public Color getColorForValue(long v, long start, long end) { int height = MAX_RAINBOW_COLORS; long length = end - start; if (start > end) { return Color.BLACK; } if (v < start || v > end) { return Color.BLACK; } if (length < 0) { return Color.BLACK; } if (length == 0) { return colors[0]; } double percent = (double) (v - start) / length; int i = (int) (percent * height); if (i < 0) { i = 0; } else if (i >= height) { i = height - 1; } Color c = colors[i]; return c; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnScrollBarUI.java����������������������������������������0000644�0001750�0001750�00000017010�14517772113�020740� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; import javax.swing.plaf.metal.MetalScrollBarUI; public class AnScrollBarUI extends MetalScrollBarUI { private static final int gap = 4; private Color backgroundColor; private static JComponent mouseInsideComponent = null; public static ComponentUI createUI(final JComponent c) { c.addMouseListener( new MouseListener() { @Override public void mouseEntered(MouseEvent e) { mouseInsideComponent = c; c.repaint(); } @Override public void mouseExited(MouseEvent e) { mouseInsideComponent = null; c.repaint(); } @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} }); return new AnScrollBarUI(); } @Override protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) { backgroundColor = g.getColor(); // Fill g.setColor(AnEnvironment.SCROLLBAR_TRACK_COLOR); g.fillRect(trackBounds.x, trackBounds.y, trackBounds.width, trackBounds.height); // Border g.setColor(AnEnvironment.SCROLLBAR_BORDER_COLOR); if (trackBounds.width < trackBounds.height) { g.drawLine(trackBounds.x, trackBounds.y, 0, trackBounds.height + 20); // Why 20 extra? } else { g.drawLine( trackBounds.x, trackBounds.y, trackBounds.width + 20, trackBounds.y); // Why 20 extra? } } @Override protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) { // Knob if (mouseInsideComponent == c) { g.setColor(AnEnvironment.SCROLLBAR_THUMB_FOCUSED_COLOR); } else { g.setColor(AnEnvironment.SCROLLBAR_THUMB_COLOR); } g.fillRect( thumbBounds.x + gap, thumbBounds.y + gap, thumbBounds.width - 2 * gap + 1, thumbBounds.height - 2 * gap + 1); // Round the corners // g.setColor(AnEnvironment.SCROLLBAR_TRACK_COLOR); g.setColor(backgroundColor); int x = thumbBounds.x; int y = thumbBounds.y; int width = thumbBounds.width - 2 * gap; int height = thumbBounds.height - 2 * gap; // More rounded corners // g.drawLine(x + gap, y + gap, x + gap + 1, y + gap); // g.drawLine(x + gap, y + gap, x + gap, y + gap + 1); // g.drawLine(x + gap + width - 2, y + gap, x + gap + width - 1, y + gap); // g.drawLine(x + gap + width - 1, y + gap, x + gap + width - 1, y + gap + 1); // g.drawLine(x + gap, y + gap + height - 2, x + gap, y + gap + height - 1); // g.drawLine(x + gap, y + gap + height - 1, x + gap + 1, y + gap + height - 1); // g.drawLine(x + gap + width - 2, y + gap + height - 1, x + gap + width - 1, y + gap + // height - 1); // g.drawLine(x + gap + width - 1, y + gap + height - 2, x + gap + width - 1, y + gap + // height - 1); // One pixel rounded corners g.drawLine(x + gap, y + gap, x + gap, y + gap); g.drawLine(x + gap + width, y + gap, x + gap + width, y + gap); g.drawLine(x + gap, y + gap + height, x + gap, y + gap + height); g.drawLine(x + gap + width, y + gap + height, x + gap + width, y + gap + height); } @Override protected JButton createDecreaseButton(int orientation) { JButton button = new Button(orientation); return button; } @Override protected JButton createIncreaseButton(int orientation) { JButton button = new Button(orientation); return button; } @Override protected Dimension getMinimumThumbSize() { return new Dimension(28, 28); } class Button extends JButton { private static final int buttonSize = 14; private int orientation; private boolean mouseInsideButton = false; public Button(int orientation) { this.orientation = orientation; setMaximumSize(new Dimension(buttonSize, buttonSize)); setMinimumSize(new Dimension(buttonSize, buttonSize)); setPreferredSize(new Dimension(buttonSize, buttonSize)); addMouseListener( new MouseListener() { @Override public void mouseEntered(MouseEvent e) { mouseInsideButton = true; } @Override public void mouseExited(MouseEvent e) { mouseInsideButton = false; } @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} }); } @Override public void paint(Graphics g) { int w = getWidth(); int h = getHeight(); // Fill the area with track color g.setColor(AnEnvironment.SCROLLBAR_TRACK_COLOR); g.fillRect(0, 0, w, h); // paint Increment/Decrement buttons if thumb is vivible Rectangle rec = getThumbBounds(); if (rec.height > 0) { if (mouseInsideButton) { g.setColor(AnEnvironment.SCROLLBAR_INC_DEC_FOCUSED_COLOR); } else { g.setColor(AnEnvironment.SCROLLBAR_INC_DEC_COLOR); } if (orientation == MetalScrollBarUI.NORTH) { g.drawLine(7, 4, 7, 4); g.drawLine(6, 5, 8, 5); g.drawLine(5, 6, 9, 6); g.drawLine(4, 7, 10, 7); g.setColor(AnEnvironment.SCROLLBAR_BORDER_COLOR); g.drawLine(0, 0, 0, h - 1); g.drawLine(0, h - 1, w, h - 1); } else if (orientation == MetalScrollBarUI.SOUTH) { g.drawLine(4, 5, 10, 5); g.drawLine(5, 6, 9, 6); g.drawLine(6, 7, 8, 7); g.drawLine(7, 8, 7, 8); g.setColor(AnEnvironment.SCROLLBAR_BORDER_COLOR); g.drawLine(0, 0, 0, h - 1); g.drawLine(0, 0, w, 0); g.drawLine(0, h - 1, w, h - 1); } else if (orientation == MetalScrollBarUI.WEST) { g.drawLine(4, 7, 4, 7); g.drawLine(5, 6, 5, 8); g.drawLine(6, 5, 6, 9); g.drawLine(7, 4, 7, 10); g.setColor(AnEnvironment.SCROLLBAR_BORDER_COLOR); g.drawLine(0, 0, w - 1, 0); g.drawLine(w - 1, 0, w - 1, h - 1); } else if (orientation == MetalScrollBarUI.EAST) { g.drawLine(5, 4, 5, 10); g.drawLine(6, 5, 6, 9); g.drawLine(7, 6, 7, 8); g.drawLine(8, 7, 8, 7); g.setColor(AnEnvironment.SCROLLBAR_BORDER_COLOR); g.drawLine(0, 0, w - 1, 0); g.drawLine(0, 0, 0, h - 1); g.drawLine(w - 1, 0, w - 1, h - 1); } } } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnJPanel.java���������������������������������������������0000644�0001750�0001750�00000002112�14517772113�017765� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import java.awt.LayoutManager; import javax.swing.JPanel; /* * Currently same as JPanel... */ public class AnJPanel extends JPanel { public AnJPanel() { super(); init(); } public AnJPanel(LayoutManager layout) { super(layout); init(); } private void init() { setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnJList.java����������������������������������������������0000644�0001750�0001750�00000001737�14517772113�017655� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import javax.swing.JList; public class AnJList extends JList { public AnJList() { super(); init(); } private void init() { if (AnEnvironment.isLFNimbus()) { setBackground(AnEnvironment.NIMBUS_LIST_BACKGROUND); } } } ���������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnJScrollPane.java����������������������������������������0000644�0001750�0001750�00000002453�14517772113�021000� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import java.awt.Component; import javax.swing.JScrollPane; import javax.swing.border.LineBorder; public class AnJScrollPane extends JScrollPane { public AnJScrollPane() { super(); init(); } public AnJScrollPane(Component view) { super(view); init(); } public AnJScrollPane(Component view, int vsbPolicy, int hsbPolicy) { super(view, vsbPolicy, hsbPolicy); init(); } private void init() { getViewport().setBackground(AnEnvironment.SCROLLPANE_BACKGROUND); setBorder(new LineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR, 0)); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnCheckBox.java�������������������������������������������0000644�0001750�0001750�00000003073�14517772113�020311� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import java.awt.Color; import java.awt.Graphics; import java.awt.Insets; import javax.swing.JCheckBox; /** * @author tpreisle */ public class AnCheckBox extends JCheckBox { public AnCheckBox() { super(); init(); } public AnCheckBox(String text) { super(text); init(); } public AnCheckBox(String text, boolean selected) { super(text, selected); init(); } private void init() { setMargin(new Insets(0, 0, 0, 0)); setOpaque(false); } @Override public void paint(Graphics g) { if (isEnabled()) { super.paint(g); if (hasFocus() && getText().length() == 0) { // Accessibility g.setColor(new Color(194 - 40, 214 - 40, 233 - 40)); g.drawLine(getWidth() - 1, 2, getWidth() - 1, getHeight() - 3); } } else { g.setColor(new Color(230, 230, 230)); g.drawRect(2, 2, 12, 12); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnTabbedPaneUI.java���������������������������������������0000644�0001750�0001750�00000016725�14517772113�021056� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import javax.swing.JButton; import javax.swing.plaf.basic.BasicTabbedPaneUI; public class AnTabbedPaneUI extends BasicTabbedPaneUI { private static int tabHeight = -1; @Override protected void installDefaults() { super.installDefaults(); tabAreaInsets = new Insets(0, 0, 0, 0); tabInsets = new Insets(0, 0, 0, 1); TabbedPaneMouseListener mouseListener = new TabbedPaneMouseListener(); tabPane.addMouseListener(mouseListener); tabPane.addMouseMotionListener(mouseListener); } @Override protected JButton createScrollButton(int direction) { JButton button = super.createScrollButton( direction); // To change body of generated methods, choose Tools | Templates. button.getAccessibleContext().setAccessibleDescription(""); return button; } @Override protected Insets getContentBorderInsets(int tabPlacement) { return new Insets(0, 0, 0, 0); } @Override protected int calculateTabHeight(int tabPlacement, int tabIndex, int fontHeight) { return getTabHeight(); } @Override protected int calculateTabWidth(int tabPlacement, int tabIndex, FontMetrics metrics) { // Make the width 10 pixels wider. May have to make room for cancel image. return super.calculateTabWidth(tabPlacement, tabIndex, metrics) + 10; } @Override protected int calculateMaxTabHeight(int tabPlacement) { return getTabHeight(); } @Override protected void paintTabArea(Graphics g, int tabPlacement, int selectedIndex) { Color topColor = AnEnvironment.TABBED_PANE_TAB_AREA_TOP_COLOR; Color bottomColor = AnEnvironment.TABBED_PANE_TAB_AREA_BOTTOM_COLOR; Graphics2D g2d = (Graphics2D) g; GradientPaint gp = new GradientPaint(0, 0, topColor, 0, getTabHeight(), bottomColor); g2d.setPaint(gp); g2d.fillRect(0, 0, tabPane.getWidth(), getTabHeight()); super.paintTabArea(g, tabPlacement, selectedIndex); // g.setColor(AnEnvironment.TABBED_PANE_LINE_COLOR); // g.setColor(Color.red); // g.drawLine(0, getTabHeight() - 1, tabPane.getWidth() - 1, getTabHeight() - 1); // g.drawLine(0, getTabHeight() - 0, tabPane.getWidth() - 1, getTabHeight() - 0); } @Override protected void paintTabBackground( Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { Color topColor; Color bottomColor; if (isSelected) { topColor = AnEnvironment.TABBED_PANE_SELECTED_TAB_COLOR; bottomColor = AnEnvironment.TABBED_PANE_SELECTED_TAB_COLOR; } else if (getRolloverTab() == tabIndex) { topColor = AnEnvironment.TABBED_PANE_FOCUSED_TAB_TOP_COLOR; bottomColor = AnEnvironment.TABBED_PANE_FOCUSED_TAB_BOTTOM_COLOR; } else { topColor = AnEnvironment.TABBED_PANE_DESELECTED_TAB_TOP_COLOR; bottomColor = AnEnvironment.TABBED_PANE_DESELECTED_TAB_BOTTOM_COLOR; } Graphics2D g2d = (Graphics2D) g; GradientPaint gp = new GradientPaint(0, 0, topColor, 0, getTabHeight(), bottomColor); g2d.setPaint(gp); g2d.fillRect(x, 0, w, h); // g.setColor(AnEnvironment.TABBED_PANE_LINE_COLOR); // g.setColor(Color.red); // g.drawLine(x, h - 1, x + w - 1, h - 1); // g.drawLine(x, h - 0, x + w - 1, h - 0); } @Override protected void paintTabBorder( Graphics g, int tabPlacement, int tabIndex, int x, int y, int w, int h, boolean isSelected) { g.setColor(AnEnvironment.TABBED_PANE_DIVIDER_COLOR); g.drawLine(x + w - 1, 0, x + w - 1, h - 1); } @Override protected void paintContentBorderTopEdge( Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {} @Override protected void paintContentBorderRightEdge( Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {} @Override protected void paintContentBorderLeftEdge( Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {} // @Override @Override protected void paintContentBorderBottomEdge( Graphics g, int tabPlacement, int selectedIndex, int x, int y, int w, int h) {} @Override protected void paintText( Graphics g, int tabPlacement, Font font, FontMetrics metrics, int tabIndex, String title, Rectangle textRect, boolean isSelected) { if (!isSelected) { g.setFont(font); g.setColor(AnEnvironment.TABBED_PANE_DESELECTED_FORGROUND_COLOR); g.drawString(title, textRect.x, textRect.height - 2); } else { super.paintText(g, tabPlacement, font, metrics, tabIndex, title, textRect, isSelected); } } @Override protected void paintFocusIndicator( Graphics g, int tabPlacement, Rectangle[] rects, int tabIndex, Rectangle iconRect, Rectangle textRect, boolean isSelected) { // super.paintFocusIndicator(g, tabPlacement, rects, tabIndex, iconRect, textRect, // isSelected); Rectangle tabRect = rects[tabIndex]; if (tabPane.hasFocus() && isSelected) { int x, y, w, h; g.setColor(AnEnvironment.TABBED_PANE_TAB_FOCUS_COLOR); x = tabRect.x + 3; y = tabRect.y + 1; w = tabRect.width - 6; h = tabRect.height - 3; g.drawRect(x, y, w, h); } } @Override protected int getTabLabelShiftY(int tabPlacement, int tabIndex, boolean isSelected) { return 0; } private int getTabHeight() { if (tabHeight < 0) { tabHeight = tabPane.getFontMetrics(tabPane.getFont()).getHeight() + 2; } return tabHeight; } private int lastRoolOverTab = -1; private class TabbedPaneMouseListener implements MouseListener, MouseMotionListener { @Override public void mouseExited(MouseEvent e) { repaint(); lastRoolOverTab = -1; } @Override public void mouseMoved(MouseEvent e) { if (lastRoolOverTab != getRolloverTab()) { repaint(); lastRoolOverTab = getRolloverTab(); } } @Override public void mouseEntered(MouseEvent e) { if (lastRoolOverTab != getRolloverTab()) { repaint(); lastRoolOverTab = getRolloverTab(); } } @Override public void mouseClicked(MouseEvent e) {} @Override public void mouseDragged(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} private void repaint() { tabPane.repaint(new Rectangle(0, 0, tabPane.getWidth(), getTabHeight() - 1)); } } } �������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/ToolTipPopup.java�����������������������������������������0000644�0001750�0001750�00000013002�14517772113�020753� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import java.awt.Component; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Point; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.Popup; import javax.swing.PopupFactory; public class ToolTipPopup { public enum Location { NORTH, NORTHEAST, EAST, CENTER }; private Popup tooltipPopup = null; private final Component parent; private final Component component; private final Location location; private final boolean bubble; private JPanel panel = null; public ToolTipPopup(Component parent, Component component, Location location, boolean bubble) { this.parent = parent; this.component = component; this.location = location; this.bubble = bubble; } private JPanel getPanel() { if (panel == null) { panel = new JPanel(); panel.setBackground(AnEnvironment.TOOLTIP_POPUP_BACKGROUND_COLOR); panel.setBorder(BorderFactory.createLineBorder(AnEnvironment.TOOLTIP_POPUP_BORDER_COLOR, 1)); panel.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints; if (bubble) { JLabel iconLabel = new JLabel(AnUtility.bubble_icon); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.insets = new Insets(8, 8, 8, 0); panel.add(iconLabel, gridBagConstraints); } gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 1; gridBagConstraints.insets = new Insets(8, 8, 8, 8); panel.add(component, gridBagConstraints); } return panel; } /** Show the dialog */ public void show() { if (tooltipPopup != null) { return; } if (!parent.isShowing()) { return; } Point locationOnScreen = parent.getLocationOnScreen(); int locationx = 0; int locationy = 0; if (null != location) switch (location) { case NORTH: locationx = locationOnScreen.x + parent.getSize().width / 2 - getPanel().getPreferredSize().width / 2; locationy = locationOnScreen.y - getPanel().getPreferredSize().height + 10; break; case NORTHEAST: locationx = locationOnScreen.x + parent.getSize().width - 1; locationy = locationOnScreen.y - getPanel().getPreferredSize().height + 1; break; case EAST: locationx = locationOnScreen.x + parent.getSize().width - 1; locationy = locationOnScreen.y + parent.getSize().height / 2 - getPanel().getPreferredSize().height / 2; break; case CENTER: locationx = locationOnScreen.x + parent.getSize().width / 2 - getPanel().getPreferredSize().width / 2; locationy = locationOnScreen.y + parent.getSize().height / 2 - getPanel().getPreferredSize().height / 2; break; default: assert false; break; } tooltipPopup = PopupFactory.getSharedInstance().getPopup(parent, getPanel(), locationx, locationy); tooltipPopup.show(); } /** hide the dialog */ public void hide() { if (tooltipPopup != null) { tooltipPopup.hide(); tooltipPopup = null; } } /** * show tooltip for ms milliseconds * * @param ms ms to show the dialog */ public void show(final int waitms, final int showms) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { try { Thread.sleep(waitms); } catch (InterruptedException ie) { } AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { show(); } }); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { try { Thread.sleep(showms); } catch (InterruptedException ie) { } AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { hide(); } }); } }, "tooltippopup2"); // NOI18N } }, "tooltippopup1"); // NOI18N } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnInsetsPanel.java����������������������������������������0000644�0001750�0001750�00000004412�14517772113�021046� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.JPanel; public class AnInsetsPanel extends javax.swing.JPanel { public AnInsetsPanel(JPanel panel, int n, int w, int s, int e) { initComponents(); setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.insets = new Insets(n, w, s, e); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(panel, gridBagConstraints); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 400, Short.MAX_VALUE)); layout.setVerticalGroup( layout .createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 300, Short.MAX_VALUE)); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/ActionTextField.java��������������������������������������0000644�0001750�0001750�00000014511�14517772113�021371� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.mpmt.AnLocale; import java.awt.Dimension; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Image; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import javax.swing.JTextField; /** * @author tpreisle */ public class ActionTextField extends JTextField implements MouseListener, MouseMotionListener { private String toolTipText = null; private String actionToolTipText = null; private String fullText = null; private String displayText = null; protected boolean focused = false; private static Image removeImage = null; private static Image removeImageFocused = null; private Image buttonImage = null; private static int removeImageWidth = 0; private static int removeImageHeight = 0; private static int removeImageXOffset = 2; private static int removeImageYOffset = 3; private ToolTipPopup tooltipPopup = null; public ActionTextField() { init(); } public ActionTextField(String text) { setText(text); init(); } private void init() { addMouseListener(this); addMouseMotionListener(this); } @Override public void setToolTipText(String text) { this.toolTipText = text; super.setToolTipText(text); // To change body of generated methods, choose Tools | Templates. } public void setActionToolTipText(String text) { this.actionToolTipText = text; } @Override public void setText(String text) { fullText = text; } @Override public void paint(Graphics g) { String newDisplayText = displayText(g, fullText); if (displayText == null || !displayText.equals(newDisplayText)) { displayText = newDisplayText; super.setText(displayText); } super.paint(g); if (focused) { removeImageYOffset = (getSize().height - removeImageHeight) / 2; g.drawImage( getRemoveButtonImage(), getSize().width - removeImageWidth - removeImageXOffset, removeImageYOffset, this); } } @Override public Dimension getMinimumSize() { return new Dimension(0, 0); } @Override public String getText() { return fullText; } private String displayText(Graphics g, String text) { int maxTextWidth = getWidth(); maxTextWidth -= 20; // make room for spaces around text FontMetrics fontMetrics = g.getFontMetrics(getFont()); int nameWidth = fontMetrics.stringWidth(text); String ret = text; if (nameWidth > maxTextWidth) { ret = shortenText(fontMetrics, text, maxTextWidth) + "..."; // NOI18N } return ret; } private String shortenText(FontMetrics fontMetrics, String text, int maxTextWidth) { String ret = text; for (int newLength = text.length(); newLength > 0; newLength--) { ret = text.substring(0, newLength); if (fontMetrics.stringWidth(ret) < maxTextWidth) { break; } } return ret; } // @Override @Override public void mousePressed(MouseEvent me) {} // @Override @Override public void mouseMoved(MouseEvent me) { Image newButtonImage; int scrollbarOffset = 0; // getScrollbarOffset(); int x = me.getPoint().x; int y = me.getPoint().y; if (x >= getSize().width - removeImageWidth - removeImageXOffset - scrollbarOffset && x <= getSize().width - removeImageXOffset - scrollbarOffset && y >= removeImageYOffset && y <= removeImageHeight + removeImageYOffset) { newButtonImage = getRemoveFocusedImage(); if (actionToolTipText != null) { super.setToolTipText(actionToolTipText); } else { super.setToolTipText(AnLocale.getString("Remove")); } } else { newButtonImage = getRemoveUnfocusedImage(); super.setToolTipText(toolTipText); } if (newButtonImage != getRemoveButtonImage()) { buttonImage = newButtonImage; repaint(100); } } // @Override @Override public void mouseClicked(MouseEvent me) {} // @Override @Override public void mouseDragged(MouseEvent me) {} // @Override @Override public void mouseEntered(MouseEvent me) { focused = true; refresh(); } // @Override @Override public void mouseExited(MouseEvent me) { focused = false; refresh(); } // @Override @Override public void mouseReleased(MouseEvent me) { int scrollbarOffset = 0; // getScrollbarOffset(); int x = me.getPoint().x; int y = me.getPoint().y; if (x >= getSize().width - removeImageWidth - removeImageXOffset - scrollbarOffset && x <= getSize().width - removeImageXOffset - scrollbarOffset && y >= removeImageYOffset && y <= removeImageHeight + removeImageYOffset) { removeButtonActionPerformed(null); me.consume(); } } private void refresh() { repaint(100); } protected Image getRemoveButtonImage() { if (buttonImage == null) { buttonImage = getRemoveUnfocusedImage(); } return buttonImage; } protected Image getRemoveUnfocusedImage() { if (removeImage == null) { removeImage = AnUtility.removeIcon.getImage(); removeImageWidth = removeImage.getWidth(this); removeImageHeight = removeImage.getHeight(this); } return removeImage; } protected Image getRemoveFocusedImage() { if (removeImageFocused == null) { removeImageFocused = AnUtility.removeFocusedIcon.getImage(); } return removeImageFocused; } protected void removeButtonActionPerformed(java.awt.event.ActionEvent evt) { ActionListener[] actionListeners = getActionListeners(); for (ActionListener actionListener : actionListeners) { actionListener.actionPerformed(evt); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnTabbedPane.java�����������������������������������������0000644�0001750�0001750�00000002465�14517772113�020614� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import java.awt.Dimension; import java.awt.Font; import javax.swing.BorderFactory; import javax.swing.JTabbedPane; public class AnTabbedPane extends JTabbedPane { public AnTabbedPane() { AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Tabbed Pane")); setFont(getFont().deriveFont(Font.BOLD)); setBorder(BorderFactory.createLineBorder(AnEnvironment.TABBED_PANE_BORDER_COLOR, 1)); setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); setMinimumSize(new Dimension(0, 0)); setUI(new AnTabbedPaneUI()); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnJTree.java����������������������������������������������0000644�0001750�0001750�00000002510�14517772113�017627� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import javax.swing.JTree; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeNode; public class AnJTree extends JTree { public AnJTree() { super(); init(); } public AnJTree(TreeNode root) { super(root); init(); } private void init() { if (AnEnvironment.isLFNimbus()) { setBackground(AnEnvironment.NIMBUS_TREE_BACKGROUND); } ((DefaultTreeCellRenderer) getCellRenderer()).setLeafIcon(null); ((DefaultTreeCellRenderer) getCellRenderer()).setClosedIcon(null); ((DefaultTreeCellRenderer) getCellRenderer()).setOpenIcon(null); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnGradientPanel.java��������������������������������������0000644�0001750�0001750�00000002614�14517772113�021340� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import java.awt.Color; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; /** * @author tpreisle */ public class AnGradientPanel extends javax.swing.JPanel { private Color topColor; private Color bottomColor; public AnGradientPanel(Color topColor, Color bottomColor) { this.topColor = topColor; this.bottomColor = bottomColor; } @Override public void paintComponent(Graphics g) { int width = getWidth(); int height = getHeight(); Graphics2D g2d = (Graphics2D) g; GradientPaint gp; gp = new GradientPaint(0, 0, topColor, 0, height, bottomColor); g2d.setPaint(gp); g2d.fillRect(0, 0, width - 1, height - 1); setOpaque(false); } } ��������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnLongScrollBar.java��������������������������������������0000644�0001750�0001750�00000016221�14517772113�021325� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import java.awt.event.AdjustmentEvent; import java.awt.event.AdjustmentListener; import java.util.ArrayList; import javax.swing.JScrollBar; /** * A scrollbar class that takes long value instead of ints. This class uses the swing JScrollBar but * handles the conversion of long values to pixels. */ public class AnLongScrollBar extends JScrollBar { private long longMin; private long longMax; private long longExtent; private long longMaxWithExtent; private long longValue; private int intMin; private int intMax; private int intExtent; private int intMaxWithExtent; private int oldIntVal; private long longUnitInc; private long longBlockInc; private int shift; private boolean setting_values = false; private ArrayList<LongAdjustmentListener> longListeners; private final int BLOCK_STEP_MAGIC = 2; private final int UNIT_STEP_MAGIC = 1; /** Creates a new instance of JLongScroll */ public AnLongScrollBar(int orientation) { super(orientation); initialize(); } /** initialize listeners */ private void initialize() { addAdjustmentListener( new AdjustmentListener() { /** When an adjustment is made to the integer value, compute a new long value */ public void adjustmentValueChanged(AdjustmentEvent e) { /* If adjustment initiated by this class ignore the event */ if (setting_values) { return; } int val = e.getValue(); boolean isAdjusting = e.getValueIsAdjusting(); long value; LongAdjustmentEvent le; if (shift == 0) { value = val; le = new LongAdjustmentEvent(value, isAdjusting); } else { int delta = val - oldIntVal; int sign; if (delta > 0) { sign = 1; } else { delta = -delta; sign = -1; } if (delta == UNIT_STEP_MAGIC) { // magic for unit increment value = longValue + longUnitInc * sign; } else if (delta == BLOCK_STEP_MAGIC) { // magic for block increment value = longValue + longBlockInc * sign; } else { // interpret as a drag of the slider value = (long) val * (1L << shift); } setValueInternal(value); le = new LongAdjustmentEvent(longValue, isAdjusting); } fireAdjustementEvent(le); } }); longListeners = new ArrayList(); super.setValues(0, 0, 0, 0); } // override parent version public void setUnitIncrement(int inc) { setUnitIncrement((long) inc); } public void setUnitIncrement(long inc) { longUnitInc = inc; int val; if (shift == 0) { val = (int) inc; } else { val = UNIT_STEP_MAGIC; // supply magic value 1 } super.setUnitIncrement(val); } // override parent version public void setBlockIncrement(int inc) { setBlockIncrement((long) inc); } public void setBlockIncrement(long inc) { longBlockInc = inc; int val; if (shift == 0) { val = (int) inc; } else { val = BLOCK_STEP_MAGIC; // supply magic longValue 2 } super.setBlockIncrement(val); } public long getLongValue() { return longValue; } private long setValueInternal(long value) { // correct for overshoot if (value < longMin) { value = longMin; } else if (value > longMaxWithExtent) { value = longMaxWithExtent; } longValue = value; long tmpValue = value >> shift; int intValue = (int) tmpValue; if (intValue < intMin) { intValue = intMin; } else if (intValue > intMaxWithExtent) { intValue = intMaxWithExtent; } oldIntVal = intValue; setting_values = true; { setValue(intValue); } setting_values = false; return longValue; } /** Set the values for the scollbar. Also sets block and unit increment */ private void setValuesInternal(long tmpValue, long tmpExtent, long tmpMin, long tmpMax) { setting_values = true; { longValue = tmpValue; longExtent = tmpExtent; longMin = tmpMin; longMax = tmpMax; longMaxWithExtent = longMax - longExtent; /* scale the long values to fit in int */ int shiftcnt = 0; while (tmpMax > Integer.MAX_VALUE || tmpMin < Integer.MIN_VALUE || tmpExtent > Integer.MAX_VALUE) { tmpMin /= 2; tmpMax /= 2; tmpValue /= 2; tmpExtent /= 2; shiftcnt++; } this.shift = shiftcnt; oldIntVal = (int) tmpValue; intExtent = (int) tmpExtent; intMin = (int) tmpMin; intMax = (int) tmpMax; intMaxWithExtent = intMax - intExtent; super.setValues(oldIntVal, intExtent, intMin, intMax); } setting_values = false; } private void setDefaultIncrementsInternal() { long uinc = longExtent / 50; if (uinc < 1) { uinc = 1; } setUnitIncrement(uinc); long binc = longExtent * 3 / 4; if (binc < 1) { binc = 1; } setBlockIncrement(binc); } public void setValues( // override parent version int tmpValue, int tmpExtent, int tmpMin, int tmpMax) { setValues((long) tmpValue, (long) tmpExtent, (long) tmpMin, (long) tmpMax); } public void setValues(long tmpValue, long tmpExtent, long tmpMin, long tmpMax) { setValuesInternal(tmpValue, tmpExtent, tmpMin, tmpMax); setDefaultIncrementsInternal(); } /** Notify listeners of adjustment */ private void fireAdjustementEvent(LongAdjustmentEvent event) { for (LongAdjustmentListener listener : longListeners) { listener.adjustmentValueChanged(event); } } /** Add LongAdjustmentListener */ public void addLongAdjustmentListener(LongAdjustmentListener listener) { longListeners.add(listener); } /** A listener for adjustements to the AnLongScrollBar */ public interface LongAdjustmentListener { public void adjustmentValueChanged(LongAdjustmentEvent adjustmentEvent); } /** An event for adjestment to JLongScrollBars */ public class LongAdjustmentEvent { private final long value; private final boolean isAdjusting; public LongAdjustmentEvent(long value, boolean isAdjusting) { this.value = value; this.isAdjusting = isAdjusting; } /** Get the new specified value */ public long getValue() { return value; } public boolean getValueIsAdjusting() { return isAdjusting; } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnBorderPanel.java����������������������������������������0000644�0001750�0001750�00000005350�14517772113�021020� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import java.awt.Color; import java.awt.Graphics; import javax.swing.JPanel; /** * @author tpreisle */ public class AnBorderPanel extends JPanel { private Color topBorderColor = null; private Color rightBorderColor = null; private Color leftBorderColor = null; private Color bottomBorderColor = null; @Override public void paint(Graphics g) { super.paint(g); if (topBorderColor != null) { g.setColor(topBorderColor); g.drawLine(0, 0, getWidth() - 1, 0); } if (rightBorderColor != null) { g.setColor(rightBorderColor); g.drawLine(getWidth() - 1, 0, getWidth() - 1, getHeight() - 1); } if (getLeftBorderColor() != null) { g.setColor(getLeftBorderColor()); g.drawLine(0, 0, 0, getHeight() - 1); } if (bottomBorderColor != null) { g.setColor(bottomBorderColor); g.drawLine(0, getHeight() - 1, getWidth() - 1, getHeight() - 1); } } /** * @return the topBorder */ public Color getTopBorderColor() { return topBorderColor; } /** * @param topBorder the topBorder to set */ public void setTopBorderColor(Color topBorderColor) { this.topBorderColor = topBorderColor; } /** * @return the rightBorderColor */ public Color getRightBorderColor() { return rightBorderColor; } /** * @param rightBorderColor the rightBorderColor to set */ public void setRightBorderColor(Color rightBorderColor) { this.rightBorderColor = rightBorderColor; } /** * @return the bottomBorderColor */ public Color getBottomBorderColor() { return bottomBorderColor; } /** * @param bottomBorderColor the bottomBorderColor to set */ public void setBottomBorderColor(Color bottomBorderColor) { this.bottomBorderColor = bottomBorderColor; } /** * @return the leftBorderColor */ public Color getLeftBorderColor() { return leftBorderColor; } /** * @param leftBorderColor the leftBorderColor to set */ public void setLeftBorderColor(Color leftBorderColor) { this.leftBorderColor = leftBorderColor; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnSplitPaneInternal.java����������������������������������0000644�0001750�0001750�00000002512�14517772113�022214� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import java.awt.Component; public class AnSplitPaneInternal extends AnSplitPane { public AnSplitPaneInternal(int orientation, Component leftComponent, Component rightComponent) { this(orientation, leftComponent, rightComponent, -1); } public AnSplitPaneInternal( int orientation, Component leftComponent, Component rightComponent, int location) { super(orientation, leftComponent, rightComponent, location); init(); } private void init() { setDividerSize(AnSplitPane.defaultDividerSizeSmall); setBackground(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR_INSIDE); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnSplitPaneFixedRightSize.java����������������������������0000644�0001750�0001750�00000010622�14517772113�023331� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import static org.gprofng.mpmt.util.gui.AnSplitPane.defaultDividerSize; import static javax.swing.JSplitPane.HORIZONTAL_SPLIT; import java.awt.Component; import java.awt.event.ComponentEvent; import java.awt.event.ComponentListener; public class AnSplitPaneFixedRightSize extends AnSplitPane { private int sizeInPixels; private final int defaultSize; private boolean hidden = false; private int sizeInPixelsHidden = -1; public AnSplitPaneFixedRightSize( int newOrientation, Component newLeftComponent, Component newRightComponent, int rightSizeInPixels, int rightDefaultSize) { super(newOrientation, newLeftComponent, newRightComponent, 0); setOneTouchExpandable(true); this.sizeInPixels = rightSizeInPixels; this.defaultSize = rightDefaultSize; setResizeWeight(1); addComponentListener( new ComponentListener() { @Override public void componentShown(ComponentEvent e) {} @Override public void componentResized(ComponentEvent e) { if (!isHidden()) { setDivider(); } } @Override public void componentMoved(ComponentEvent e) {} @Override public void componentHidden(ComponentEvent e) {} }); } private void setDivider() { int location; if (getOrientation() == HORIZONTAL_SPLIT) { location = getWidth() - sizeInPixels; } else { location = getHeight() - sizeInPixels; } if (location != super.getDividerLocation()) { super.setDividerLocation(location); } } @Override public void setDividerLocation(int location) { // Only react to this if it is from a direct user action like dragging or clicking if (isDraggingDivider() || clickedOneTouchButton()) { setDividerLocationInternal(location); } } public void setDividerLocationInternal(int location) { if (getOrientation() == HORIZONTAL_SPLIT) { sizeInPixels = getWidth() - location; } else { sizeInPixels = getHeight() - location; } super.setDividerLocation(location); } @Override public int getLastDividerLocation() { int ldl = super.getLastDividerLocation(); int size; if (getOrientation() == HORIZONTAL_SPLIT) { size = getWidth(); } else { size = getHeight(); } if (ldl <= 8 || ldl > (size - 8)) { int location = size - defaultSize; ldl = location; } return ldl; } /* * Hack...... */ private boolean clickedOneTouchButton() { StackTraceElement[] es = Thread.currentThread().getStackTrace(); int n = 0; for (StackTraceElement e : es) { String s = e.getClassName(); if (s.contains("OneTouchAction")) { // NOI18N return true; } if (n++ > 3) { break; } } return false; } /** * @return the widthInPixels */ public int getSizeInPixels() { if (hidden) { return sizeInPixelsHidden; } else { return sizeInPixels; } } /** * @param sizeInPixels */ public void setSizeInPixels(int sizeInPixels) { this.sizeInPixels = sizeInPixels; setDivider(); } /** * @param hide */ @Override public void setHidden(boolean hide) { if (hide) { if (!hidden) { hidden = true; sizeInPixelsHidden = sizeInPixels; sizeInPixels = 0; setDividerSize(0); super.setDividerLocation(10000); } } else { if (hidden) { hidden = false; sizeInPixels = sizeInPixelsHidden; sizeInPixelsHidden = -1; setDividerSize(defaultDividerSize); setDivider(); } } } /** * @return */ @Override public boolean isHidden() { return hidden; } } ��������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnDialogOuterPanel.form�����������������������������������0000644�0001750�0001750�00000011677�14517772113�022054� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Container class="javax.swing.JPanel" name="panel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="5" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout> <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="400" max="32767" attributes="0"/> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="266" max="32767" attributes="0"/> </Group> </DimensionLayout> </Layout> </Container> <Component class="javax.swing.JButton" name="okButton"> <Properties> <Property name="text" type="java.lang.String" value="jButton1"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="22" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="cancelButton"> <Properties> <Property name="text" type="java.lang.String" value="jButton2"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="3" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="22" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="helpButton"> <Properties> <Property name="text" type="java.lang.String" value="jButton3"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="4" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="22" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> �����������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnInsetsPanel.form����������������������������������������0000644�0001750�0001750�00000004027�14517772113�021072� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> </AuxValues> <Layout> <DimensionLayout dim="0"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="400" max="32767" attributes="0"/> </Group> </DimensionLayout> <DimensionLayout dim="1"> <Group type="103" groupAlignment="0" attributes="0"> <EmptySpace min="0" pref="300" max="32767" attributes="0"/> </Group> </DimensionLayout> </Layout> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/gui/AnSplitPane.java������������������������������������������0000644�0001750�0001750�00000027023�14517772113�020523� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.gui; import org.gprofng.analyzer.AnEnvironment; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JSplitPane; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.plaf.basic.BasicSplitPaneDivider; import javax.swing.plaf.basic.BasicSplitPaneUI; public class AnSplitPane extends JSplitPane { private boolean hidden = false; private boolean isDragging = false; public static final int defaultDividerSize = 6; public static final int defaultDividerSizeSmall = 2; private int locationWhenShowing = 0; private int dividerSizeWhenShowing = 0; static { UIManager.getDefaults().put("SplitPane.border", BorderFactory.createEmptyBorder()); // NOI18N } ; public AnSplitPane(int orientation, Component leftComponent, Component rightComponent) { this(orientation, leftComponent, rightComponent, -1); } public AnSplitPane( int orientation, Component leftComponent, Component rightComponent, int location) { super(orientation, leftComponent, rightComponent); init(); if (location >= 0) { setDividerLocation(location); } setBackground(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); } private void init() { setContinuousLayout(true); setDividerSize(defaultDividerSize); // setOneTouchExpandable(true); setUI( new BasicSplitPaneUI() { private final int oneTouchSize = 5; @Override public BasicSplitPaneDivider createDefaultDivider() { return new BasicSplitPaneDivider(this) { private boolean mouseInsideRight; private boolean mouseInsideLeft; @Override public void setBorder(Border b) {} @Override public void paint(Graphics g) { g.setColor(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); super.paint(g); } /** * Creates and return an instance of JButton that can be used to collapse the left * component in the split pane. */ /* * Code copied from BasicSplitPaneDivider.java */ @Override protected JButton createLeftOneTouchButton() { JButton b = new JButton() { @Override public void setBorder(Border b) {} @Override public void paint(Graphics g) { if (splitPane != null) { int[] xs = new int[3]; int[] ys = new int[3]; int blockSize; // Fill the background first ...... g.setColor(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); g.fillRect(0, 0, this.getWidth(), this.getHeight()); // ... then draw the arrow. if (mouseInsideLeft) { g.setColor(AnEnvironment.SPLIT_PANE_ONE_TOUCH_BUTTON_FOCUSED_COLOR); } else { g.setColor(AnEnvironment.SPLIT_PANE_ONE_TOUCH_BUTTON_COLOR); } if (orientation == JSplitPane.VERTICAL_SPLIT) { blockSize = Math.min(getHeight(), oneTouchSize); xs[0] = blockSize; xs[1] = 0; xs[2] = blockSize << 1; ys[0] = 0; ys[1] = blockSize; ys[2] = blockSize; g.drawPolygon(xs, ys, 3); } else { blockSize = Math.min(getWidth(), oneTouchSize); xs[0] = blockSize; xs[1] = 0; xs[2] = blockSize; ys[0] = 0; ys[1] = blockSize; ys[2] = blockSize << 1; } g.fillPolygon(xs, ys, 3); g.setColor(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); // g.setColor(Color.red); if (orientation == JSplitPane.VERTICAL_SPLIT) { g.drawLine( 0, this.getHeight() - 1, this.getWidth() - 1, this.getHeight() - 1); } else { g.drawLine( this.getWidth() - 1, 0, this.getWidth() - 1, this.getHeight() - 1); } } } // Don't want the button to participate in focus traversable. @Override public boolean isFocusTraversable() { return false; } }; b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize)); b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); b.setFocusPainted(false); b.setBorderPainted(false); b.setRequestFocusEnabled(false); b.addMouseListener( new MouseListener() { @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) { mouseInsideLeft = true; repaint(); } @Override public void mouseExited(MouseEvent e) { mouseInsideLeft = false; repaint(); } }); return b; } /** * Creates and return an instance of JButton that can be used to collapse the right * component in the split pane. */ /* * Code copied from BasicSplitPaneDivider.java */ @Override protected JButton createRightOneTouchButton() { JButton b = new JButton() { @Override public void setBorder(Border border) {} @Override public void paint(Graphics g) { if (splitPane != null) { int[] xs = new int[3]; int[] ys = new int[3]; int blockSize; // Fill the background first ... g.setColor(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); g.fillRect(0, 0, this.getWidth(), this.getHeight()); // ... then draw the arrow. if (orientation == JSplitPane.VERTICAL_SPLIT) { blockSize = Math.min(getHeight(), oneTouchSize); xs[0] = blockSize - 1; xs[1] = (blockSize << 1) - 1; xs[2] = 0; ys[0] = blockSize + 1; ys[1] = 0 + 1; ys[2] = 0 + 1; } else { blockSize = Math.min(getWidth(), oneTouchSize); xs[0] = 0 + 1; xs[1] = blockSize + 1; xs[2] = 0 + 1; ys[0] = 0; ys[1] = blockSize; ys[2] = blockSize << 1; } if (mouseInsideRight) { g.setColor(AnEnvironment.SPLIT_PANE_ONE_TOUCH_BUTTON_FOCUSED_COLOR); } else { g.setColor(AnEnvironment.SPLIT_PANE_ONE_TOUCH_BUTTON_COLOR); } g.fillPolygon(xs, ys, 3); } } // Don't want the button to participate in focus traversable. @Override public boolean isFocusTraversable() { return false; } }; b.setMinimumSize(new Dimension(oneTouchSize, oneTouchSize)); b.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); b.setFocusPainted(false); b.setBorderPainted(false); b.setRequestFocusEnabled(false); b.addMouseListener( new MouseListener() { @Override public void mouseClicked(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) {} @Override public void mouseReleased(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) { mouseInsideRight = true; repaint(); } @Override public void mouseExited(MouseEvent e) { mouseInsideRight = false; repaint(); } }); return b; } }; } @Override protected void dragDividerTo(int location) { isDragging = true; super.dragDividerTo(location); isDragging = false; } }); } protected boolean isDraggingDivider() { return isDragging; } public void setHidden(boolean hide) { if (hide) { if (!hidden) { locationWhenShowing = getDividerLocation(); dividerSizeWhenShowing = getDividerSize(); setDividerLocation(0); setDividerSize(0); hidden = true; } } else if (hidden) { hidden = false; setDividerLocation(locationWhenShowing); setDividerSize(dividerSizeWhenShowing); } } public boolean isHidden() { return hidden; } public int getDividerLocationWhenShowing() { if (isHidden()) { return locationWhenShowing; } else { return getDividerLocation(); } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/��������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�016140� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/LabelCoordinateCalculator.java��������������������������0000644�0001750�0001750�00000001705�14517772113�023752� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler; /** Computes the coordinates for an axis. */ public interface LabelCoordinateCalculator { /** Get the midpoint of a bin */ public int getCenterCoordForValue(long value); /** Get the size of the ruler portion (w/o margins) */ public int getDataPixels(); } �����������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/valuetypes/���������������������������������������������0000755�0001750�0001750�00000000000�14517775726�020341� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/valuetypes/ValuesNanoseconds.java�����������������������0000644�0001750�0001750�00000004232�14517772113�024542� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler.valuetypes; import org.gprofng.mpmt.AnLocale; /** * This class provides unit strings for a number of nanoseconds that fall withing a specified range. */ public class ValuesNanoseconds extends ValuesWithUnits { /** Instantiate a new ValuesNanoseconds object with a specified range */ public ValuesNanoseconds(long low, long high) { super(low, high); } public String getUnitString() { String units = getUnitString(absMax); return units; } public long getUnitDivisor() { long uDiv = getUnitDivisor(absMax); return uDiv; } /** Get the Unit String to use */ private String getUnitString(long value) { String time_units; if (value < 1000L) { // nanoseconds time_units = AnLocale.getString("nsec"); // NOI18N } else if (value < 1000000L) { // microseconds time_units = AnLocale.getString("usec"); // NOI18N } else if (value < 1000000000L) { // millisenconds time_units = AnLocale.getString("msec"); // NOI18N } else { // seconds time_units = AnLocale.getString("sec"); // NOI18N } return time_units; } /* * Get the divisor required to use the metric unit prefix * supplied by getUnitString() */ private long getUnitDivisor(long value) { long divisor; if (value < 1000L) { divisor = 1L; } else if (value < 1000000L) { divisor = 1000L; } else if (value < 1000000000L) { divisor = 1000000L; } else { divisor = 1000000000L; } return divisor; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/valuetypes/ValuesBytes.java�����������������������������0000644�0001750�0001750�00000003670�14517772113�023363� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler.valuetypes; import org.gprofng.mpmt.AnLocale; /** This class provides unit strings for a number of bytes that fall withing a specified range. */ public class ValuesBytes extends ValuesWithUnits { /** Instantiate a new ValuesBytes object with a specified range */ public ValuesBytes(long low, long high) { super(low, high); } public String getUnitString() { String units = getUnitString(absMax); return units; } public long getUnitDivisor() { long uDiv = getUnitDivisor(absMax); return uDiv; } /** Get the Unit String to use */ public String getUnitString(long value) { String units; if (value < 1000L) { units = AnLocale.getString("Bytes"); // NOI18N } else if (value < 1000000L) { units = AnLocale.getString("KB"); // NOI18N } else if (value < 1000000000L) { units = AnLocale.getString("MB"); // NOI18N } else { units = AnLocale.getString("GB"); // NOI18N } return units; } private long getUnitDivisor(long value) { long divisor; if (value < 1000L) { divisor = 1L; } else if (value < 1000000L) { divisor = 1000L; } else if (value < 1000000000L) { divisor = 1000000L; } else { divisor = 1000000000L; } return divisor; } } ������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/valuetypes/ValuesWithUnits.java�������������������������0000644�0001750�0001750�00000006420�14517772113�024227� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler.valuetypes; import java.text.DecimalFormat; /* * The ValuesWithUnits stores a range for values that can be expressed * with modifiers like kilo or nano. * Values are of type long and must be stored in the highest-resolusion. */ public abstract class ValuesWithUnits implements ValuesGeneric { protected long low; protected long high; protected long absMax; // maximum absolute value /** Instantiate a new ValuesWithUnits object */ public ValuesWithUnits(long v1, long v2) { setRange(v1, v2); } /* * Get the units' string. * Example: value units = bytes -> Bytes, KB, MB, ... * Example: value units = nanoseconds -> Nanoseconds, Milliseconds... * Assumes <value> is in highest-resolusion units. */ public abstract String getUnitString(); /* * Get the divisor required to convert to the units * supplied by getUnitString(). */ public abstract long getUnitDivisor(); /* * Format a value using <range> to set number of sig digits */ public String getFormattedValue(long value, long range) { String myformat = "###,###,###,###,###,##0"; // convert origValue to desired units long uDiv = getUnitDivisor(); double uValue = value; uValue /= uDiv; // calculate # of places to right of decimal point required to show // MSD of <range> range = Math.abs(range); // ensure range>=1 range = Math.max(1, range); if (range < uDiv) { // range is a fraction of uDiv long tmp = range; int decimalPlaces = 0; while (tmp < uDiv) { tmp *= 10; decimalPlaces++; } String decimalfmt = ".000000000000000000000000000"; myformat = myformat + decimalfmt.substring(0, decimalPlaces + 1); } // generate string DecimalFormat df = new DecimalFormat(myformat); // bd = bd.setScale(decimalPlaces,BigDecimal.ROUND_HALF_UP); String text = df.format(uValue); return text; } /** Format a value based on default setting */ public String getFormattedValue(long value) { long range = high - low + 1; String ss = getFormattedValue(value, range); return ss; } /** Get the low value */ public long getLowValue() { return low; } /** Get the high value */ public long getHighValue() { return high; } /** Set the range of values */ public void setRange(long v1, long v2) { if (v1 < v2) { low = v1; high = v2; } else { low = v2; high = v1; } absMax = 0; long tmp = Math.abs(v1); if (absMax < tmp) { absMax = tmp; } tmp = Math.abs(v2); if (absMax < tmp) { absMax = tmp; } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/valuetypes/ValuesLabelList.java�������������������������0000644�0001750�0001750�00000004157�14517772113�024151� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler.valuetypes; /** Display formatting for any text-based values such (e.g. function name) */ public class ValuesLabelList implements ValuesGeneric { private long low; private long high; private String labels[]; /** Instantiate a new GenericValueType */ public ValuesLabelList(String labels[]) { this.labels = labels; } /** Display as the value converted to a string */ public String getFormattedValue(long value) { if (value >= 0 && value < labels.length) { int idx = (int) value; return labels[idx]; // YXXX could show a range in the future } else { return ""; } } /** No units for generic data */ public String getUnitString() { return null; } /** Display as the value converted to a string */ public String getFormattedValue(long value, long range) { return getFormattedValue(value); } /** Return the low value index */ public long getLowValue() { return low; } /** Return the high value index */ public long getHighValue() { return high; } private int limit(long value) { int rc; if (value < 0) { rc = 0; } else if (value >= labels.length) { rc = labels.length - 1; } else { rc = (int) value; } return rc; } /** Set the range */ public void setRange(long v1, long v2) { if (v1 < v2) { low = limit(v1); high = limit(v2); } else { low = limit(v2); high = limit(v1); } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/valuetypes/ValuesLong.java������������������������������0000644�0001750�0001750�00000003246�14517772113�023173� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler.valuetypes; /** Display formatting for generic values such as a count. */ public class ValuesLong implements ValuesGeneric { private long low; private long high; /** Instantiate a new ValuesLong */ public ValuesLong(long low, long high) { setRange(low, high); } /** Display as the value converted to a string */ public String getFormattedValue(long value) { return Long.toString(value); } /** No units for generic data */ public String getUnitString() { return null; } /** Display as the value converted to a string */ public String getFormattedValue(long value, long range) { return getFormattedValue(value); } /** Return the low value */ public long getLowValue() { return low; } /** Return the high value */ public long getHighValue() { return high; } /** Set the range */ public void setRange(long v1, long v2) { if (v1 < v2) { low = v1; high = v2; } else { low = v2; high = v1; } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/valuetypes/ValuesGeneric.java���������������������������0000644�0001750�0001750�00000002576�14517772113�023655� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler.valuetypes; /** * The ValuesGeneric interface allows for specification of how to format a value to display it and * what unit string to use. */ public interface ValuesGeneric { /** Get the units (e.g. "usec") */ public String getUnitString(); /** get <value> as a string (does not include units) */ public String getFormattedValue(long value); /** get <value> as a string, with enough precision to show <range> */ public String getFormattedValue(long value, long range); /** Get the low value for the range */ public long getLowValue(); /** Get the high value for the range */ public long getHighValue(); /** Set the data range */ public void setRange(long v1, long v2); } ����������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/Ruler.java����������������������������������������������0000644�0001750�0001750�00000003325�14517772113�020002� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler; /** * A Component that is suitable to representa range of values or a discrete set of labels in a chart * or timeline. The ruler has three levels, one for ticks, one for labels, and one for the title. * * @author blewis */ public interface Ruler { // orientation public static final int VERTICAL_ORIENTATION = 1; public static final int HORIZONTAL_ORIENTATION = 2; // ticks placement public static final int TICKS_ON_THE_BOTTOM = 1; public static final int TICKS_ON_THE_TOP = 2; // title location public static final int PLACEMENT_NONE = 0; // title not displayed public static final int PLACEMENT_WITH_LABELS = 1; // title inline w/tick labels public static final int PLACEMENT_TITLE_LEVEL = 2; // separate row for title /** * Set a spacing to align component padLo is at the 0 end of the graphics' coordinate system padHi * is at the opposite end */ public void setPadding(int padLo, int padHi); /** set direction of ruler w.r.t. coordinate system */ public void setOrderReverse(boolean reverse); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/ruler/RangeRuler.java�����������������������������������������0000644�0001750�0001750�00000074141�14517772113�020763� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.ruler; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.timeline_common.CoordCalcTimeReader; import org.gprofng.mpmt.timeline_common.VerticalRowRuler; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.ruler.valuetypes.ValuesGeneric; import org.gprofng.mpmt.util.zoomruler.PaintListener; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Polygon; import java.util.ArrayList; import java.util.List; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.accessibility.AccessibleRole; import javax.swing.JTable; // import org.gprofng.mpmt.GraphControls; /** * A component that is suitable to show the labels for an axis of the graph which has a range of * values. Special processing is made to for nano second values to show the time units. */ public class RangeRuler extends VerticalRowRuler implements Ruler, Accessible { // user settings private ValuesGeneric valueType; private LabelCoordinateCalculator coordCalculator; private boolean isContinuous; private int orientation; // see enum above private int paddingLow; private int paddingHigh; private int tickPlacement; // see enum above private int titlePlacement = PLACEMENT_NONE; // see enum above private boolean inverseOrder = false; private boolean useTickCenterForUnitSteps; // ticks geometry private final int MIN_PIXELS_BETWEEN_TICKS = 4; private final int SMALL_TICK_LENGTH = 2; private final int MAXTICKLEN = SMALL_TICK_LENGTH * 4; // font settings private final int MIN_PIXELS_BETWEEN_LABELS = 30; private static final double RADIANS_90DEGREES = Math.PI / 2; private int MARGIN = 2; // font state private static Font TEXT_FONT; private int FONT_HEIGHT = 0; private int FONT_ASCENT = 0; private int FONT_DESCENT = 0; // state private boolean staggerHorizontalLabels; private int labelBoundaryCoord = 0; // coordinate of edge of title private String title; private ArrayList<PaintListener> paintListeners = new ArrayList(); private boolean lockPreferredSize = false; private Dimension preferredD = new Dimension(1, 1); // non-zero for layout mgr // TabStops // TBR: eventually move to new class that implements RangeRuler public enum TabStopTypes { TABSTOP_GENERIC, TABSTOP_LEFT, TABSTOP_RIGHT }; private List<TabStopTypes> tabStopTypes; private List<Long> tabStopValues; private CoordCalcTimeReader tabStopCalc; private final int TABSTOP_WIDTH = 5; private final int TABSTOP_LENGTH = MAXTICKLEN - 1; private final Color tabStopColorLeft = new Color(0, 32, 255); // Microstate Sleep blue private final Color tabStopColorRight = new Color(255, 16, 0); // Microstate Stopped red /** Instantiate a RangeRuler with a specified orientation */ public RangeRuler(ValuesGeneric type, int orientation) { super(); initRangeRuler(type, orientation, null, true); } static { JTable jtable = new JTable(); Font org_font = jtable.getFont(); TEXT_FONT = new Font( "SansSerif", org_font.getStyle(), // NOI18N org_font.getSize()); } public RangeRuler( ValuesGeneric type, int orientation, LabelCoordinateCalculator coordCalculator, boolean continuous) { super(); initRangeRuler(type, orientation, coordCalculator, continuous); } private void initRangeRuler( ValuesGeneric type, int orientation, LabelCoordinateCalculator coordCalculator, boolean isContinuous) { this.valueType = type; this.paddingLow = 0; this.paddingHigh = 0; this.orientation = orientation; if (coordCalculator == null) { this.coordCalculator = new LocalCalculator(); isContinuous = true; } else { this.coordCalculator = coordCalculator; } this.isContinuous = isContinuous; this.useTickCenterForUnitSteps = true; this.tickPlacement = TICKS_ON_THE_BOTTOM; this.title = ""; // NOI18N if (this.orientation == this.VERTICAL_ORIENTATION) { inverseOrder = !inverseOrder; } this.tabStopTypes = new ArrayList(); this.tabStopValues = new ArrayList(); String aText = orientation == RangeRuler.HORIZONTAL_ORIENTATION ? AnLocale.getString("Horizontal Ruler") : AnLocale.getString("Vertical Ruler"); AnUtility.setAccessibleContext(getAccessibleContext(), aText); } private boolean isFontInitialized() { if (FONT_HEIGHT != 0) { return true; } if (TEXT_FONT != null) { FontMetrics fm = this.getFontMetrics(TEXT_FONT); if (fm != null) { FONT_ASCENT = fm.getAscent() - 1; // YXXX bogus adjust for looks FONT_DESCENT = fm.getDescent() - 2; // YXXX bogus adjust for looks FONT_HEIGHT = FONT_ASCENT + FONT_DESCENT; return true; } } return false; } /** * Set a spacing to align component padLo is at the "0" end of the graphics' coordinate system * padHi is at the opposite end */ public void setPadding(int padLo, int padHi) { if (paddingLow != padLo || paddingHigh != padHi) { paddingLow = padLo; paddingHigh = padHi; repaint(); // should we do this elsewhere, as well? } } public int getPaddingLow() { return paddingLow; } public int getPaddingHigh() { return paddingHigh; } public void setUseTickCenterForUnitSteps(boolean center) { useTickCenterForUnitSteps = center; } /** set direction of ruler w.r.t. coordinate system */ public void setOrderReverse(boolean reverse) { this.inverseOrder = reverse; } /** Set title for the axis */ public void setTitle(String title) { this.title = title; if (title != null && titlePlacement == PLACEMENT_NONE) { setTitlePlacement(PLACEMENT_TITLE_LEVEL); } } /** Set to TICKS_ON_THE_BOTTOM or TICKS_ON_THE_TOP */ public void setTickPlacement(int p) { tickPlacement = p; } public void setTitlePlacement(int placement) { titlePlacement = placement; repaint(); } public void addPaintLister(PaintListener paintListener) { paintListeners.add(paintListener); } private void notifyPaintListeners(Graphics g) { for (PaintListener l : paintListeners) { l.timelinePainted(g); } } // if the LabelCoordinateCalculator stays the same, you can call this // WARNING: Modifies values in the global variable that was passed in! public final void setRange(long lo, long hi) { if (valueType.getLowValue() != lo || valueType.getHighValue() != hi) { valueType.setRange(lo, hi); repaint(); } } // --- accessability public final AccessibleContext getAccessibleContext() { // variable accessibleContext is protected in superclass if (accessibleContext == null) { accessibleContext = new AccessibleRuler(); } return accessibleContext; } final class AccessibleRuler extends AccessibleJComponent { public AccessibleRole getAccessibleRole() { return AccessibleRole.CANVAS; } } // --- calculators private class LocalCalculator implements LabelCoordinateCalculator { public int getCenterCoordForValue(long vv) { int absoluteCoord; // pretty inefficient, could cache some of these values int pixelsAvailForData = getDataPixels(); long dataHi = valueType.getHighValue(); long dataLo = valueType.getLowValue(); long dataRange = dataHi - dataLo + 1; double pixelsPerVal = (double) pixelsAvailForData / dataRange; double relOffset = vv - dataLo; if (useTickCenterForUnitSteps) { relOffset += 0.5; } int tmp = (int) (pixelsPerVal * relOffset); if (inverseOrder) { absoluteCoord = pixelsAvailForData - tmp; } else { absoluteCoord = tmp; } return absoluteCoord; } public int getDataPixels() { int availPixels; if (orientation == HORIZONTAL_ORIENTATION) { availPixels = getWidth() - paddingLow - paddingHigh; } else { availPixels = getHeight() - paddingLow - paddingHigh; } return availPixels; } } private boolean setPreferredForVertical(final Graphics g) { if (!isFontInitialized()) { return false; } int w = calcWidestLabel(g, valueType.getLowValue(), valueType.getHighValue(), 1); int width = w + MAXTICKLEN + MARGIN; if (titlePlacement != PLACEMENT_NONE) { width += FONT_HEIGHT + MARGIN; } boolean changed = internalSetPreferredSize(width, 0); return changed; } private boolean setPreferredForHorizontal(final Graphics g) { if (!isFontInitialized()) { return false; } int level = 1; // basic labels if (false) { // YXXX maybe the right thing to do, but I want to minimize resizes setStaggerHorizontalLabels(g); // compute staggerHorizontalLabels if (staggerHorizontalLabels) { level++; } } else { if (!isContinuous) { level++; } } if (titlePlacement == PLACEMENT_TITLE_LEVEL) { level++; } int height = computeDistanceFromHorizontalRuler(level); height += MARGIN; boolean changed = internalSetPreferredSize(0, height); return changed; } private int computeYCoordForHorizontalLabel(int level) { int coord = computeDistanceFromHorizontalRuler(level); if (tickPlacement == TICKS_ON_THE_BOTTOM) { coord += FONT_DESCENT; coord = preferredD.height - coord; } else { coord += FONT_ASCENT; } return coord; } // note: modifies staggerHorizontalLabels private int setStaggerHorizontalLabels(final Graphics g) { int availPixels = coordCalculator.getDataPixels(); if (availPixels <= 0) { return 0; } long lo = valueType.getLowValue(); long hi = valueType.getHighValue(); long dataRange = hi - lo + 1; // must be positive long estDataStep = dataRange / 80; // worst case, say 80 labels int maxLabelPixels; // max number of pixels per label, on-axis direction // # of allowable offsets (e.g. 2 for alternating) for tick labels boolean doStagger = false; maxLabelPixels = calcWidestLabel(g, lo, hi, estDataStep); maxLabelPixels += FONT_HEIGHT / 2; // add horzontal space based on font int estLabelCount = availPixels / maxLabelPixels; if (estLabelCount < dataRange && !isContinuous) { // labels don't all fit, use multi level doStagger = true; // two levels of labels -> divide by 2 maxLabelPixels = maxLabelPixels / 2 + 1; } staggerHorizontalLabels = doStagger; return maxLabelPixels; // largest size allowed for a single label } private int computeDistanceFromHorizontalRuler(int level) { int coord = MAXTICKLEN; coord += level * (FONT_HEIGHT); return coord; } // --- paint functions private void paintHorizontal(final Graphics g) { g.setFont(TEXT_FONT); g.setColor(Color.black); // direction-specific geometry int originX = 0; int originY; if (tickPlacement == TICKS_ON_THE_BOTTOM) { originY = this.getHeight(); } else { originY = 0; } int maxLabelPixels = setStaggerHorizontalLabels(g); // sets staggerHorizontalLabels // draw title int title_x; int title_y; String lbl = title; String units = valueType.getUnitString(); if (units != null && !units.equals("")) { lbl += "(" + units + ")"; // NOI18N } if (titlePlacement == PLACEMENT_TITLE_LEVEL) { title_x = coordCalculator.getDataPixels() / 2 + paddingLow; int level = 1; if (staggerHorizontalLabels) { level++; } title_y = computeYCoordForHorizontalLabel(level); drawCenteredString(g, lbl, title_x, title_y, 0); // YXXX add right bound later labelBoundaryCoord = MARGIN; } else if (titlePlacement == PLACEMENT_WITH_LABELS) { title_x = MARGIN; title_y = computeYCoordForHorizontalLabel(0); g.drawString(lbl, title_x, title_y); int titleWidth = g.getFontMetrics(TEXT_FONT).stringWidth(lbl); labelBoundaryCoord = title_x + titleWidth + MARGIN; } // draw ticks drawAllTicks(g, maxLabelPixels, originX, originY); drawAllTabStops(g, originX, originY); } private void paintVertical(final Graphics g) { g.setFont(TEXT_FONT); g.setColor(Color.black); // direction-specific geometry int originY = this.getHeight(); int originX; if (tickPlacement == TICKS_ON_THE_BOTTOM) { // right originX = this.getWidth(); } else { originX = 0; } int maxLabelPixels = FONT_HEIGHT + 1; // draw title if (titlePlacement == PLACEMENT_NONE) { labelBoundaryCoord = MARGIN; } else { int title_x = FONT_ASCENT + MARGIN; int title_y; String lbl = title; String units = valueType.getUnitString(); if (units != null && !units.equals("")) { lbl += "(" + units + ")"; // NOI18N } int w = g.getFontMetrics(TEXT_FONT).stringWidth(lbl); title_y = (coordCalculator.getDataPixels() + w) / 2 + paddingLow; Graphics2D g2 = (Graphics2D) g; g2.rotate(-RADIANS_90DEGREES); g2.drawString(lbl, -title_y, title_x); g2.rotate(RADIANS_90DEGREES); labelBoundaryCoord = MARGIN + FONT_HEIGHT + MARGIN; } // draw ticks drawAllTicks(g, maxLabelPixels, originX, originY); } // color must already be set private void drawAllTicks( final Graphics g, int maxLabelPixels, // pixels to allocate per label int originX, int originY) { g.setColor(Color.black); // estimate label sizes int availPixels = coordCalculator.getDataPixels(); long lo = valueType.getLowValue(); long hi = valueType.getHighValue(); long dataRange = hi - lo + 1; // must be positive // get array which specifies tick spacing long[] tickStep = calcTickSteps(availPixels, maxLabelPixels, dataRange); int tickLen = SMALL_TICK_LENGTH; // loop thru each level of tick spacing for (int ii = 0; ii < tickStep.length; ii++) { boolean showLabels = false; if (ii == tickStep.length - 1) { // last element in list specifies Labels showLabels = true; } drawTicks(g, originX, originY, tickStep[ii], tickLen, showLabels); tickLen += SMALL_TICK_LENGTH; } } // color must already be set private boolean drawTicks( final Graphics g, int originX, int originY, long dataStep, int tickLen, boolean showLabels) { if (dataStep == 0) { // no ticks at this dataStep level return false; } int pixelsAvailForData = coordCalculator.getDataPixels(); long dataHi = valueType.getHighValue(); long dataLo = valueType.getLowValue(); long dataRange = dataHi - dataLo + 1; double nsteps = (double) dataRange / dataStep; long pixelsPerTick = (long) (pixelsAvailForData / nsteps); if (pixelsPerTick < MIN_PIXELS_BETWEEN_TICKS) { // ticks too close together for screen if (showLabels) { return false; // gets here when there's no space for labels } return false; } // calculate loop start and end long alignedStart; // first value >= dataLo that is aligned to dataStep long alignedEnd; if (dataLo >= 0) { alignedStart = (dataLo + dataStep - 1) / dataStep * dataStep; } else { alignedStart = (dataLo) / dataStep * dataStep; } if (useTickCenterForUnitSteps) { alignedEnd = dataHi; } else { alignedEnd = dataHi + 1; // show most extreme tickmark } int labelOffsetLevel = 0; if (staggerHorizontalLabels) { long topDigit = alignedStart / dataStep; labelOffsetLevel = (int) (topDigit % 2); } // step thru range by tick step for (long vv = alignedStart; vv <= alignedEnd; vv += dataStep) { int x, y; // tick x and y // compute pixel location in axis direction int tickLocation; tickLocation = coordCalculator.getCenterCoordForValue(vv); tickLocation += paddingLow; if (orientation == HORIZONTAL_ORIENTATION) { x = tickLocation; if (showLabels) { int labelTickLen = computeDistanceFromHorizontalRuler(labelOffsetLevel); // draw extended ticks to handle staggered labels if (tickPlacement == TICKS_ON_THE_BOTTOM) { y = originY - labelTickLen; } else { y = originY + labelTickLen; } g.drawLine(x, originY, x, y); int lx = x; int ly = computeYCoordForHorizontalLabel(labelOffsetLevel); String label = valueType.getFormattedValue(vv, dataStep); int labelRightLimit = lx + (int) pixelsPerTick / 2; drawCenteredString(g, label, lx, ly, labelRightLimit); if (staggerHorizontalLabels) { labelOffsetLevel = (labelOffsetLevel + 1) % 2; } } else { if (tickPlacement == TICKS_ON_THE_BOTTOM) { y = originY - tickLen; } else { y = originY + tickLen; } g.drawLine(x, originY, x, y); } } else { // VERTICAL_ORIENTATION y = tickLocation; if (tickPlacement == TICKS_ON_THE_BOTTOM) { // on the right x = originX - tickLen; if (x < labelBoundaryCoord) { // no space to draw continue; } } else { x = tickLen; if (x > labelBoundaryCoord) { // no space to draw continue; } } if (showLabels) { String label = valueType.getFormattedValue(vv, dataStep); int lx = x; int ly = y - FONT_HEIGHT / 2 + FONT_ASCENT; if (tickPlacement == TICKS_ON_THE_BOTTOM) { // on the right drawRightAdjustedString(g, label, lx, ly); } else { drawLeftAdjustedString(g, label, lx, ly); } } else { g.drawLine(originX, y, x, y); } } } return true; } // tabStop code to show caliper "handles" // TBR, refactor to class that implements RangeRuler public final void setTabStops( List<Long> vals, List<TabStopTypes> types, CoordCalcTimeReader calc) { final int valuesSize = (vals != null) ? vals.size() : 0; final int typesSize = (types != null) ? types.size() : 0; boolean needsUpdate = false; tabStopCalc = calc; // TBR after refactoring tabStop* into separate class if (tabStopValues.size() != valuesSize || tabStopTypes.size() != typesSize) { needsUpdate = true; } for (int ii = 0; !needsUpdate && ii < valuesSize; ii++) { if (tabStopValues.get(ii) != vals.get(ii)) { needsUpdate = true; break; } if (tabStopTypes.get(ii) != types.get(ii)) { needsUpdate = true; break; } } if (!needsUpdate) { return; } tabStopValues.clear(); tabStopTypes.clear(); for (int ii = 0; ii < valuesSize; ii++) { tabStopValues.add(vals.get(ii)); TabStopTypes newType = TabStopTypes.TABSTOP_GENERIC; if (types != null && ii < types.size()) { newType = types.get(ii); } tabStopTypes.add(newType); } repaint(); } private void drawAllTabStops(final Graphics g, int originX, int originY) { if (tabStopValues.size() != 2) { // only handle caliper pairs for now return; } { int bin; int cx; final int margin = tabStopCalc.getMargin(); int ii = 0; bin = tabStopCalc.getBinAtTime(tabStopValues.get(ii)); cx = tabStopCalc.getLowCoordForBin(bin) - margin; drawTabStop(g, originX, originY, margin, cx, tabStopTypes.get(ii)); ii = 1; bin = tabStopCalc.getBinAtTime(tabStopValues.get(ii)); cx = (tabStopCalc.getLowCoordForBin(bin + 1) - 1) - margin; drawTabStop(g, originX, originY, margin, cx, tabStopTypes.get(ii)); } } private void drawTabStop( final Graphics g, int originX, int originY, int margin, int coord, TabStopTypes type) { if (coord < -margin || coord > coordCalculator.getDataPixels() + margin) { return; } int tickLen = TABSTOP_LENGTH; int x, y; // tick x and y // compute pixel location in axis direction int tickLocation = coord + paddingLow; if (orientation == HORIZONTAL_ORIENTATION) { x = tickLocation; int midY; if (tickPlacement == TICKS_ON_THE_BOTTOM) { y = originY - tickLen; midY = originY - TABSTOP_WIDTH; } else { y = originY + tickLen; midY = originY + TABSTOP_WIDTH; } int w = 0; Color c = Color.black; switch (type) { case TABSTOP_LEFT: w = -TABSTOP_WIDTH; c = tabStopColorLeft; break; case TABSTOP_RIGHT: w = TABSTOP_WIDTH; c = tabStopColorRight; break; default: case TABSTOP_GENERIC: g.setColor(Color.red); g.drawLine(x, originY, x, y); break; } if (w != 0) { Polygon p; { int xx[] = {x, x, x + w, x + w, x}; int yy[] = {originY, y, y, midY, originY}; p = new Polygon(xx, yy, xx.length); // This polygon represents a triangle with the above } g.setColor(c); g.fillPolygon(p); g.setColor(Color.DARK_GRAY); g.drawPolygon(p); } } } // --- string utilites private void drawRightAdjustedString(Graphics g, String label, int rightBoundary, int ycoord) { if (rightBoundary <= labelBoundaryCoord) { // right of string is already infringing on title return; } int xlabelsz = g.getFontMetrics(TEXT_FONT).stringWidth(label); int startx = rightBoundary - xlabelsz; if (startx >= labelBoundaryCoord) { g.drawString(label, startx, ycoord); } else { int availWidth = rightBoundary - labelBoundaryCoord; String printString = squishString(g, label, availWidth); if (printString != null) { xlabelsz = g.getFontMetrics(TEXT_FONT).stringWidth(printString); startx = rightBoundary - xlabelsz; g.drawString(printString, startx, ycoord); } } } private void drawLeftAdjustedString(Graphics g, String label, int leftBoundary, int ycoord) { g.drawString(label, leftBoundary, ycoord); // YXXX implement limited print later } private void drawCenteredString( Graphics g, String label, int labelCenter, int ycoord, int rightBoundary) { if (labelCenter <= labelBoundaryCoord) { // middle of string is already infringing on title return; } int xlabelsz = g.getFontMetrics(TEXT_FONT).stringWidth(label); int startx = labelCenter - xlabelsz / 2; if (startx >= labelBoundaryCoord) { g.drawString(label, startx, ycoord); } else { int availWidth = rightBoundary - labelBoundaryCoord; String printString = squishString(g, label, availWidth); if (printString != null) { g.drawString(printString, labelBoundaryCoord, ycoord); } } } private String squishString(Graphics g, String label, int availWidth) { int strlen; strlen = g.getFontMetrics(TEXT_FONT).stringWidth(label); if (strlen <= availWidth) { return label; } String newString = ".."; strlen = g.getFontMetrics(TEXT_FONT).stringWidth(newString); if (strlen > availWidth) { return null; } String currString = newString; int ii = 0; if (false) { ii += 1; // show first N characters then ".." newString = label.substring(0, ii) + currString; strlen = g.getFontMetrics(TEXT_FONT).stringWidth(newString); if (strlen > availWidth) { return currString; } ii += 1; // skip N characters currString = newString; int max = label.length(); // find largest tail segment that fits for (; ii < max; ii++) { newString = currString + label.substring(ii); strlen = g.getFontMetrics(TEXT_FONT).stringWidth(newString); if (strlen < availWidth) { return newString; } } } else { // chop off tailing characters and end with ".." int max = label.length(); currString = newString; // find largest head segment that fits for (ii = 0; ii < max; ii++) { newString = label.substring(0, max - ii - 1) + ".."; strlen = g.getFontMetrics(TEXT_FONT).stringWidth(newString); if (strlen < availWidth) { return newString; } } } return currString; } // --- return array which specifies tick spacing private long[] calcTickSteps(int pixelsAvailForData, int maxLabelSize, long dataRange) { // how far apart should labels be? int strPixels = maxLabelSize; if (isContinuous && strPixels < MIN_PIXELS_BETWEEN_LABELS) { // for continuous axes, require more space between labels strPixels = MIN_PIXELS_BETWEEN_LABELS; } if (strPixels <= 0) { strPixels = 1; } // estimate max # of labels based on estimated label size int maxNumLabels; maxNumLabels = pixelsAvailForData / strPixels; if (maxNumLabels < 1) { // one label may not fit! maxNumLabels = 1; } // types of steps to calculate long labelStep; // value step between labels long wholeStep; // value step for Ones long midStep; // value step for Halves long tenthStep; // value step for 10ths // determine labelStep double d_minValueStep; // smallest step allowed based on label size d_minValueStep = (double) dataRange / maxNumLabels; long multipleOfTen = getMultipleOfTen((long) d_minValueStep); double d_minValStepMSD; // most significant digit of minValueStep d_minValStepMSD = d_minValueStep / multipleOfTen; int labelMSD; // significant digit of step for Labels if (isContinuous) { // show a sparse # of labels & let the ticks show intermediate vals if (d_minValStepMSD <= 1.0) { labelMSD = 1; } else { labelMSD = 10; // try 10x first long estNumLabels = dataRange / (labelMSD * multipleOfTen); if (estNumLabels < 2 && d_minValStepMSD <= 5) { // label half-steps to increase # of labels labelMSD = 5; estNumLabels = dataRange / (labelMSD * multipleOfTen); if (estNumLabels < 2 && d_minValStepMSD <= 2) { // label half-steps to increase # of labels labelMSD = 2; } } } } else { // !isContinous // show as many labels as possible if (d_minValStepMSD <= 1.0) { labelMSD = 1; } else if (d_minValStepMSD <= 2) { labelMSD = 2; } else if (d_minValStepMSD <= 5) { labelMSD = 5; } else { labelMSD = 10; } } labelStep = labelMSD * multipleOfTen; // decide step for ticks if (d_minValStepMSD <= 1.0) { wholeStep = multipleOfTen; } else { wholeStep = multipleOfTen * 10; } midStep = wholeStep / 2; tenthStep = wholeStep / 10; if (labelMSD == 2) { midStep = 0; // don't emphasize "5" ticks if labels are at steps of 2 } long rc[] = new long[4]; // smallest tick first, label last rc[0] = tenthStep; rc[1] = midStep; rc[2] = wholeStep; rc[3] = labelStep; return rc; } private long getMultipleOfTen(long value) { long d = value; long multipleOfTen = 1; while (d >= 10) { d /= 10; multipleOfTen *= 10; } return multipleOfTen; } private int calcWidestLabel(final Graphics g, long lo, long hi, long dataStep) { if (!isFontInitialized()) { return 0; // YXXX or could return a guess } int strPixels = 0; long step = 1; if (isContinuous) { // just the endpoints are OK step = hi - lo; if (step < 1) { step = 1; } } for (long ii = lo; ii <= hi; ii += step) { String stmp = valueType.getFormattedValue(ii, dataStep); int itmp = g.getFontMetrics(TEXT_FONT).stringWidth(stmp); if (strPixels < itmp) { strPixels = itmp; } } return strPixels; } /** Recompute preferred size */ private boolean recomputePreferredSize(Graphics g) { boolean changed; if (orientation == HORIZONTAL_ORIENTATION) { changed = setPreferredForHorizontal(g); } else { changed = setPreferredForVertical(g); } return changed; } public void lockRulerThickness(Graphics g, boolean lock) { /* * YXXX not sure if it ok to use g from another context, but * font size is needed to set preferred ruler size, and * I don't know how else to get font size without g. * Maybe we should never attempt to lock ruler thickness? * Unfortunately, changing thickness might unexpectedly change * data range that can be shown on center panel. * For now, workaround is to provide g. */ if (!lockPreferredSize && lock) { recomputePreferredSize(g); } lockPreferredSize = lock; } // override parent public Dimension getPreferredSize() { return preferredD; } private boolean internalSetPreferredSize(int width, int height) { boolean changed = false; if (preferredD.width != width || preferredD.height != height) { preferredD.width = width; preferredD.height = height; changed = true; } return changed; } protected void paintComponent(Graphics g) { if (!isFontInitialized()) { // should never happen since <g> should allow font to be set return; } if (!lockPreferredSize) { boolean changed = recomputePreferredSize(g); if (changed) { revalidate(); // YXXX not supposed to revalidate from paint } } if (orientation == HORIZONTAL_ORIENTATION) { paintHorizontal(g); } else { paintVertical(g); } this.notifyPaintListeners(g); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/zoomruler/����������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�017045� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/zoomruler/PaintListener.java����������������������������������0000644�0001750�0001750�00000001642�14517772113�022377� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.zoomruler; import java.awt.Graphics; /** * A listener that listens when the timeline is repainted. It used by the zoomRuler overlay to know * when to redraw. */ public interface PaintListener { void timelinePainted(Graphics g); } ����������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/zoomruler/OverlayMouseHandler.java����������������������������0000644�0001750�0001750�00000003232�14517772113�023543� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.zoomruler; import java.awt.Cursor; /** * The OverlayMouseHander object allows for components with an overlayed image to defer mouse * handling in the overlay to the overlay. The overlayed image will be the zoomruler but this could * be used with other overlayed images that want mouse control. */ public interface OverlayMouseHandler { /** Test wether a mouse action was in the overlay. */ public boolean inOverlay(int x, int y); /** * Deactive mouse handling and let the overlay handle mouse event, presumably called when the * mouse gestures are within the overlay. */ public void deactivate(); /** * Active mouse handling and handling and handle mouse events, presumably called when the mouse * has left the overlay. */ public void activate(); /** Get the cursor cursor. */ public Cursor getCursor(); /** The default cursor to show when the mouse is in an overlay. */ public static final Cursor overlaycursor = new Cursor(Cursor.HAND_CURSOR); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/zoomruler/ZoomRulerOverlay.java�������������������������������0000644�0001750�0001750�00000074454�14517772113�023131� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.zoomruler; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.Vector; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.Timer; /** * The ZoomrulerOverlay class draws the ZoomRuler on top of a component. It registers a * MouseListener and MouseMotionListener on that component and handles mouse events that occur * within the overlay. It generates ZoomRoulerEvent objects when the user requests a change in zoom. * Along with the ruler to display the levels, a reset button and a revert button can be used. There * is also some support for a pan button but it is not fully supported at this point. The overlay * does require the component to interact with it. The overlay doesn't not know when to repaint. So * the component must tell it to repaint. Additionally MouseHandling usually should be coordinated * through the OverlayMouseHandler class. * * @author blewis */ public class ZoomRulerOverlay { // geometry (LD == long direction, SD == short direction) // distance from canvas edge private static final int BORDER = 1; // size of +/- and arrow boxes private static final int ANCHOR_SIZE = 14; // panning arrows private static final int ARROW_WIDTH = 4; private static final int ARROW_LENGTH = 4; // slider private static final int MARKER_LD = 6; private static final int MARKER_SD = 14; // slider bar (ruler) public static final int RULER_LD_DEFAULT = 50 + MARKER_LD; // 10e15/log(2)=50 // whitespace between anchor border and +/- labels private static final int LABEL_BORDER = 3; // colors and shape private static final Color borderColor = new Color(0x44, 0x44, 0x44); private static final Color buttonFillColor = new Color(0xf4, 0xf4, 0xf4); private static final Color labelShadowColor = new Color(0xcc, 0xcc, 0xcc); private static final Color shadowColor = new Color(0x99, 0x99, 0x99); private static final boolean useLabelShadow = true; private static final int rectRadius = 3; // components and listeners private Vector<ZoomRulerListener> listeners; private JComponent component; private static final ImageIcon revertImg = AnUtility.undo_icon; private static final ImageIcon resetImg = AnUtility.rset_icon; // levels, modified at runtime private int nlevels; // total levels private int ilevel; // current level // state private boolean active = true; private boolean dragging = false; private int recent_mouse_button = -1; // set by user at or near creation private static final int RULER_SD = 4; private final int RULER_LD; // full ruler including +/- boxes private static final int TOTAL_SD = 2 * BORDER + ANCHOR_SIZE; private final int TOTAL_LD; // +/- box far from origin private static final int ANCHOR2_OFFSET_SD = BORDER; private final int ANCHOR2_OFFSET_LD; // +/- box near origin private static final int ANCHOR1_OFFSET_SD = BORDER; private final int ANCHOR1_OFFSET_LD; // reset box private static final int RESET_OFFSET_SD = BORDER; private final int RESET_OFFSET_LD; // revert box private static final int REVERT_OFFSET_SD = BORDER; private final int REVERT_OFFSET_LD; private final boolean hasSlider; private final int orientation; private final boolean revertable; private final boolean PANNING = false; // enable panning mode private final boolean resetable1d; private final boolean resetable2d; private final boolean autoRepeat; private int xoff; private int yoff; private boolean paintBackground; private boolean isEnabled; // user-accessible enums public static final int VERTICAL_ORIENTATION = 1; public static final int HORIZONTAL_ORIENTATION = 2; /** * Instantiate a new overlay object that will draw the ruler on the given component, with nlevels, * starting at coordinate(x,y) with the specified orientation. Usage of Resetable and Revertable * buttons are also specified. */ public ZoomRulerOverlay( JComponent component, int x, int y, final int orientation, final int slider_length, final boolean resetable1d, final boolean resetable2d, final boolean revertable, final boolean autoRepeat) { if (slider_length < MARKER_LD * 2) { hasSlider = false; } else { hasSlider = true; } RULER_LD = slider_length; // precalculate offsets on the long axis RESET_OFFSET_LD = BORDER; if (resetable2d) { if (orientation == this.HORIZONTAL_ORIENTATION) { ANCHOR1_OFFSET_LD = RESET_OFFSET_LD + resetImg.getIconWidth() + 1; } else { ANCHOR1_OFFSET_LD = RESET_OFFSET_LD + resetImg.getIconHeight() + 1; } } else if (resetable1d) { ANCHOR1_OFFSET_LD = RESET_OFFSET_LD + ANCHOR_SIZE + 2; } else { ANCHOR1_OFFSET_LD = RESET_OFFSET_LD; } ANCHOR2_OFFSET_LD = ANCHOR1_OFFSET_LD + ANCHOR_SIZE + RULER_LD; REVERT_OFFSET_LD = ANCHOR2_OFFSET_LD + ANCHOR_SIZE + 1; int ld_total = REVERT_OFFSET_LD; if (orientation == this.HORIZONTAL_ORIENTATION) { if (revertable) ld_total += revertImg.getIconWidth(); } else { if (revertable) ld_total += revertImg.getIconHeight(); } TOTAL_LD = ld_total; this.component = component; this.nlevels = 0; this.ilevel = 0; this.xoff = x; this.yoff = y; this.orientation = orientation; this.resetable1d = resetable1d; this.resetable2d = resetable2d; this.revertable = revertable; this.autoRepeat = autoRepeat; listeners = new Vector(); initializeMouseListeners(); isEnabled = true; } /** Get the height of the overlay */ public int getHeight() { if (orientation == HORIZONTAL_ORIENTATION) return TOTAL_SD + 1; else { return TOTAL_LD + 1; } } /** Get the widht of the overlay */ public int getWidth() { if (orientation == HORIZONTAL_ORIENTATION) { return TOTAL_LD + 1; } else return TOTAL_SD + 1; } /** Get the horizontal offset in the component where the overlay is drawn */ public int getX() { return xoff; } /** Get the vertical offset in the component where the overlay is drawn */ public int getY() { return yoff; } /** Set the number of zoom levels to display */ public void setNumberOfLevels(int n) { if (n != nlevels && n >= 0) { nlevels = n; doRepaint(); } } /** Get the the number of possible levels */ public int getNumberOfLevels() { return nlevels; } /** quietly changes the level without notify listeners */ public void setZoomLevel(int il) { if (il < 0) { il = 0; // weird } else if (il >= nlevels) { il = nlevels - 1; // weird } if (ilevel != il && il < nlevels) { ilevel = il; // YXXX this might cause lack of paints doRepaint(); } } /** sets the current level and notifies listeners */ private void setCurrentLevel(int il) { setZoomLevel(il); notifyListeners(new ZoomRulerEvent(ZoomRulerEvent.SET_LEVEL, ilevel)); } /** sets the current level and notifies listeners */ private void setNotifyPlus() { notifyListeners(new ZoomRulerEvent(ZoomRulerEvent.LEVEL_PLUS, 0)); } /** sets the current level and notifies listeners */ private void setNotifyMinus() { notifyListeners(new ZoomRulerEvent(ZoomRulerEvent.LEVEL_MINUS, 0)); } /** Notify listeners of a revert event */ private void undo() { notifyListeners(new ZoomRulerEvent(ZoomRulerEvent.UNDO, 0)); } private void redo() { notifyListeners(new ZoomRulerEvent(ZoomRulerEvent.REDO, 0)); } /** Notify listeners of a pan event */ private void pan(int idir) { notifyListeners(new ZoomRulerEvent(ZoomRulerEvent.PAN, idir)); } /** Notify listeners of a rest event */ private void reset() { notifyListeners(new ZoomRulerEvent(ZoomRulerEvent.RESET, 0)); } /** Notify listeners of a ZoomRulerEvent */ private void notifyListeners(ZoomRulerEvent event) { for (ZoomRulerListener listener : listeners) { listener.zoomChanged(event); } } private boolean isInComponent(int x, int y) { if (x > xoff && x < xoff + getWidth() && y > yoff && y < yoff + getHeight()) { return true; } else { return false; } } private class TimelineMouseAdapter extends MouseAdapter { private Timer autoScrollTimer; private final int AUTO_PLUS_MINUS_REPEAT_TIME = 120; // ms between repeats private final int AUTO_PLUS_MINUS_REPEAT_INITIAL = 360; // ms before first repeat private int clickType = ZoomRulerEvent.UNKNOWN; public TimelineMouseAdapter() { if (autoRepeat) { autoScrollTimer = new Timer( AUTO_PLUS_MINUS_REPEAT_TIME, new ActionListener() { @Override public void actionPerformed(ActionEvent ae) { if (clickType == ZoomRulerEvent.LEVEL_MINUS) { setNotifyMinus(); } else if (clickType == ZoomRulerEvent.LEVEL_PLUS) { setNotifyPlus(); } else { int ii = 1; // weird autoScrollTimer.stop(); } } }); autoScrollTimer.setInitialDelay(AUTO_PLUS_MINUS_REPEAT_INITIAL); autoScrollTimer.setRepeats(true); } } public void mousePressed(MouseEvent event) { int button = event.getButton(); recent_mouse_button = button; if (button != event.BUTTON1) { return; } if (!active) return; int x = event.getX(); int y = event.getY(); clickType = getClickType(x, y); if (clickType == ZoomRulerEvent.LEVEL_MINUS || clickType == ZoomRulerEvent.LEVEL_PLUS) { if (autoScrollTimer != null && !autoScrollTimer.isRunning()) { autoScrollTimer.start(); } } } public void mouseReleased(MouseEvent event) { recent_mouse_button = -1; int button = event.getButton(); if (button != event.BUTTON1) { return; } if (autoScrollTimer != null) { autoScrollTimer.stop(); } if (!active && !dragging) return; int x = event.getX(); int y = event.getY(); // clickType<0 if (dragging) { processDrag(x, y); setCurrentLevel(ilevel); // notifies listeners dragging = false; return; } int releaseClickType = getClickType(x, y); if (releaseClickType >= 0) { if (releaseClickType != clickType) { // mouse drifted across buttons, do nothing return; } switch (releaseClickType) { case ZoomRulerEvent.LEVEL_MINUS: setNotifyMinus(); break; case ZoomRulerEvent.LEVEL_PLUS: setNotifyPlus(); break; case ZoomRulerEvent.PAN_RIGHT: case ZoomRulerEvent.PAN_LEFT: case ZoomRulerEvent.PAN_UP: case ZoomRulerEvent.PAN_DOWN: pan(releaseClickType); break; case ZoomRulerEvent.REDO: case ZoomRulerEvent.UNDO: undo(); break; case ZoomRulerEvent.RESET: reset(); break; case ZoomRulerEvent.UNKNOWN: default: { int ii = 0; // weird } } return; } else { // negative value int il = (-releaseClickType) - 1; setCurrentLevel(il); } } public void mouseDragged(MouseEvent event) { if (recent_mouse_button != event.BUTTON1) { return; } if (!active) return; if (!hasSlider) return; if (clickType >= 0) return; // initial click was not on ruler int x = event.getX(); int y = event.getY(); /* process if the coordinate is in the boundaries of the overaly */ if (dragging || isInComponent(x, y)) { processDrag(x, y); dragging = true; } } public void mouseMoved(MouseEvent e) {} public void mouseClicked(MouseEvent event) {} } /** Add listeners to the component to handle mouse events in the overlay */ private void initializeMouseListeners() { if (component == null) { return; } TimelineMouseAdapter timelineMouseAdapter = new TimelineMouseAdapter(); component.addMouseWheelListener(timelineMouseAdapter); component.addMouseMotionListener(timelineMouseAdapter); component.addMouseListener(timelineMouseAdapter); } /** Add ZoomRulerListener */ public void addZoomRulerListener(ZoomRulerListener listener) { listeners.add(listener); } /** Draw the Ruler */ public void paintRuler(Graphics g) { if (!isEnabled) { return; } if (component == null) { return; } if (paintBackground) { g.setColor(component.getBackground()); g.fillRect(xoff, yoff, getWidth(), getHeight()); } // Graphics2D g2d = (Graphics2D) g; // RenderingHints rhints = g2d.getRenderingHints(); // boolean antialiasOn = rhints.containsValue(RenderingHints.VALUE_ANTIALIAS_ON); // if(!antialiasOn){ // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // RenderingHints.VALUE_ANTIALIAS_ON); // } paintRuler(g, xoff, yoff); if (PANNING) { paintPanButtons(g, xoff, yoff); } // if(!antialiasOn){ // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // RenderingHints.VALUE_ANTIALIAS_OFF); // } } private void paintPanButtons(Graphics g, final int xstart, final int ystart) { // pan buttons would need work to make them usable final int sz = ANCHOR1_OFFSET_LD; g.setColor(borderColor); g.drawRect(BORDER, 1, ANCHOR_SIZE, ANCHOR_SIZE); g.drawRect(1, BORDER, ANCHOR_SIZE, ANCHOR_SIZE); g.drawRect(BORDER, BORDER, ANCHOR_SIZE, ANCHOR_SIZE); g.drawRect(BORDER + BORDER, BORDER, ANCHOR_SIZE, ANCHOR_SIZE); g.drawRect(BORDER, BORDER + BORDER, ANCHOR_SIZE, ANCHOR_SIZE); // g.fillRect(xstart, ystart, (2 * BORDER + ANCHOR_SIZE), (2 * BORDER + ANCHOR_SIZE)); int ps = revertImg.getIconHeight(); int pb = (sz - ps) / 2; g.setColor(buttonFillColor); g.fillOval(xstart + pb, ystart + pb, ps, ps); g.setColor(borderColor); // g.drawOval(xstart+pb, ystart+pb, ps, ps); int xend = xstart + sz - pb; int yend = ystart + sz - pb; int xmid = xstart + pb + ps / 2; int ymid = ystart + pb + ps / 2; g.drawLine(xstart + pb, ymid, xend, ymid); g.drawLine(xmid, ystart + pb, xmid, yend); int xps[] = new int[3]; int yps[] = new int[3]; xps[0] = xmid; xps[1] = xmid + ARROW_WIDTH; xps[2] = xmid - ARROW_WIDTH; yps[0] = ystart + pb; yps[1] = ystart + pb + ARROW_LENGTH; yps[2] = ystart + pb + ARROW_LENGTH; g.fillPolygon(xps, yps, 3); xps[0] = xmid; xps[1] = xmid + ARROW_WIDTH; xps[2] = xmid - ARROW_WIDTH; yps[0] = yend; yps[1] = yend - ARROW_LENGTH; yps[2] = yend - ARROW_LENGTH; g.fillPolygon(xps, yps, 3); xps[0] = xstart + pb; xps[1] = xstart + pb + ARROW_LENGTH; xps[2] = xstart + pb + ARROW_LENGTH; yps[0] = ymid; yps[1] = ymid + ARROW_WIDTH; yps[2] = ymid - ARROW_WIDTH; g.fillPolygon(xps, yps, 3); xps[0] = xend; xps[1] = xend - ARROW_LENGTH; xps[2] = xend - ARROW_LENGTH; yps[0] = ymid; yps[1] = ymid + ARROW_WIDTH; yps[2] = ymid - ARROW_WIDTH; g.fillPolygon(xps, yps, 3); } private void paintRuler(Graphics g, final int inX, final int inY) { for (int ii = 0; ii < 4; ii++) { if (!useLabelShadow && ii == 2) { continue; } final int xOffset, yOffset; // includes shadow shift // final int xstart, ystart; final Color lineColor; final Color fillColor; final boolean doLabel; final boolean doFill; final boolean doIcons; final boolean doBorder; switch (ii) { case 0: // border shadow doFill = true; doBorder = true; doLabel = false; doIcons = false; lineColor = shadowColor; fillColor = shadowColor; xOffset = inX + 1; yOffset = inY + 1; break; case 1: // border main doFill = true; doBorder = true; doLabel = false; doIcons = true; lineColor = borderColor; fillColor = buttonFillColor; xOffset = inX; yOffset = inY; break; case 2: // label shadow doFill = false; doBorder = false; doLabel = true; doIcons = false; lineColor = labelShadowColor; fillColor = labelShadowColor; xOffset = inX + 1; yOffset = inY + 1; break; case 3: default: // label main doFill = false; doBorder = false; doLabel = true; doIcons = false; lineColor = borderColor; fillColor = buttonFillColor; xOffset = inX; yOffset = inY; break; } // Draw anchors and main bar { final int ix1, iy1; final int ix2, iy2; final int sx, sy, sl, sw; if (orientation == this.HORIZONTAL_ORIENTATION) { ix1 = xOffset + ANCHOR1_OFFSET_LD; iy1 = yOffset + ANCHOR1_OFFSET_SD; ix2 = xOffset + ANCHOR2_OFFSET_LD; iy2 = yOffset + ANCHOR2_OFFSET_SD; sx = ix1 + ANCHOR_SIZE; sy = iy1 + ANCHOR_SIZE / 2 - 2; sw = RULER_LD; sl = RULER_SD; } else { ix1 = xOffset + ANCHOR1_OFFSET_SD; iy1 = yOffset + ANCHOR1_OFFSET_LD; ix2 = xOffset + ANCHOR2_OFFSET_SD; iy2 = yOffset + ANCHOR2_OFFSET_LD; sx = ix1 + ANCHOR_SIZE / 2 - 2; sy = iy1 + ANCHOR_SIZE; sw = RULER_SD; sl = RULER_LD; } if (doFill) { g.setColor(fillColor); myFillRect(g, ix1, iy1, ANCHOR_SIZE, ANCHOR_SIZE); myFillRect(g, ix2, iy2, ANCHOR_SIZE, ANCHOR_SIZE); if (hasSlider) { myFillRect(g, sx, sy, sw, sl); } } if (doBorder) { g.setColor(lineColor); myDrawRect(g, ix1, iy1, ANCHOR_SIZE, ANCHOR_SIZE); myDrawRect(g, ix2, iy2, ANCHOR_SIZE, ANCHOR_SIZE); if (hasSlider) { myDrawRect(g, sx, sy, sw, sl); } } if (doLabel) { g.setColor(lineColor); if (orientation == this.HORIZONTAL_ORIENTATION) { drawMinusLabel(g, ix1, iy1, ANCHOR_SIZE, ANCHOR_SIZE); drawPlusLabel(g, ix2, iy2, ANCHOR_SIZE, ANCHOR_SIZE); } else { drawPlusLabel(g, ix1, iy1, ANCHOR_SIZE, ANCHOR_SIZE); drawMinusLabel(g, ix2, iy2, ANCHOR_SIZE, ANCHOR_SIZE); } } if (hasSlider && nlevels > 0) { final float wp = pixelsPerLevel(); final int ix, iy, length, width; if (orientation == HORIZONTAL_ORIENTATION) { iy = iy1 + ANCHOR_SIZE / 2 - MARKER_SD / 2; ix = sx + Math.round(wp * ilevel); length = MARKER_LD; width = MARKER_SD; } else { iy = sy + Math.round(wp * (nlevels - 1 - ilevel)); ix = ix1 + ANCHOR_SIZE / 2 - MARKER_SD / 2; width = MARKER_LD; length = MARKER_SD; } if (doFill) { g.setColor(fillColor); myFillRect(g, ix, iy, length, width); } if (doBorder) { g.setColor(lineColor); myDrawRect(g, ix, iy, length, width); } } } if (resetable1d || resetable2d) { final int resetX, resetY; if (orientation == this.HORIZONTAL_ORIENTATION) { resetX = xOffset + RESET_OFFSET_LD; resetY = yOffset + RESET_OFFSET_SD; } else { resetX = xOffset + RESET_OFFSET_SD; resetY = yOffset + RESET_OFFSET_LD; } if (resetable1d) { if (doFill) { g.setColor(fillColor); myFillRect(g, resetX, resetY, ANCHOR_SIZE, ANCHOR_SIZE); } if (doBorder) { g.setColor(lineColor); myDrawRect(g, resetX, resetY, ANCHOR_SIZE, ANCHOR_SIZE); } if (doLabel) { g.setColor(lineColor); drawResetLeftLabel(g, resetX, resetY, ANCHOR_SIZE, ANCHOR_SIZE); } } else if (resetable2d) { if (doIcons) { final int rx, ry; if (orientation == HORIZONTAL_ORIENTATION) { int offset = (ANCHOR_SIZE - resetImg.getIconWidth()) / 2; rx = resetX + BORDER; ry = resetY + offset + BORDER; } else { int offset = (ANCHOR_SIZE - resetImg.getIconHeight()) / 2; rx = resetX + offset + BORDER; ry = resetY + BORDER; } g.drawImage(resetImg.getImage(), rx, ry, null); } } } if (revertable) { if (doIcons) { final int rx, ry; if (orientation == HORIZONTAL_ORIENTATION) { int iy = (REVERT_OFFSET_SD - revertImg.getIconHeight()) / 2 + 2; rx = xOffset + REVERT_OFFSET_LD; ry = yOffset + iy; } else { int ix = (REVERT_OFFSET_SD - revertImg.getIconWidth()) / 2 + 1; rx = xOffset + ix; ry = yOffset + REVERT_OFFSET_LD; } g.drawImage(revertImg.getImage(), rx, ry, null); } } } } private void myDrawRect(Graphics g, int x1, int y1, int x2, int y2) { if (rectRadius > 1) { g.drawRoundRect(x1, y1, x2, y2, rectRadius, rectRadius); } else { g.drawRect(x1, y1, x2, y2); } } private void myFillRect(Graphics g, int x1, int y1, int w, int h) { if (rectRadius > 1) { g.fillRoundRect(x1, y1, w, h, rectRadius, rectRadius); } else { g.fillRect(x1, y1, w, h); } } private void drawMinusLabel(Graphics g, final int x, final int y, int width, int height) { final int x1 = x + LABEL_BORDER; final int y1 = y + height / 2; final int x2 = x + width - LABEL_BORDER; final int y2 = y1; g.drawLine(x1, y1, x2, y2); } private void drawResetLeftLabel(Graphics g, final int x, final int y, int width, int height) { final int x1 = x + (width - ARROW_LENGTH) / 2; final int yBorder = (height - ARROW_WIDTH * 2) / 2 + 1; final int y1 = y + yBorder; final int x2 = x1; final int y2 = y + width - yBorder; g.drawLine(x1, y1, x2, y2); // triangle: { int xps[] = new int[3]; int yps[] = new int[3]; final int ymid = y + height / 2; final int xstart = x1 + 1; xps[0] = xstart; xps[1] = xstart + ARROW_LENGTH; xps[2] = xstart + ARROW_LENGTH; yps[0] = ymid; yps[1] = ymid + ARROW_WIDTH; yps[2] = ymid - ARROW_WIDTH; g.fillPolygon(xps, yps, 3); } } private void drawPlusLabel(Graphics g, final int x, final int y, int width, int height) { drawMinusLabel(g, x, y, width, height); final int x1 = x + width / 2; final int y1 = y + LABEL_BORDER; final int x2 = x1; final int y2 = y + width - LABEL_BORDER; g.drawLine(x1, y1, x2, y2); } /** Handle a mouse click at (xin, yin) */ // NOTE: this method should not change class state. private int getClickType(final int _mouseX, final int _mouseY) { final int mouseX = _mouseX - 1; final int mouseY = _mouseY - 1; /* create local x and y relative to the Overlay */ if (!active) return ZoomRulerEvent.UNKNOWN; if (!isInComponent(mouseX, mouseY)) return ZoomRulerEvent.UNKNOWN; final int xl, yl; if (orientation == this.VERTICAL_ORIENTATION) { /* the logic is set up for a horizontal orientation, swap the values */ xl = mouseY - yoff; yl = mouseX - xoff; } else { xl = mouseX - xoff; yl = mouseY - yoff; } /* if PANNING is supported, handle it here */ if (nlevels <= 0) return ZoomRulerEvent.UNKNOWN; /* check for click on ZoomOut Anchor */ if (xl >= ANCHOR1_OFFSET_LD && xl <= ANCHOR1_OFFSET_LD + ANCHOR_SIZE && yl >= ANCHOR1_OFFSET_SD && yl <= ANCHOR1_OFFSET_SD + ANCHOR_SIZE) { if (orientation == this.VERTICAL_ORIENTATION) { if (ilevel + 1 < nlevels) { return ZoomRulerEvent.LEVEL_PLUS; } } else { if (ilevel > 0) { return ZoomRulerEvent.LEVEL_MINUS; } } return ZoomRulerEvent.UNKNOWN; } /* check for a click on the ZoomIn Anchor */ if (xl >= ANCHOR2_OFFSET_LD && xl <= ANCHOR2_OFFSET_LD + ANCHOR_SIZE && yl >= ANCHOR2_OFFSET_SD && yl <= ANCHOR2_OFFSET_SD + ANCHOR_SIZE) { if (orientation == this.VERTICAL_ORIENTATION) { if (ilevel > 0) { return ZoomRulerEvent.LEVEL_MINUS; } } else { if (ilevel + 1 < nlevels) { return ZoomRulerEvent.LEVEL_PLUS; } } return ZoomRulerEvent.UNKNOWN; } /* check for a click on the ruler */ if (hasSlider && nlevels > 0 && xl > ANCHOR1_OFFSET_LD + ANCHOR_SIZE && xl < ANCHOR2_OFFSET_LD && yl > ANCHOR1_OFFSET_SD && yl < ANCHOR1_OFFSET_SD + ANCHOR_SIZE) { final int levelValue = getLevel(_mouseX, _mouseY); return -(levelValue + 1); } /* check for a click on the 1d reset button*/ if (resetable1d) { int s1 = RESET_OFFSET_LD; int s2 = RESET_OFFSET_SD; int h = ANCHOR_SIZE; int w = ANCHOR_SIZE; if (xl > s1 && xl < s1 + w && yl > s2 && yl < s2 + h) { return ZoomRulerEvent.RESET; } } /* check for a click on the 2d reset button*/ if (resetable2d) { final int h, w; if (orientation == this.VERTICAL_ORIENTATION) { // reversed w = resetImg.getIconHeight(); h = resetImg.getIconWidth(); } else { h = resetImg.getIconHeight(); w = resetImg.getIconWidth(); } final int s1 = RESET_OFFSET_LD; final int s2 = RESET_OFFSET_SD + (ANCHOR_SIZE - h) / 2; if (xl > s1 && xl < s1 + w && yl > s2 && yl < s2 + h) { return ZoomRulerEvent.RESET; } } /* check for a click on the revert button*/ if (revertable) { final int h, w; if (orientation == this.VERTICAL_ORIENTATION) { // reversed w = revertImg.getIconHeight(); h = revertImg.getIconWidth(); } else { h = revertImg.getIconHeight(); w = revertImg.getIconWidth(); } int s1 = REVERT_OFFSET_LD; final int s2 = RESET_OFFSET_SD + (ANCHOR_SIZE - h) / 2; if (xl > s1 && xl < s1 + w && yl > s2 && yl < s2 + h) { return ZoomRulerEvent.UNDO; } } return ZoomRulerEvent.UNKNOWN; } /** Process a mouse drag at (x, y). */ private void processDrag(final int _mouseX, final int _mouseY) { if (!active && !dragging) return; if (nlevels <= 0) return; if (!hasSlider) return; final int levelValue = getLevel(_mouseX, _mouseY); setZoomLevel(levelValue); } private float pixelsPerLevel() { return (float) (RULER_LD - MARKER_LD) / (nlevels - 1); } private int getLevel(final int _mouseX, final int _mouseY) { final int mouseX = _mouseX - 1; final int mouseY = _mouseY - 1; final int sliderX; if (orientation == this.VERTICAL_ORIENTATION) { /* vertical ruler level decreases as y values increase, so invert * coordiantes on the ruler, if outside the ruler it may be on the * revert button */ int offsetAdjusted = mouseY - yoff; sliderX = (ANCHOR2_OFFSET_LD - MARKER_LD / 2) - offsetAdjusted - 1; } else { int offsetAdjusted = mouseX - xoff; sliderX = offsetAdjusted - (ANCHOR1_OFFSET_LD + ANCHOR_SIZE + MARKER_LD / 2); } /* subtract of pan area */ final float pixels_per_level = pixelsPerLevel(); int levelValue = Math.round(sliderX / pixels_per_level); if (levelValue < 0) { levelValue = 0; } if (levelValue > nlevels - 1) { levelValue = nlevels - 1; } return levelValue; } /** Check if a (x,y) coordinate is with the overlay. */ public boolean withinBounds(int x, int y) { x -= xoff; y -= yoff; int w = getWidth(); if (x < 0 || x > w) { return false; } int h = getHeight(); if (y < 0 || y > h) { return false; } return true; } /** Turn on mouse handling */ public void activateMouseHandling() { active = true; } /** Turn off mouse handling */ public void deactivateMouseHandling() { active = false; } /** Set the component that the overlay is drawn on */ public void setComponent(JComponent component) { this.component = component; initializeMouseListeners(); } /** Determine if a mouse drag is occuring */ public boolean isDragging() { return dragging; } /** Return dimensions of the overlay */ public static int getDefaultDimension() { return TOTAL_SD; } /** Set the offset at which to draw the overlay */ public void setOffsets(int x, int y) { if (this.xoff != x || this.yoff != y) { this.xoff = x; this.yoff = y; doRepaint(); } } /* * Set the boolean to indicate wether to paint a solid background or let the * underlying image show through */ public void setPaintBackground(boolean pb) { this.paintBackground = pb; } public void show(boolean show) { if (isEnabled != show) { isEnabled = show; dragging = false; active = isEnabled; // YXXX not sure if this is right doRepaint(); } } private void doRepaint() { if (component != null) { component.repaint(); } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/zoomruler/ZoomRulerListener.java������������������������������0000644�0001750�0001750�00000001431�14517772113�023256� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.zoomruler; public interface ZoomRulerListener { public void zoomChanged(ZoomRulerEvent event); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/zoomruler/ZoomRulerComponent.java�����������������������������0000644�0001750�0001750�00000004210�14517772113�023431� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.zoomruler; import java.awt.Dimension; import java.awt.Graphics; import javax.accessibility.Accessible; import javax.accessibility.AccessibleContext; import javax.swing.JComponent; import javax.swing.JLabel; public class ZoomRulerComponent extends JComponent implements Accessible { private JLabel accessibleHelper = new JLabel(); private ZoomRulerOverlay overlay; public ZoomRulerComponent( int orientation, int slide_length, boolean resetable1d, boolean revertable, boolean autoRepeat) { super(); overlay = new ZoomRulerOverlay( this, 0, 0, orientation, slide_length, resetable1d, false, revertable, autoRepeat); Dimension d; d = new Dimension(overlay.getWidth() + 1, overlay.getHeight() + 1); super.setMinimumSize(d); super.setMaximumSize(d); super.setPreferredSize(d); } public void setNumberOfLevels(int n) { overlay.setNumberOfLevels(n); } public void addZoomRulerListener(ZoomRulerListener listener) { overlay.activateMouseHandling(); overlay.addZoomRulerListener(listener); } @Override public void setEnabled(boolean enable) { overlay.show(enable); } public void setZoomLevel(int il) { overlay.setZoomLevel(il); } @Override public void paintComponent(Graphics g) { super.paintComponent(g); overlay.paintRuler(g); } @Override public AccessibleContext getAccessibleContext() { return accessibleHelper.getAccessibleContext(); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/util/zoomruler/ZoomRulerEvent.java���������������������������������0000644�0001750�0001750�00000005572�14517772113�022564� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.util.zoomruler; /** * A an event the was triggered from the ZoomRuler. The types of possible events include - set level * - The zoom level changes to a specific level revert - The zoom level changes back to the prevous * level pan - A pan up, down, left, or right is requested reset - Zoom all the way out to the * initial level. */ public class ZoomRulerEvent { private int arg; private int type; // Identifiers for click locations // NOTE: negative numbers reserved for indicating the level selected: public static final int SET_LEVEL = 11; public static final int UNDO = 12; public static final int PAN = 13; public static final int LEVEL_PLUS = 14; public static final int LEVEL_MINUS = 15; public static final int REDO = 16; public static final int PAN_UP = 0; public static final int PAN_RIGHT = 1; public static final int PAN_DOWN = 2; public static final int PAN_LEFT = 3; public static final int RESET = 4; public static final int UNKNOWN = Integer.MAX_VALUE; /** Create a new event with the specified type and one argument. */ public ZoomRulerEvent(int type, int arg) { this.type = type; this.arg = arg; } /** Get the specifies the zoom level for SET_LEVEL events */ // XXXmpview need error handling public int getZoomLevel() { return arg; } /** Get direction for pan events */ // XXXmpview need error handling public int getDirection() { return arg; } /** Return true if this is a revert event. */ public boolean isUndo() { return (type == UNDO); } /** Return true if this is a revert event. */ public boolean isRedo() { return (type == REDO); } /** Return true if this is a Zoom Level Change event. */ public boolean isLevelChange() { return (type == SET_LEVEL); } /** Return true if this is a Zoom Plus click */ public boolean isLevelPlus() { return (type == LEVEL_PLUS); } /** Return true if this is a Zoom Minus click */ public boolean isLevelMinus() { return (type == LEVEL_MINUS); } /** Return true if this is a pan event. */ public boolean isPan() { return (type == PAN); } /** Return true if this is a reset event. */ public boolean isReset() { return (type == RESET); } } ��������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/FuncListDisp.java��������������������������������������������������0000644�0001750�0001750�00000130116�14517772113�017151� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.AnDisplay.DSP_Functions; import static org.gprofng.mpmt.AnDisplay.DSP_Lines; import static org.gprofng.mpmt.AnDisplay.DSP_PCs; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.AnTable.SelObjInfo; import org.gprofng.mpmt.export.Export; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.CompareModeSetting.CompareMode; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.settings.ViewsSetting; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.KeyStroke; import javax.swing.border.LineBorder; public class FuncListDisp extends AnDisplay implements ExportSupport { // public AnHotGap gap; // defined in AnDisplay protected AnTable table; protected long sel_func, sel_src; protected int name_col; protected String[] names; private int[] src_type; private boolean can_comp; private int prevScroll = -1; protected long[] current_ids; protected boolean ignoreSelected = false; protected boolean updateSummary = true; /** Keeps last warning to avoid showing the same warning message many times */ private String lastWarning = null; protected JPanel warningPane; // Constructor public FuncListDisp( final AnWindow window, final int type, final int subtype, final String help_id) { super(window, type, subtype, help_id); sel_func = 0; sel_src = 0; name_col = 0; can_comp = false; current_ids = null; } @Override public void requestFocus() { if (table != null) { table.requestFocus(); } } @Override public JPopupMenu getFilterPopup() { if (table != null) { return table.initPopup(true); } else { return null; } } // Initialize GUI components @Override protected void initComponents() { // System.err.println("XXX In FLD initComponents()"); setLayout(new BorderLayout()); String acName = null; String acDesc = null; JLabel acLabel = null; switch (type) { case AnDisplay.DSP_Functions: acName = AnLocale.getString("Functions"); acDesc = AnLocale.getString("Show function list"); break; case AnDisplay.DSP_Source: acName = AnLocale.getString("Source"); acDesc = AnLocale.getString("Show source for selected function"); break; case AnDisplay.DSP_IO: case AnDisplay.DSP_IOFileDescriptors: case AnDisplay.DSP_IOCallStacks: acName = AnLocale.getString("IOActivity"); acDesc = AnLocale.getString("Show I/O activity for selected application"); break; case AnDisplay.DSP_Heap: acName = AnLocale.getString("HeapActivity"); acDesc = AnLocale.getString("Show Heap activity for selected application"); break; case AnDisplay.DSP_Disassembly: acName = AnLocale.getString("Disasm"); acDesc = AnLocale.getString("Show assembly for selected function"); break; case AnDisplay.DSP_Lines: acName = AnLocale.getString("Hot Lines"); acDesc = AnLocale.getString("Show hot lines"); break; case AnDisplay.DSP_PCs: acName = AnLocale.getString("PC"); acDesc = AnLocale.getString("Show hot PCs"); break; case AnDisplay.DSP_IndexObject: // XXX: This is not a good idea to use subtype, // but we don't have a better API yet. if ((0 <= subtype) && (9 >= subtype)) { switch (subtype) { case 0: // Threads acName = AnLocale.getString("Threads"); acDesc = acName; break; case 1: // CPUs acName = AnLocale.getString("CPUs"); acDesc = acName; break; case 2: // Samples acName = AnLocale.getString("Samples"); acDesc = acName; break; case 3: // Seconds acName = AnLocale.getString("Seconds"); acDesc = acName; break; case 4: // Processes acName = AnLocale.getString("Processes"); acDesc = acName; break; case 5: // ExperimentIDs acName = AnLocale.getString("ExperimentIDs"); acDesc = acName; break; case 6: // Data Size acName = AnLocale.getString("Data Size"); acDesc = acName; break; case 7: // Duration acName = AnLocale.getString("Duration"); acDesc = acName; break; case 8: // OpenMP Parallel Region acName = AnLocale.getString("OpenMP Parallel Region"); acDesc = acName; break; case 9: // OpenMP Tasks acName = AnLocale.getString("OpenMP Tasks"); acDesc = acName; break; } } break; } if (acName != null) { acLabel = new JLabel(acName, JLabel.RIGHT); } table = new AnTable(type, true, true, can_sort, false, true, true, true, acName, acDesc, acLabel); table.setParent(this); if (acLabel != null) { acLabel.setVisible(false); acLabel.setDisplayedMnemonic(acName.charAt(0)); table.add(acLabel); } table.addAnListener(new TableHandler()); add(table, BorderLayout.CENTER); // if (type == DSP_DataLayout) { // HotGapPanel hotGapPanel = createHotGapPanel(); // table.setHotGapPanel(hotGapPanel); // add(hotGapPanel, BorderLayout.EAST); // } switch (type) { case AnDisplay.DSP_Source: warningPane = new JPanel(); warningPane.setVisible(false); warningPane.setBorder(new LineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR)); add(warningPane, BorderLayout.SOUTH); break; } } private static JPanel toolbarPanel = null; // Fixup: XXXX ugly design public void updateToolBar() { if (type != AnDisplay.DSP_Functions) { return; } if (backForwardControls == null) { backForwardControls = new BackForwardControls(); } backForwardControls.updateToolBarStatus(); FuncListDisp.getToolbarPanelInternal().removeAll(); FuncListDisp.getToolbarPanelInternal().add(backForwardControls, BorderLayout.CENTER); FuncListDisp.getToolbarPanelInternal().repaint(); } protected BackForwardControls backForwardControls = null; protected JPanel backForwardControlsPanel = null; public static JPanel getToolbarPanelInternal() { if (toolbarPanel == null) { toolbarPanel = new JPanel(); toolbarPanel.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); toolbarPanel.setLayout(new BorderLayout()); } return toolbarPanel; } @Override public JPanel getToolbarPanel() { return getToolbarPanelInternal(); } /** * @return the settings */ public Settings getSettings() { return AnWindow.getInstance().getSettings(); } protected class BackForwardControls extends JPanel { protected AnIconButton backButton; protected AnIconButton forwardButton; public BackForwardControls() { setOpaque(false); setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints; // Back button gridBagConstraints = new GridBagConstraints(); backButton = new AnIconButton(AnUtility.goBackwardIcon); backButton.setMargin(new Insets(2, 0, 2, 2)); backButton.setToolTipText( AnLocale.getString("Back") + AnUtility.keyStrokeToStringFormatted(KeyboardShortcuts.backwardActionShortcut)); backButton.setEnabled(true); backButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // Hook it up to back action; table.goBack(); } }); // Backward KeyStroke keyStrokeBackward = KeyboardShortcuts.backwardActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeBackward, keyStrokeBackward); getActionMap() .put( keyStrokeBackward, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { backButton.doClick(); } }); add(backButton, gridBagConstraints); // Back button gridBagConstraints = new GridBagConstraints(); forwardButton = new AnIconButton(AnUtility.goForwardIcon); forwardButton.setMargin(new Insets(2, 4, 2, 4)); forwardButton.setToolTipText( AnLocale.getString("Forward") + AnUtility.keyStrokeToStringFormatted(KeyboardShortcuts.forwardActionShortcut)); forwardButton.setEnabled(true); forwardButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // Hook it up to forward action; table.goForward(); } }); // Forward KeyStroke keyStrokeForward = KeyboardShortcuts.forwardActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStrokeForward, keyStrokeForward); getActionMap() .put( keyStrokeForward, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { forwardButton.doClick(); } }); add(forwardButton, gridBagConstraints); } public void updateToolBarStatus() { if (backButton != null) { backButton.setEnabled(table.canGoBack()); } if (forwardButton != null) { forwardButton.setEnabled(table.canGoForward()); } } } public void tryAddNewObj(int row) { // add new obj to history if it's different from current if (table.getNavigationHistoryPool().getHistory().enabled && table.getType() == AnDisplay.DSP_Functions) { SelObjInfo cur_so = table.getNavigationHistoryPool().getHistory().getCurrent(); if (cur_so == null || cur_so.lineno != row) { SelObjInfo new_so = new SelObjInfo(0, row, ""); table.getNavigationHistoryPool().getHistory().goToNew(new_so); } else { table.getNavigationHistoryPool().getHistory().newAdded = false; } } } // Clear display @Override public void clear() { if (table != null) { table.removeAll(); } } /* * Returns Total values for MET_CALL metric list (Temporary solution) */ public Object[] getCurrentTotal() { final String mlistStr = "MET_CALL"; final String typeStrFunc = "FUNCTION"; final String subtypeStr = "0"; // + DSP_SOURCE; // final String stab_callers = "CALLERS"; final String stab_callees = "CALLEES"; // final String stab_self = "SELF"; Object[] total = null; Object[] raw_data_with_ids = window.getTableDataV2(mlistStr, stab_callees, typeStrFunc, subtypeStr, null /*cstack*/); if (null == raw_data_with_ids) { return total; } final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(type); Object[][] processed_data = localProcessData(mlist, raw_data_with_ids); int len = processed_data.length; if (len > 0) { total = new Object[len]; for (int i = 0; i < len; i++) { total[i] = processed_data[i][0]; } } return total; } /** Copy all lines to the system clipboard */ protected void copyAll() { String text = exportAsText(null, ExportFormat.TEXT, null); copyToClipboard(text); } /** Copy selected lines to the system clipboard */ protected void copySelected() { String sortedby = AnLocale.getString("sorted by metric:"); String textImage = ""; textImage = table.printTableHeader(sortedby, MaximumValues); if (null == MaximumValues) { return; // empty report } int printLimit = 0; textImage += table.printSelectedTableContents(MaximumValues, printLimit); copyToClipboard(textImage); } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String sortedby = AnLocale.getString("sorted by metric:"); String textImage = ""; if (format == ExportFormat.TEXT) { textImage = table.printTableHeader(sortedby, MaximumValues); if (null == MaximumValues) { return textImage; // empty report } int printLimit = limit != null ? limit : 0; textImage += table.printTableContents(MaximumValues, printLimit); } else if (format == ExportFormat.CSV || format == ExportFormat.HTML) { // FIXUP: code shold be moved form gp-display-text to GUI AnUtility.checkIPCOnWrongThread(false); Export.setLimit(limit); Export.setFormat(format, delimiter); String fake_printer = "-"; textImage = Export.printData(type, subtype, fake_printer, null); // IPC call AnUtility.checkIPCOnWrongThread(true); } return textImage; } // Get new selected func index & compare to the old one // Note: must be called from doCompute protected final long getFuncObj() { final long func_obj; final long src_obj; // System.err.println("XXX In FLD getFuncObj()"); // need Total/Maximum from func-list data window .getFunctionsView() .computeIfNeeded(); // on worker thread and synchronized (AnVariable.mainFlowLock) func_obj = window.getSelectedObject().getSelObj(DSP_Functions, 0); if (sel_func != func_obj) { computed = false; if (type == DSP_Source) { src_obj = window.getSelectedObject().getSelObj(DSP_SourceSelectedObject, 0); if (src_obj != sel_src) { sel_src = src_obj; } } } else if (type != DSP_Source) { computed = false; } else { src_obj = window.getSelectedObject().getSelObj(DSP_SourceSelectedObject, 0); if (src_obj != sel_src) { computed = false; sel_src = src_obj; } } return func_obj; } private String getTabName() { List<ViewsSetting.View> indx_tablist = AnWindow.getInstance().getSettings().getViewsSetting().getIndexViews(); if (type == AnDisplay.DSP_IndexObject && subtype < indx_tablist.size()) { AnWindow.AnDispTab adt = indx_tablist.get(subtype).getAnDispTab(); return adt.getTCmd(); } return ""; // NO18N } protected int getMetricMType() { if (isOmpInxObj()) { return AnDisplay.DSP_Functions; // FIXUP: this is UGLY!!!!!!!!!!! } else { return type; } } protected boolean isOmpInxObj() { if (type == AnDisplay.DSP_IndexObject) { String cmd = getTabName(); if (cmd.equalsIgnoreCase("OMP_preg") // NO18N || cmd.equalsIgnoreCase("OMP_task")) { // NO18N return true; } } return false; } // Compute & update function list table @Override public void doCompute() { final long sel_obj; int new_ind = -1; boolean reset_new_ind = false; final int sort_ind; final Object[] raw_data; final String pwarnstr; final MetricLabel[] label; AnUtility.checkIfOnAWTThread(false); // Not selected if (!selected && !ignoreSelected) { return; } if (inCompute) { // NM TEMPORARY should be synchronized return; } else { inCompute = true; } // System.err.println("XXX In FLD doCompute - 1 ()"); // window.setBusyCursor(true); if (can_comp) { // System.err.println("XXX In FLD doCompute - 2 ()"); sel_obj = window.getSelectedObject().getSelObj(DSP_Lines, 0); sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) can_comp = false; computed = false; } else { // System.err.println("XXX In FLD doCompute - 3 ()"); sel_obj = window.getSelectedObject().getSelObj(type, subtype); if (can_sort) { // Function/LINE/PC sel_func = sel_obj; } else { // Annotated src/dis sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) } } // Special code for Index tabs and for OpenMP tabs int typeForPresentation = type; String typeStr = "INDEXOBJ"; String subtypeStr = "" + subtype; String modeStr = "ALL"; String mlistStr = "MET_INDX"; if (isOmpInxObj()) { mlistStr = "MET_NORMAL"; typeForPresentation = AnDisplay.DSP_Functions; } if (!computed) { // need re-compute // System.err.println("XXX In FLD doCompute - 4 ()"); reset(); // window.setBusyCursor(true); Object[] res = setFuncData(sel_func, type, subtype); new_ind = (int) ((long[]) (res[0]))[0]; String errstr = ((String[]) (res[1]))[0]; // Update table if (errstr == null) { // System.err.println("XXX In FLD doCompute - 5 ()"); switch (type) { case AnDisplay.DSP_Source: updateWarningPanel(); break; default: String warning = window.getMsg(AnUtility.WARNING_MSG); if (null != warning) { if (!(warning.equalsIgnoreCase(lastWarning))) { lastWarning = warning; showWarning(lastWarning); } } break; } table.setViewport(); Object[][] table_data; int raw_data_length = -1; final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(typeForPresentation); final IPCResult ipcr_getNames = SendRequest_getNames(typeForPresentation, 0); // ASYNC IPC if (type == AnDisplay.DSP_IndexObject) { // Use new API Object[] raw_data_with_ids = window.getTableDataV2(mlistStr, modeStr, typeStr, subtypeStr, null); table_data = localProcessData(mlist, raw_data_with_ids); src_type = null; } else { // Use old API new_ind = -1; // reset new_ind for old API raw_data = getFuncList(type, subtype); if (raw_data != null && raw_data.length > 0) { raw_data_length = raw_data.length; table_data = localProcessData( mlist, raw_data); // first index is for column, second index is for rows // System.err.println("XXX after processData table_data.length = " + table_data.length + // "; row_length " + table_data[0].length ); src_type = (int[]) raw_data[raw_data.length - 1]; // AnTable.AT_SRC, DIS, QUOTE, etc. } else { // Should never happen but it does sometimes if you quickly select/deselect metrics in // overview // Changdao? String txt = "IPC ERROR (?) in FuncListDisp: raw_data is null or empty"; AnLog.log(txt); if (tailAction != null) { tailAction.tailFunction(); tailAction = null; } String[] hdrContent = ipcr_getNames.getStrings(); // To exclude the reply from the queue inCompute = false; return; } } // String[] hdrContent = getNames(typeForPresentation, 0); // name column table header // contents (?) // SYNC IPC String[] hdrContent = ipcr_getNames.getStrings(); label = getSettings() .getMetricsSetting() .getLabel(table_data, null, typeForPresentation, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(getMetricMType()); sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(typeForPresentation); new_ind = (new_ind == -1) ? 0 : new_ind; if (!(window.getSelectedObject().wasASelDone())) { if ((new_ind < 1) && (raw_data_length > 1)) { // Change selected object to first function reset_new_ind = true; new_ind = 1; } } table.setData(label, table_data, hdrContent, src_type, new_ind, name_col, sort_ind); if (table.getTable().getColumnCount() == 1) { // Show "No Metrics Selected" instaed of only name column in table for certain views if (MetricsSetting.dtype2mtype(type) == MetricsSetting.MET_DATA) { table.showMessage(new NoMetricsSelectedPanel(type)); inCompute = false; return; } } if ((sel_func == 0) || (reset_new_ind)) { window.getSelectedObject().setSelObj(new_ind, typeForPresentation, subtype); // SYNC IPC } } else { // System.err.println("XXX In FLD doCompute - 6 ()"); window.getExperimentsView().appendLog(AnLocale.getString("Error: ") + errstr); table.showMessage(errstr); } } // Update selected row if (!reset_new_ind) { new_ind = window.getSelectedObject().getSelIndex(sel_obj, type, subtype); // SYNC IPC } if (new_ind == -1) { new_ind = table.getSelectedRow(); if (type == AnDisplay.DSP_Functions) { tryAddNewObj(new_ind); } table.showSelectedRow(); window.getSelectedObject().setSelObj(new_ind, type, subtype); // SYNC IPC sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) } else { if (type == AnDisplay.DSP_Functions) { tryAddNewObj(new_ind); } table.setSelectedRow(new_ind); } // scroll to previous location after re-sort if (prevScroll > 0) { table.setScroll(prevScroll); prevScroll = -1; } updateGap(); // Update summary display if (updateSummary) { updateSummary(new_ind); } // pstatstr = window.getMsg(AnUtility.PSTAT_MSG); pwarnstr = window.getMsg(AnUtility.PWARN_MSG); // SYNC IPC // if (pstatstr != null) { // window.appendLog(pstatstr); // } if (pwarnstr != null) { window.showProcessorWarning(pwarnstr); } FuncListDisp.getToolbarPanelInternal().removeAll(); if (type == AnDisplay.DSP_Functions && window.getViews().getCurrentViewDisplay() == this) { // FIXUP: REARCH // Set toolbar and select subviews updateToolBar(); window .getCalledByCallsFunctionsView() .doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) } computed = true; ignoreSelected = false; updateSummary = true; if (tailAction != null) { tailAction.tailFunction(); tailAction = null; } inCompute = false; } // show warning panel public void updateWarningPanel() { String warning = window.getMsg(AnUtility.WARNING_MSG); if (null != warning) { if (!(warning.equalsIgnoreCase(lastWarning))) { warningPane.removeAll(); lastWarning = warning; String temp[] = lastWarning.split("[`']"); String text = " "; for (int i = 0; i < temp.length; i += 2) { String temp2[] = temp[i].split("[ ]"); for (int j = 0; j < temp2.length; j++) { if (!temp2[j].startsWith("Warning") && temp2[j].length() > 0) { text = text + temp2[j].replaceAll("[ ]", "") + " "; } } } JLabel lb = new JLabel(text, JLabel.LEFT); Font newLabelFont = new Font(lb.getFont().getName(), Font.PLAIN, lb.getFont().getSize()); warningPane.setLayout(new BorderLayout()); JLabel wlb = new JLabel(AnLocale.getString(" Warning:"), JLabel.LEFT); // I18N lb.setFont(newLabelFont); JLabel ilb = new JLabel(AnUtility.warningIcon, JLabel.LEFT); JPanel msgPanel = new JPanel(); msgPanel.setOpaque(false); msgPanel.setLayout(new BoxLayout(msgPanel, BoxLayout.X_AXIS)); msgPanel.add(ilb); msgPanel.add(wlb); msgPanel.add(lb); warningPane.add(msgPanel, BorderLayout.WEST); warningPane.setToolTipText(lastWarning); JPanel panel = new JPanel(); panel.setOpaque(false); JButton btn = new JButton(AnUtility.removeFocusedIcon); Dimension dm = new Dimension( AnUtility.removeFocusedIcon.getIconWidth() + 1, AnUtility.removeFocusedIcon.getIconHeight() + 1); panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS)); panel.setPreferredSize(dm); btn.setMaximumSize(dm); btn.setPreferredSize(dm); btn.setMargin(new Insets(0, 0, 0, 0)); btn.setSize(dm); panel.add(btn); btn.addActionListener( new ActionListener() { public void actionPerformed(ActionEvent e) { warningPane.setVisible(false); } }); warningPane.add(panel, BorderLayout.EAST); warningPane.setBackground(AnVariable.WARNINGPANEL_COLOR); // showWarning(lastWarning); warningPane.setVisible(true); } } else { warningPane.setVisible(false); } } // Set current func/load-object in 'selected func' & summary display private void updateSummary(final int new_ind) { // sel_func = can_sort ? new_ind : getFuncObj(); // window.updateSummary(new_ind, type, subtype); int[] rows = null; if (table != null) { rows = table.getSelectedRows(); } if (rows != null && rows.length > 1) { window.getSelectionManager().updateSelection(rows, type, subtype, 1); } else { window.getSelectionManager().updateSelection(new_ind, type, subtype, 1); } } // Update gap panel protected final void updateGap() { if (gap != null) { gap.update(); } } @Override protected boolean supportsFindText() { return true; } // Find @Override public int find(final String str, final boolean next, boolean caseSensitive) { int find_row; if ((str == null) && (type != DSP_Source) && (type != DSP_Disassembly) && (type != DSP_DualSource) && (type != DSP_DataLayout)) { return -1; } find_row = table.findAfter(str, next, caseSensitive); if (find_row == -1) { find_row = table.findBefore(str, next, caseSensitive); } // Update summary display if (find_row != -1) { goToLine(table, find_row); } return find_row; } public void goToLine(final AnTable tbl, final int row) { final boolean can_nav; if (can_sort) { can_nav = true; } else { int stype = tbl.getSrcType(row); can_nav = (stype == AnTable.AT_SRC) || (stype == AnTable.AT_DIS) || (stype == AnTable.AT_QUOTE); } tbl.setSelectedRow(row); // Set selected object & Update summary display if (can_nav) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { window.getSelectedObject().setSelObj(row, type, subtype); if (type == AnDisplay.DSP_Functions) { if (tbl.getNavigationHistoryPool() != null) { tbl.getNavigationHistoryPool().getHistory().goToFuncNew(row); updateToolBar(); } window.getCalledByCallsFunctionsView().setComputed(false); window.getCalledByCallsFunctionsView().computeOnAWorkerThread(); } updateSummary(row); } }, "funcdisplist selection"); } } // Is current selected tab? public void setSelected(final boolean set) { selected = set; if (type == AnDisplay.DSP_Functions) { window.getCalledByCallsFunctionsView().setSelected(set); } } // Sort public void sort(final int index) { if (table != null) { table.sort(index); } } protected Object[][] MaximumValues = null; int totalColumn = -1; protected Object[][] localProcessData(final AnMetric[] mlist, final Object[] raw_data) { final Object[][] data = get_data(mlist, raw_data); if (data == null) { return null; } if ((raw_data.length > mlist.length) && (raw_data[mlist.length] != null) && (raw_data[mlist.length] instanceof long[])) { current_ids = (long[]) raw_data[mlist.length]; // per-row HistItem->obj->id } // XXXX (Mez) Neew to remove MaximumValues from FuncListDisp MaximumValues = AnObject.updateMaxValues(data, MaximumValues); return data; } protected Object[][] get_data(final AnMetric[] mlist, final Object[] raw_data) { // raw_data has one vector for each column of metric values. // In addition, it has a vector of dbe row identifiers (HistItem->obj->id) if ((raw_data == null) || (mlist == null) || (mlist.length == 0) || (mlist.length > raw_data.length)) { return null; } // "Bugs 16624403 and 19539622" (leave this string intact for searches) // look for the row that has name==<Total> int row_with_Total = -1; for (int i = 0; i < mlist.length; i++) { AnMetric m = mlist[i]; if (!m.isNameMetric()) { continue; } Object[] d = (Object[]) raw_data[i]; for (int j = 0; j < d.length; j++) { if (d[j].toString().equals("<Total>")) { // FOUND IT!!! row_with_Total = j; break; } } break; } final Object[][] data = new Object[mlist.length][]; for (int i = 0; i < mlist.length; i++) { AnMetric m = mlist[i]; switch (m.get_valtype()) { case AnMetric.VT_LLONG: case AnMetric.VT_ULLONG: if (raw_data[i] instanceof long[]) { data[i] = AnLong.toArray((long[]) raw_data[i]); } else { data[i] = AnDouble.toArray((double[]) raw_data[i]); } break; case AnMetric.VT_ADDRESS: if (raw_data[i] instanceof long[]) { data[i] = AnAddress.toArray((long[]) raw_data[i]); } else { data[i] = AnDouble.toArray((double[]) raw_data[i]); } break; case AnMetric.VT_DOUBLE: data[i] = AnDouble.toArray((double[]) raw_data[i]); break; case AnMetric.VT_LABEL: data[i] = (Object[]) raw_data[i]; break; default: System.err.println( String.format( "Error in localProcessData: unrecognized get_valtype(): %d", m.get_valtype())); data[i] = (Object[]) raw_data[i]; break; } CompareMode mode = m.getCompareMode(); if (mode == CompareMode.CMP_DELTA) { switch (m.get_valtype()) { case AnMetric.VT_LLONG: // EUGENE why not also other types like VT_INT? case AnMetric.VT_ULLONG: case AnMetric.VT_ADDRESS: case AnMetric.VT_DOUBLE: Object[] row = data[i]; for (int j = 0, jsz = (row == null) ? 0 : row.length; j < jsz; j++) { ((AnObject) row[j]).showSign(true); } break; } } if (mode == CompareMode.CMP_RATIO) { switch (m.get_valtype()) { case AnMetric.VT_LLONG: // EUGENE why not also other types like VT_INT? case AnMetric.VT_ULLONG: case AnMetric.VT_DOUBLE: Object[] row = data[i]; for (int j = 0, jsz = (row == null) ? 0 : row.length; j < jsz; j++) { ((AnObject) row[j]).showXtimes(true); } break; } } // "Bugs 16624403 and 19539622" (leave this string intact for searches) if (m.getUserName().equals("Block Covered %") || m.getUserName().equals("Instr Covered %")) { if (row_with_Total >= 0) { // to blank this item out, set to 0 and set showZero(false) data[i][row_with_Total] = new AnLong((long) 0); ((AnObject) data[i][row_with_Total]).showZero(false); } } } return data; } protected AnObject[] getTotals(int type, int subtype) { AnUtility.checkIPCOnWrongThread(false); Object[] raw_data = dbeGetTotals(type, subtype); AnUtility.checkIPCOnWrongThread(true); if ((raw_data == null) || (raw_data.length != 2)) { return null; } Object[] data = (Object[]) raw_data[1]; AnMetric[] mlist = getSettings().getMetricList((Object[]) raw_data[0]); if ((mlist == null) || (mlist.length == 0) || (mlist.length != data.length)) { return null; } AnObject[] res = new AnObject[mlist.length]; for (int i = 0; i < mlist.length; i++) { AnMetric m = mlist[i]; switch (m.get_valtype()) { case AnMetric.VT_LLONG: case AnMetric.VT_ULLONG: res[i] = new AnLong(((long[]) data[i])[0]); break; case AnMetric.VT_ADDRESS: res[i] = new AnAddress(((long[]) data[i])[0]); break; case AnMetric.VT_DOUBLE: res[i] = new AnDouble(((double[]) data[i])[0]); break; case AnMetric.VT_LABEL: res[i] = new AnDouble((double) 0); break; default: System.err.println( String.format("Error in getTotals: unrecognized get_valtype(): %d", m.get_valtype())); res[i] = new AnDouble((double) 0); break; } } return res; } /* * Returns MaximumValues (Total and Max values), calculated by processData() */ public Object[] getTotalMax() { return MaximumValues; } // // Create the filter clause based on the selected objects // public String createFilterClause() { // int[] selected_indices = table.selected_indices; // if (isOmpInxObj()) { // Use new API // String clause = ""; // if (selected_indices.length <= 0) { // return clause; // } // String IDs = ""; // for (int i = 0; i < selected_indices.length; i++) { // long id = current_ids[selected_indices[i]]; // IDs = IDs + id; // if (i + 1 < selected_indices.length) { // IDs = IDs + ","; // } // } // clause = "(" + getTabName() + " IN (" + IDs + "))"; // return clause; // } // String clause = composeFilterClause(type, subtype, selected_indices); // return clause; // } // Listener for updating table private final class TableHandler implements AnListener { public void valueChanged(final AnEvent event) { final int from; final int to; int stype = 0; final boolean can_nav; switch (event.getType()) { case AnEvent.EVT_SELECT: // Selecting from = event.getValue(); if (can_sort) { can_nav = true; } else { stype = src_type[from]; if (stype < 0) { stype = -stype; } can_nav = (stype == AnTable.AT_SRC) || (stype == AnTable.AT_DIS) || (stype == AnTable.AT_QUOTE); } if ((type == DSP_Source)) { deselectRaceStack(subtype); // FIXUP: REARCH window.getSourceDisassemblyView().focusInHalf(AnTable.AT_SRC); } if ((type == DSP_SourceDisassembly) || (type == DSP_Disassembly)) { if (stype == AnTable.AT_DIS) { window.getSourceDisassemblyView().focusInHalf(AnTable.AT_DIS); } else { // SOURCE window.getSourceDisassemblyView().focusInHalf(AnTable.AT_SRC); } } // Set selected object & Update summary display if (can_nav) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { window.getSelectedObject().setSelObj(from, type, subtype); if (type == AnDisplay.DSP_Functions) { window.getCalledByCallsFunctionsView().setComputed(false); window.getCalledByCallsFunctionsView().computeOnAWorkerThread(); } updateSummary(from); } }, "funclistdisp selection"); } else // in other cases (eg. AT_SRC_ONLY), just update summary { // updateSummary(from); if (type == AnDisplay.DSP_Functions) { window.getCalledByCallsFunctionsView().setComputed(false); window.getCalledByCallsFunctionsView().computeOnAWorkerThread(); } updateSummary(from); } break; case AnEvent.EVT_SORT: // Sorting // save current scroll location prevScroll = table.getScroll(); getSettings() .getMetricsSetting() .setSortMetricByDType(this, ((Integer) event.getAux()).intValue(), getMetricMType()); break; case AnEvent.EVT_COPY_ALL: // Copy all lines copyAll(); break; case AnEvent.EVT_COPY_SEL: // Copy selected lines copySelected(); break; case AnEvent.EVT_SWITCH: // Column switching if (table != null) { table.columnsSaved = false; } from = event.getValue(); to = ((Integer) event.getAux()).intValue(); getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, getMetricMType()); break; } } } protected void deselectRaceStack(int subtype) { // FIXUP: REARCH // System.err.println("The selection is done in Source # " + subtype); if (subtype == 0) { return; } window.getDualSourceView().focusInHalf(subtype); } // Native methods from liber_dbe.so protected Object[] setFuncData(final long sel_func, final int type, final int subtype) { synchronized (IPC.lock) { window.IPC().send("setFuncDataV2"); window.IPC().send(0); window.IPC().send(sel_func); window.IPC().send(type); window.IPC().send(subtype); return (Object[]) window.IPC().recvObject(); } } // protected void dbe_archive(final long ids[], final String locations[]) { // synchronized (IPC.lock) { // window.IPC().send("dbe_archive"); // window.IPC().send(ids); // window.IPC().send(locations); // window.IPC().recvVoid(); // } // } // // protected void dbeSetLocations(final String fnames[], final String locations[]) { // synchronized (IPC.lock) { // window.IPC().send("dbeSetLocation"); // window.IPC().send(fnames); // window.IPC().send(locations); // window.IPC().recvVoid(); // } // } // // protected Object[] dbeResolvedWith_setpath(final String path) { // // obj[0] - list of old pathes // // obj[1] - list of new pathes // // obj[2] - list of ids // synchronized (IPC.lock) { // window.IPC().send("dbeResolvedWith_setpath"); // window.IPC().send(path); // return (Object[]) window.IPC().recvObject(); // } // } // // protected Object[] dbeResolvedWith_pathmap(final String old_prefix, final String new_prefix) // { // // obj[0] - list of old pathes // // obj[1] - list of new pathes // // obj[2] - list of ids // synchronized (IPC.lock) { // window.IPC().send("dbeResolvedWith_pathmap"); // window.IPC().send(old_prefix); // window.IPC().send(new_prefix); // return (Object[]) window.IPC().recvObject(); // } // } protected Object[] getFuncList(final int type, final int subtype) { synchronized (IPC.lock) { window.IPC().send("getFuncList"); window.IPC().send(0); window.IPC().send(type); window.IPC().send(subtype); return (Object[]) window.IPC().recvObject(); } } protected Object[] dbeGetTotals(int dsptype, int subtype) { synchronized (IPC.lock) { IPC ipc = window.IPC(); ipc.send("dbeGetTotals"); ipc.send(0); ipc.send(dsptype); ipc.send(subtype); return (Object[]) ipc.recvObject(); } } protected Object[] getHotMarks(final int type) { synchronized (IPC.lock) { window.IPC().send("getHotMarks"); window.IPC().send(0); window.IPC().send(type); return (Object[]) window.IPC().recvObject(); } } protected Object[] getHotMarksInc(final int type) { synchronized (IPC.lock) { window.IPC().send("getHotMarksInc"); window.IPC().send(0); window.IPC().send(type); return (Object[]) window.IPC().recvObject(); } } protected String[] getNames(final int type, final long sel_obj) { synchronized (IPC.lock) { window.IPC().send("getNames"); window.IPC().send(0); window.IPC().send(type); window.IPC().send(sel_obj); return (String[]) window.IPC().recvObject(); } } /** * Send request to get Names. Non-blocking IPC call. Caller should call ipcResult.getStrings() to * get the result * * @return IPCResult */ public static IPCResult SendRequest_getNames(final int type, final long sel_obj) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("getNames"); ipcHandle.append(0); ipcHandle.append(type); ipcHandle.append(sel_obj); IPCResult ipcResult = ipcHandle.sendRequest(); // Object[] result = ipcResult.getStrings() // blocking return ipcResult; } protected String composeFilterClause( final int type, final int subtype, final int[] selected_ids) { synchronized (IPC.lock) { window.IPC().send("composeFilterClause"); window.IPC().send(0); window.IPC().send(type); window.IPC().send(subtype); window.IPC().send(selected_ids); return window.IPC().recvString(); } } @Override public List<ExportFormat> getSupportedExportFormats() { List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.TEXT); formats.add(ExportFormat.HTML); formats.add(ExportFormat.CSV); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return true; } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); if (type == DSP_Functions || type == DSP_Lines || type == DSP_PCs) { list.add(window.getTimelineCallStackSubview()); list.add(window.getIoCallStackSubview()); list.add(window.getHeapCallStackSubview()); } if (type == DSP_Functions) { if (!window.getSettings().getCompareModeSetting().comparingExperiments()) { list.add(window.getCalledByCallsFuncSubview()); } } return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } @Override public void setComputed(boolean set) { super.setComputed(set); if (table != null) { // possible major change to table, so rebuild columns table.columnsSaved = false; } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/guitesting/��������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�016214� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/guitesting/GUITesting.java�����������������������������������������0000644�0001750�0001750�00000011363�14517772113�020750� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.guitesting; import org.gprofng.mpmt.AnWindow; /* * Miscellenuous support for automated GUI testing */ public class GUITesting { private static final String GUI_TESTING_ENVVAR = "SP_ANALYZER_GUI_TESTING"; private static final String GUI_TESTING_EXTRA = "SP_ANALYZER_GUI_TESTING_EXTRA"; private static final String GUI_RUNNING_UNDER_NB = "SP_RUNNING_UNDER_NB"; private static GUITesting instance = null; private boolean enableGUITestingExtra = false; private boolean runningUnderGUITesting = false; private boolean runningUnderNB = false; public GUITesting() { String guiTestingExtra = System.getenv(GUI_TESTING_EXTRA); if (guiTestingExtra == null) { guiTestingExtra = System.getProperty(GUI_TESTING_EXTRA); } enableGUITestingExtra = guiTestingExtra != null; String guiTesting = System.getenv(GUI_TESTING_ENVVAR); if (guiTesting == null) { guiTesting = System.getProperty(GUI_TESTING_ENVVAR); } runningUnderGUITesting = guiTesting != null; String underNB = System.getenv(GUI_RUNNING_UNDER_NB); if (underNB == null) { underNB = System.getProperty(GUI_RUNNING_UNDER_NB); } runningUnderNB = underNB != null; if (enableGUITestingExtra) { System.out.println("GUITesting: SP_ANALYZER_GUI_TESTING_EXTRA: " + enableGUITestingExtra); } if (runningUnderGUITesting) { System.out.println("GUITesting: SP_ANALYZER_GUI_TESTING: " + runningUnderGUITesting); } if (runningUnderNB) { System.out.println("GUITesting: SP_RUNNING_UNDER_NB: " + runningUnderNB); } } public static GUITesting getInstance() { if (instance == null) { instance = new GUITesting(); } return instance; } /** * @return the runningUnderGUITesting */ public boolean isRunningUnderGUITesting() { return runningUnderGUITesting; } /** * @return the runningUnderNB */ public boolean isRunningUnderNB() { return runningUnderNB; } /** * @return the enableGUITestingExtra */ public boolean guiTestingExtraEnabled() { return enableGUITestingExtra; } public String filter(String in) { String out = in; out = out.replaceAll("\\(found as .*\\)", "(found as <FILTERED>)"); out = out.replaceAll("...... file: /.*/", "...... file: <FILTERED>/"); // Source or Object file out = out.replaceAll("Stack 0x.*", "Stack 0x<FILTERED>"); // I/O view out = out.replaceAll("Process Id.*", "Process Id <FILTERED>"); // I/O subview out = out.replaceAll("Time of peak.*", "Time of peak <FILTERED>"); // I/O subview out = out.replaceAll("Total time.*", "Total time <FILTERED>"); // I/O subview // out = out.replaceAll("Heap size bytes.*", "Heap size bytes <FILTERED>"); // I/O // subview // out = out.replaceAll("Total bytes.*", "Total bytes <FILTERED>"); // I/O subview out = out.replaceAll( "Instruction freq.*", "Instruction freq... <FILTERED>"); // instruction Frequency return out; } /** * Dump contents of main view. Used in unit tests. * * @return */ public String dumpMainview() { return dumpMainview(0); } /** * Dump contents of main view. Used in unit tests. * * @param maxLines limit output to top maxLines lines. 0 meaning all lines. * @return */ public String dumpMainview(int maxLines) { AnWindow window = AnWindow.getInstance(); String txt = window.dumpMainview(maxLines); txt = filter(txt); return txt; } /** * Dump contents of all visible sub views. Used in unit tests. * * @return */ public String dumpSubviews() { AnWindow window = AnWindow.getInstance(); String txt = window.dumpSubviews(); txt = filter(txt); return txt; } /** * Dump visibility of main view and sub views. Used in unit tests. * * @return */ public String dumpViewsVisibility() { AnWindow window = AnWindow.getInstance(); return window.dumpViewsVisibility(); } public String dumpAvailableViews() { AnWindow window = AnWindow.getInstance(); String txt = window.getViewsPanel().dumpAvailableViews(); return txt; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AboutPanel.form����������������������������������������������������0000644�0001750�0001750�00000014453�14517772113�016663� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-85,0,0,2,123"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Container class="javax.swing.JPanel" name="innerPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="iconLabel"> <Properties> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> <Image iconType="3" name="/org/gprofng/mpmt/icons/performanceAnalyzerSplash.gif"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JScrollPane" name="infoScrollPane"> <Properties> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[300, 180]"/> </Property> </Properties> <AuxValues> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <SubComponents> <Component class="javax.swing.JTextPane" name="infoTextPane"> <Properties> <Property name="editable" type="boolean" value="false"/> </Properties> </Component> </SubComponents> </Container> <Container class="javax.swing.JScrollPane" name="copyrightScrollPane"> <AuxValues> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <SubComponents> <Component class="javax.swing.JTextArea" name="copyrightTextArea"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="columns" type="int" value="20"/> <Property name="lineWrap" type="boolean" value="true"/> <Property name="rows" type="int" value="8"/> <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor"> <Insets value="[4, 4, 4, 4]"/> </Property> </Properties> </Component> </SubComponents> </Container> </SubComponents> </Container> </SubComponents> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ExperimentsView.java�����������������������������������������������0000644�0001750�0001750�00000074733�14517772113�017754� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.util.gui.AnJPanel; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnSplitPane; import org.gprofng.mpmt.util.gui.AnTabbedPane; import org.gprofng.mpmt.util.gui.AnTextIcon; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Rectangle; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusEvent; import java.awt.event.FocusListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.util.ArrayList; import javax.accessibility.AccessibleContext; import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTabbedPane; import javax.swing.JTree; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.border.EtchedBorder; import javax.swing.event.PopupMenuEvent; import javax.swing.event.UndoableEditEvent; import javax.swing.event.UndoableEditListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreePath; import javax.swing.undo.CannotRedoException; import javax.swing.undo.CannotUndoException; import javax.swing.undo.UndoManager; public final class ExperimentsView extends AnDisplay implements ExportSupport, AnChangeListener { private boolean initialized = false; private AnTree tree; private AnUtility.AnTextArea log; private AnTextIcon[] exp_list; private AnMenuListener menuListener; // Menu actions // final String STR_ACTION_SETFILTER_SEO = AnLocale.getString("Add Filter: Selected Experiments // Only"); 11 // final String STR_ACTION_SETFILTER_ESE = AnLocale.getString("Add Filter: Exclude Selected // Experiments"); 12 // final String STR_ACTION_EXPERIMENTS = AnLocale.getString("Filter Experiments..."); // final String STR_ACTION_SETFILTER_RDF = AnLocale.getString("Remove All Filters"); // private final String STR_ACTION_UNDOFILTER = AnLocale.getString("Undo Last Filter"); // private final String STR_ACTION_MANAGEFILTERS = AnLocale.getString("Manage Filters..."); // Constructor public ExperimentsView() { super(AnWindow.getInstance(), AnDisplay.DSP_Experiments, AnVariable.HELP_TabsExperiments); setAccessibility(AnLocale.getString("Experiments")); AnEventManager.getInstance().addListener(this); } public void initErrorsAndWarnings(String[] errors, String[] warnings) { cleanLog(); // Clean old messages if (errors != null) { appendLog("" + AnLocale.getString("Errors:") + "\n"); for (String msg : errors) { if (msg != null) { appendLog(msg + "\n"); } } appendLog("\n"); } if (warnings != null) { appendLog("" + AnLocale.getString("Warnings:") + "\n"); for (String msg : warnings) { if (msg != null) { appendLog(msg + "\n"); } } appendLog("\n"); } } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("ExperimentsView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case FILTER_CHANGING: case FILTER_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: // Nothing break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void requestFocus() { initGUIComponents(); if (tree != null) { tree.requestFocus(); } } /** * Override and return true if text find is supported * * @return */ @Override protected boolean supportsFindText() { return true; } // Find @Override public int find(final String str, final boolean next, final boolean caseSensitive) { int selectedIndex = findSelectedIndex(); Object root = tree.getModel().getRoot(); int childCount = tree.getModel().getChildCount(root); DefaultMutableTreeNode foundNode = null; if (next) { if (selectedIndex >= 0 && selectedIndex < childCount - 1) { foundNode = findNode(selectedIndex + 1, childCount - 1, str, caseSensitive); if (foundNode == null) { foundNode = findNode(0, selectedIndex, str, caseSensitive); } } else { foundNode = findNode(0, childCount - 1, str, caseSensitive); } } else if (selectedIndex > 0) { foundNode = findNode(selectedIndex - 1, 0, str, caseSensitive); if (foundNode == null) { foundNode = findNode(childCount - 1, selectedIndex, str, caseSensitive); } } else { foundNode = findNode(childCount - 1, 0, str, caseSensitive); } if (foundNode != null) { TreePath treePath = new TreePath(foundNode.getPath()); tree.scrollPathToVisible(treePath); tree.setSelectionPath(treePath); // tree.expandPath(treePath); return 0; } else { return -1; } } private DefaultMutableTreeNode findNode(int from, int to, String str, boolean caseSensitive) { // System.out.println(from + " " + to); Object root = tree.getModel().getRoot(); DefaultMutableTreeNode foundNode = null; if (from <= to) { for (int i = from; i <= to; i++) { Object child = tree.getModel().getChild(root, i); foundNode = match(child, str, caseSensitive); if (foundNode != null) { break; } } } else { for (int i = from; i >= to; i--) { Object child = tree.getModel().getChild(root, i); foundNode = match(child, str, caseSensitive); if (foundNode != null) { break; } } } return foundNode; } private DefaultMutableTreeNode match(Object child, String str, boolean caseSensitive) { if (child instanceof DefaultMutableTreeNode) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) child; Object userObject = node.getUserObject(); if (userObject instanceof AnTextIcon) { AnTextIcon anTextIcon = (AnTextIcon) userObject; if (!caseSensitive && anTextIcon.getText().toLowerCase().contains(str.toLowerCase())) { return node; } else if (anTextIcon.getText().contains(str)) { return node; } } } return null; } private int findSelectedIndex() { DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent(); Object root = tree.getModel().getRoot(); int childCount = tree.getModel().getChildCount(root); for (int i = 0; i < childCount; i++) { Object child = tree.getModel().getChild(root, i); if (child instanceof DefaultMutableTreeNode) { DefaultMutableTreeNode node = (DefaultMutableTreeNode) child; if (node == selectedNode) { return i; } } } return -1; } @Override protected void initComponents() {} // @Override private void initGUIComponents() { if (!initialized) { initGUIComponentsInternal(); initialized = true; } } /** Initialize GUI components */ // @Override private void initGUIComponentsInternal() { JLabel treeLabel; JPanel logPanel; setLayout(new BorderLayout()); // Experiment tree area String text = AnLocale.getString("Experiments"); tree = new AnTree(text, 2); tree.getAccessibleContext().setAccessibleName(text); tree.getAccessibleContext().setAccessibleDescription(text); treeLabel = new JLabel(text); treeLabel.setLabelFor(tree); treeLabel.getAccessibleContext().setAccessibleName(text); treeLabel.getAccessibleContext().setAccessibleDescription(text); treeLabel.setVisible(false); JScrollPane treeScrollPane = new AnJScrollPane(tree); treeScrollPane.setBorder( BorderFactory.createMatteBorder(0, 0, 1, 0, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); treeScrollPane.add(treeLabel); // Errors and warnings list area JPanel listPanel = new JPanel(); listPanel.setBackground(Color.WHITE); JScrollPane listScrollPane = new AnJScrollPane(listPanel); // listScrollPane.setBorder(BorderFactory.createMatteBorder(1, 0, 1, 0, // AnEnvironment.SPLIT_PANE_BORDER_COLOR)); // Errors and warnings log area log = new AnUtility.AnTextArea(null, false); log.setBackground(AnEnvironment.DEFAULT_DIALOG_BACKGROUND); AnUtility.setAccessibleContext(log.getAccessibleContext(), AnLocale.getString("Logs")); logPanel = new JPanel(new BorderLayout()); logPanel.add(log, BorderLayout.CENTER); JScrollPane logScrollPane = new AnJScrollPane(logPanel); // logScrollPane.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, // AnEnvironment.SPLIT_PANE_BORDER_COLOR)); // Errors and warnings tabs JTabbedPane tabbedPane = new AnTabbedPane(); tabbedPane.setBorder( BorderFactory.createMatteBorder( 1, 0, 0, 0, new Color(219, 219, 219))); // AnEnvironment.SPLIT_PANE_BORDER_COLOR)); tabbedPane.add(AnLocale.getString("List"), listScrollPane); tabbedPane.add(AnLocale.getString("Log"), logScrollPane); tabbedPane.setSelectedIndex(1); // FIXUP: justfornow JPanel errorsAndWarningsPanel = new JPanel(new GridBagLayout()); errorsAndWarningsPanel.setBackground(Color.WHITE); errorsAndWarningsPanel.setBorder( BorderFactory.createMatteBorder(1, 0, 0, 0, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); GridBagConstraints gridBagConstraints; gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(2, 0, 2, 0); JLabel eawLabel = new JLabel(AnLocale.getString("Errors & Warnings:")); eawLabel.getAccessibleContext().setAccessibleDescription(""); eawLabel.setOpaque(false); errorsAndWarningsPanel.add(eawLabel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; errorsAndWarningsPanel.add(tabbedPane, gridBagConstraints); // JSplitPane splitPane = new AnSplitPane(JSplitPane.VERTICAL_SPLIT, treeScrollPane, errorsAndWarningsPanel); splitPane.setOneTouchExpandable(true); splitPane.setResizeWeight(1.0); add(splitPane, BorderLayout.CENTER); // Popup menu menuListener = new AnMenuListener(tree); tree.addMouseListener(menuListener); // this.addMouseListener(menuListener); // Do we need i? // KeyStroke ks = KeyboardShortcuts.contextMenuActionShortcut; // tree.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, ks); // tree.getActionMap().put(ks, new AbstractAction() { // public void actionPerformed(ActionEvent ev) { // JPopupMenu popup = menuListener.init_popup(); // if (popup != null) { // JTree src = (JTree) ev.getSource(); // Rectangle cellRect, visRect; // // visRect = src.getVisibleRect(); // cellRect = visRect; // int selrow = src.getMaxSelectionRow(); // if (selrow >= 0) { // cellRect = src.getRowBounds(selrow); // } // // // if current view doesn't include selected row, scroll // if (!visRect.contains(cellRect)) { // // calculate middle based on selected row // // being below or above current visible rows // if (visRect.y < cellRect.y) { // cellRect.y += visRect.height / 2; // } else { // cellRect.y -= visRect.height / 2; // } // src.scrollRectToVisible(cellRect); // } // popup.show(src, cellRect.x, cellRect.y + cellRect.height); // } // } // }); } /** Append added experiments */ private void addExperiment() { exp_list = window.getExperimentList(); if (exp_list == null) { return; } // Add the extra node "Load Objects" if needed & Get the last index int last = tree.addExtra(AnLocale.getString("Load Objects")); // Add experiments into tree tree.addNodes(exp_list, last); } private void cleanLog() { initGUIComponents(); log.setText(""); } public void appendLog(final String text) { initGUIComponents(); log.append(AnUtility.trimNewLine(text) + "\n"); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { final Dimension logSize; final Rectangle endRect; logSize = log.getPreferredSize(); endRect = new Rectangle(0, logSize.height, 1, 1); log.scrollRectToVisible(endRect); } }); } /** Compute & update Experiment display */ @Override public void doCompute() { // System.out.println("ExperimentsView:doCompute: " + selected + " " + computed); AnUtility.checkIfOnAWTThread(false); initGUIComponents(); if (!computed) { addExperiment(); String[] info = window.getExpInfo(); if (info != null) { int nc = (info.length - 1) / 2 + 1; JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 2, 2)); panel.add(new AnUtility.AnTextArea(AnUtility.trimNewLine(info[0]), false)); // Load Objects panel.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); tree.setContent(0, panel); int k = 1; for (int i = 1; i < nc; i++) { panel = new AnTreePanel(info[k++], info[k++], i - 1); panel.setBorder(new EtchedBorder(EtchedBorder.LOWERED)); tree.setContent(i, panel); } } tree.setSelectionRow(0); computed = true; } } class AnTreePanel extends AnJPanel implements UndoableEditListener, FocusListener, KeyListener, ActionListener { private static final int SAVE_FILE = 0; private static final int DELETE_FILE = 1; public static final int UNDO_LIMIT = 1500; // Setting Undo Limit to 1500 edits private int cnt_edit_actions, cnt_undo_actions; private final int exp_id; private boolean undo_manager_exists = false; public String notesText; public final String info_text; public AnUtility.AnTextArea notes_text_area; private AnUndoManager undoManager; public AnUtility.ResponseAction saveAction, undoAction, redoAction, deleteAction; public AnTreePanel(final String notes_text, final String info_text, final int exp_id) { super(); this.exp_id = exp_id; cnt_edit_actions = cnt_undo_actions = 0; this.notesText = notes_text; this.info_text = info_text; initComponents(); notes_text_area.getDocument().addUndoableEditListener(this); notes_text_area.addFocusListener(this); notes_text_area.addKeyListener(this); // final String[] initMessages; // initMessages = getInitMessages(); // for (int i = 0; i < initMessages.length; i++) { // appendLog(initMessages[i]); // } } private void initComponents() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); final JPanel notesPanel = new JPanel(); notesPanel.setLayout(new javax.swing.BoxLayout(notesPanel, BoxLayout.X_AXIS)); notesPanel.setBorder(new javax.swing.border.EtchedBorder()); final JPanel buttPanel = new JPanel(new java.awt.FlowLayout(java.awt.FlowLayout.RIGHT, 2, 2)); saveAction = new AnUtility.ResponseAction( AnUtility.save_icon, AnLocale.getString("Save notes") + " Ctrl+S", "__save", this); saveAction.setEnabled(false); undoAction = new AnUtility.ResponseAction( AnUtility.undo_icon, AnLocale.getString("Undo") + " Ctrl+Z", "__undo", this); undoAction.setEnabled(false); redoAction = new AnUtility.ResponseAction( AnUtility.redo_icon, AnLocale.getString("Redo") + " Ctrl+Y", "__redo", this); redoAction.setEnabled(false); deleteAction = new AnUtility.ResponseAction( AnUtility.del_icon, AnLocale.getString("Delete notes") + " Ctrl+D", "__delete", this); deleteAction.setEnabled(notesText != null && !notesText.equals("")); buttPanel.add(saveAction); buttPanel.add(undoAction); buttPanel.add(redoAction); buttPanel.add(deleteAction); AnUtility.AnLabel notesLabel = (AnUtility.AnLabel) AnUtility.getHeader(AnLocale.getString("Notes:")); if (notesText == null || notesText.equals("")) { notesText = AnLocale.getString("<Empty>"); } notes_text_area = new AnUtility.AnTextArea(AnUtility.trimNewLine(notesText), true); AnUtility.setAccessibleContext( notes_text_area.getAccessibleContext(), AnLocale.getString("Notes area")); notesLabel.setLabelFor(notes_text_area); notesLabel.setBorder(new javax.swing.border.EmptyBorder(new java.awt.Insets(1, 4, 1, 1))); notesLabel.setHorizontalTextPosition(javax.swing.SwingConstants.LEADING); notesPanel.add(notesLabel); notesPanel.add(buttPanel); add(notesPanel); add(notes_text_area); final JPanel infoPanel = new JPanel(new FlowLayout(java.awt.FlowLayout.LEFT, 2, 2)); infoPanel.setBorder(new EtchedBorder()); final AnUtility.AnLabel infoLabel = (AnUtility.AnLabel) AnUtility.getHeader(AnLocale.getString("Info:")); final AnUtility.AnTextArea infoTextArea = new AnUtility.AnTextArea(AnUtility.trimNewLine(info_text), false); AnUtility.setAccessibleContext( infoTextArea.getAccessibleContext(), AnLocale.getString("Info area")); infoLabel.setLabelFor(infoTextArea); infoLabel.setBorder(new EmptyBorder(new java.awt.Insets(1, 2, 1, 1))); infoPanel.add(infoLabel); add(infoPanel); add(infoTextArea); } // createUndoMananger creating undo manager public void createUndoMananger() { if (undo_manager_exists) { return; } undoManager = new AnUndoManager(); undoManager.setLimit(UNDO_LIMIT); undo_manager_exists = true; } // removeUndoMananger removing undo manager public void removeUndoMananger() { undoManager.end(); cnt_edit_actions = 0; cnt_undo_actions = 0; saveAction.setEnabled(false); undoAction.setEnabled(false); redoAction.setEnabled(false); undo_manager_exists = false; } @Override public void focusGained(final FocusEvent fe) { createUndoMananger(); } @Override public void focusLost(final FocusEvent fe) { // removeUndoMananger(); } // undoableEditHappened called when edit happened @Override public void undoableEditHappened(final UndoableEditEvent e) { // add the edits to the unod manager undoManager.addEdit(e.getEdit()); cnt_edit_actions++; cnt_undo_actions = 0; // no redo acts after editing redoAction.setEnabled(false); saveAction.setEnabled(true); undoAction.setEnabled(true); } @Override public void keyPressed(final KeyEvent e) { createUndoMananger(); if ((e.getKeyCode() == KeyEvent.VK_Z) && (e.isControlDown())) { if (!undoAction.isEnabled()) { return; // Undo changes } try { undoManager.undo(); } catch (CannotUndoException cue) { Toolkit.getDefaultToolkit().beep(); } } if ((e.getKeyCode() == KeyEvent.VK_Y) && (e.isControlDown())) { if (!redoAction.isEnabled()) { return; // Redo changes } try { undoManager.redo(); } catch (CannotRedoException cue) { Toolkit.getDefaultToolkit().beep(); } } if ((e.getKeyCode() == KeyEvent.VK_S) && (e.isControlDown())) { // Save changes if (!saveAction.isEnabled()) { return; } undoManager.save(); } if ((e.getKeyCode() == KeyEvent.VK_D) && (e.isControlDown())) { // Delete notes file if (!deleteAction.isEnabled()) { return; } undoManager.delete(true); } } @Override public void keyReleased(final KeyEvent e) {} @Override public void keyTyped(final KeyEvent e) {} @Override public void actionPerformed(final ActionEvent e) { createUndoMananger(); if (e.getActionCommand().equals("__save")) { undoManager.save(); } else if (e.getActionCommand().equals("__undo")) { try { undoManager.undo(); } catch (CannotUndoException cue) { Toolkit.getDefaultToolkit().beep(); } } else if (e.getActionCommand().equals("__redo")) { try { undoManager.redo(); } catch (CannotRedoException cue) { Toolkit.getDefaultToolkit().beep(); } } else if (e.getActionCommand().equals("__delete")) { undoManager.delete(true); } } public void updateAllExps(final int type) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { DefaultMutableTreeNode root, node; AnTree the_tree; AnTreePanel panel; final String cur_exp; String exp; // final int win_size = window.get_win_size(); cur_exp = new File(exp_list[exp_id].getText()).getAbsolutePath(); // for (int i = 0; i < win_size; i++) { the_tree = window.getExperimentsView().tree; root = ((DefaultMutableTreeNode) the_tree.getModel().getRoot()); final int cnt = root.getChildCount(); for (int k = 1; k < cnt; k++) { node = (DefaultMutableTreeNode) root.getChildAt(k); exp = new File(((AnTextIcon) node.getUserObject()).getText()).getAbsolutePath(); if (cur_exp.equals(exp)) { final DefaultMutableTreeNode nd = (DefaultMutableTreeNode) node.getChildAt(0); panel = (AnTreePanel) nd.getUserObject(); if (!panel.equals(AnTreePanel.this)) { panel.createUndoMananger(); panel.notes_text_area.setText(notesText); updateNotes(panel.exp_id, type, (type == SAVE_FILE) ? notesText : null, false); panel.deleteAction.setEnabled(type == SAVE_FILE); panel.removeUndoMananger(); ((DefaultTreeModel) the_tree.getModel()).nodeChanged(node); } } } } // } }); } private final class AnUndoManager extends UndoManager { @Override public synchronized void undo() throws CannotUndoException { super.undo(); cnt_edit_actions--; cnt_undo_actions++; if (cnt_edit_actions == 0) { saveAction.setEnabled(false); undoAction.setEnabled(false); } else { saveAction.setEnabled(true); } redoAction.setEnabled(true); } // undo @Override public synchronized void redo() throws CannotUndoException { super.redo(); cnt_edit_actions++; cnt_undo_actions--; saveAction.setEnabled(true); undoAction.setEnabled(true); redoAction.setEnabled(cnt_undo_actions != 0); } // redo public synchronized void save() { notesText = notes_text_area.getText(); // delete emty notes files if (notesText.equals("")) { if (delete(deleteAction.isEnabled()) != 0) { // delete if file exists undo_all(); // undo all changes if not confirmed } removeUndoMananger(); return; } final int status = updateNotes(exp_id, SAVE_FILE, AnUtility.addNewLine(notesText), true); if (status != 0) { window.showError(AnLocale.getString("Cannot write notes file")); undo_all(); } else { deleteAction.setEnabled(true); final DefaultMutableTreeNode root; final DefaultMutableTreeNode node; root = ((DefaultMutableTreeNode) tree.getModel().getRoot()); node = (DefaultMutableTreeNode) root.getChildAt(exp_id + 1); ((DefaultTreeModel) tree.getModel()).nodeChanged(node); updateAllExps(SAVE_FILE); } removeUndoMananger(); } // save public synchronized int delete(final boolean confirm) { if (confirm) { final int resp = JOptionPane.showConfirmDialog( window.getFrame(), AnLocale.getString("Delete notes file ?"), UIManager.getString("OptionPane.titleText"), JOptionPane.YES_NO_OPTION); if (resp != JOptionPane.YES_OPTION) { return -1; } } final int status = updateNotes(exp_id, DELETE_FILE, null, true); notesText = AnLocale.getString("<Empty>"); deleteAction.setEnabled(false); if (status != 0) { if (confirm) { window.showError(AnLocale.getString("Cannot delete notes file")); } return -1; } notes_text_area.setText(AnUtility.trimNewLine(notesText)); updateAllExps(DELETE_FILE); removeUndoMananger(); return 0; } // delete private void undo_all() { while (cnt_edit_actions > 0) { undo(); } } // undo_all } } private int updateNotes( final int exp_id, final int type, final String text, final boolean handle_file) { synchronized (IPC.lock) { window.IPC().send("updateNotes"); window.IPC().send(0); window.IPC().send(exp_id); window.IPC().send(type); window.IPC().send(text); window.IPC().send(handle_file); return window.IPC().recvInt(); } } private class AnMenuListener extends MouseAdapter { private boolean debug; // NM private AnTable anTable; JTree tree; AnMenuListener(JTree tree) { this.tree = tree; debug = false; } public JPopupMenu initPopup(MouseEvent event) { AccessibleContext ac; JMenuItem mi; JPopupMenu popup = new JPopupMenu(); String txt; boolean row_selected = false; int row = tree.getLeadSelectionRow(); if (row >= 0) { row_selected = true; } return popup; } @Override public void mousePressed(MouseEvent e) { maybeShowPopup(e); } @Override public void mouseReleased(MouseEvent e) { maybeShowPopup(e); } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { JPopupMenu popup = initPopup(e); if (popup != null) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeInvisible(" + e + ")"); } } public void popupMenuWillBecomeVisible(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuWillBecomeVisible(" + e + ")"); } } public void popupMenuCanceled(PopupMenuEvent e) { if (debug) { System.out.println("AnMenuListener:popupMenuCanceled(" + e + ")"); } } } @Override public java.util.List<ExportFormat> getSupportedExportFormats() { java.util.List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return true; } } �������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ExperimentPickList.java��������������������������������������������0000644�0001750�0001750�00000007537�14517772113�020377� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.picklist.PickList; import org.gprofng.mpmt.picklist.PickListElement; import java.io.File; import java.util.ArrayList; import java.util.List; public class ExperimentPickList extends PickList { public ExperimentPickList(int max) { super(max); } public List<ExperimentPickListElement> getRecentExperiments() { List<ExperimentPickListElement> list = new ArrayList<ExperimentPickListElement>(); List<PickListElement> mostRecentExperiments = getElements(); for (PickListElement ple : mostRecentExperiments) { list.add((ExperimentPickListElement) ple); } return list; } public List<ExperimentPickListElement> getRecentExperiments(int max) { int numberAdded = 0; List<ExperimentPickListElement> list = new ArrayList<ExperimentPickListElement>(); List<PickListElement> mostRecentExperiments = getElements(); for (PickListElement ple : mostRecentExperiments) { list.add((ExperimentPickListElement) ple); numberAdded++; if (max > 0 && numberAdded >= max) { break; } } return list; } public List<ExperimentPickListElement> getRecentValidExperiments(int max) { int numberAdded = 0; List<ExperimentPickListElement> list = new ArrayList<ExperimentPickListElement>(); List<PickListElement> mostRecentExperiments = getElements(); for (PickListElement ple : mostRecentExperiments) { if (exists(((ExperimentPickListElement) ple).getPath())) { list.add((ExperimentPickListElement) ple); numberAdded++; if (max > 0 && numberAdded >= max) { break; } } } return list; } public void removeExperiment(String path) { List<ExperimentPickListElement> list = getRecentExperiments(); for (ExperimentPickListElement experimentPickListElement : list) { if (experimentPickListElement.getPath().equals(path)) { removeElement(experimentPickListElement); break; } } } private boolean exists(String path) { // FIXUP: need to validate on remote host in case of remote String host = Analyzer.getInstance().getHost(); if (host == null || !host.equals("localhost")) { return true; // FIXUP: need to validate on remote host in case of remote } FileExists fileExists = new FileExists(path); fileExists.start(); try { fileExists.join(100); // Wait at most .1 sec for result. Interrupt if hanging. fileExists.interrupt(); } catch (InterruptedException ie) { } // System.out.println(path + " " + exists.existsResult.exists); return fileExists.getExistsResult().exists; } private class ExistsResult { public boolean exists = false; } private class FileExists extends Thread { private final String path; private final ExistsResult existsResult = new ExistsResult(); public FileExists(String path) { this.path = path; } // @Override @Override public void run() { // System.out.println("Checking " + path); existsResult.exists = new File(path).exists(); } /** * @return the existsResult */ public ExistsResult getExistsResult() { return existsResult; } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ITreeToPanel.java��������������������������������������������������0000644�0001750�0001750�00000001502�14517772113�017071� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; /** * @author nd159473 */ public interface ITreeToPanel { public IExtTreeModel getModel(); public void onSelect(int i, Object aRace); } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/IDispToModel.java��������������������������������������������������0000644�0001750�0001750�00000001714�14517772113�017077� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; /** * @author nd159473 */ // this interface from a race tree model to race disp public interface IDispToModel { public String[] getSubEventsDataData(final int exp_id, final int race_id, final int type); public AnWindow getWindow(); public IExtTreeModel createModel(); } ����������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/���������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�014605� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCRequest.java������������������������������������������������0000644�0001750�0001750�00000010635�14517772113�017344� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; class IPCRequest { private StringBuilder body; protected IPCRequest() { body = new StringBuilder(); } protected void append(final int i) { body.append(sendByte(IPCProtocol.L_INTEGER)); body.append(sendVal(i)); } protected void append(final long l) { body.append(sendByte(IPCProtocol.L_LONG)); body.append(sendVal(l)); } protected void append(final boolean b) { body.append(sendByte(IPCProtocol.L_BOOLEAN)); body.append(sendVal(b)); } protected void append(final String s) { body.append(sendByte(IPCProtocol.L_STRING)); String ss = sendVal(s); body.append(ss); } protected void append(final Object object) { body.append(sendByte(IPCProtocol.L_ARRAY)); body.append(sendVal(object)); } protected String getBody() { return body.toString(); } private String sendByte(final int b) { return IPCProtocol.encodeByte(b); } private String sendVal(final long l) { return IPCProtocol.encodeVal(l); } private String sendVal(final int i) { return IPCProtocol.encodeVal(i); } private String sendVal(final String s) { if (s == null) { return sendVal(-1); } byte[] sb = s.getBytes(); StringBuilder buf = new StringBuilder(); buf.append(sendVal(sb.length)); for (byte b : sb) { buf.append((char) b); } return buf.toString(); } private String sendVal(final boolean b) { return sendByte(b ? 1 : 0); } private String sendVal(final char c) { return sendByte((int) c); } private String sendVal(final double d) { return sendVal(Double.toString(d)); } private String sendVal(final Object object) { StringBuilder buf = new StringBuilder(); if (object == null) { buf.append(sendByte(IPCProtocol.L_INTEGER)); buf.append(sendVal(-1)); return buf.toString(); } if (object instanceof double[]) { buf.append(sendByte(IPCProtocol.L_DOUBLE)); final double[] array = (double[]) object; buf.append(sendVal(array.length)); for (int i = 0; i < array.length; i++) { buf.append(sendVal(array[i])); } } else if (object instanceof int[]) { buf.append(sendByte(IPCProtocol.L_INTEGER)); final int[] array = (int[]) object; buf.append(sendVal(array.length)); for (int i = 0; i < array.length; i++) { buf.append(sendVal(array[i])); } } else if (object instanceof long[]) { buf.append(sendByte(IPCProtocol.L_LONG)); final long[] array = (long[]) object; buf.append(sendVal(array.length)); for (int i = 0; i < array.length; i++) { buf.append(sendVal(array[i])); } } else if (object instanceof char[]) { buf.append(sendByte(IPCProtocol.L_CHAR)); final char[] array = (char[]) object; buf.append(sendVal(array.length)); for (int i = 0; i < array.length; i++) { buf.append(sendVal(array[i])); } } else if (object instanceof boolean[]) { buf.append(sendByte(IPCProtocol.L_BOOLEAN)); final boolean[] array = (boolean[]) object; buf.append(sendVal(array.length)); for (int i = 0; i < array.length; i++) { buf.append(sendVal(array[i])); } } else if (object instanceof String[]) { buf.append(sendByte(IPCProtocol.L_STRING)); final String[] array = (String[]) object; buf.append(sendVal(array.length)); for (int i = 0; i < array.length; i++) { buf.append(sendVal(array[i])); } } else if (object instanceof Object[]) { buf.append(sendByte(IPCProtocol.L_OBJECT)); final Object[] array = (Object[]) object; buf.append(sendVal(array.length)); for (int i = 0; i < array.length; i++) { buf.append(sendVal(array[i])); } } return buf.toString(); } } ���������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCHandle.java�������������������������������������������������0000644�0001750�0001750�00000033025�14517772113�017105� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.ipc.IPCProtocol.CurChar; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import javax.swing.JOptionPane; /** * Examples: * * <p>// Simplest code IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); * ipcHandle.append("getFilterStr"); ipcHandle.append(window.getID()); IPCResult ipcResult = * ipcHandle.sendRequest(); String result = ipcResult.getString(); // blocking * * <p>// Checking completion code IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); * ipcHandle.append("getFilterStr"); ipcHandle.append(window.getID()); IPCResult ipcResult = * ipcHandle.sendRequest(); if (ipcResult.getCC() == IPCResult.CC.SUCCESS) { // blocking // Things * are fine String result = ipcResult.getString(); return result; } else { // error handling } * * <p>// Handling progress, not cancellable IPCContext ipcContext = new * IPCContext(IPCContext.Scope.WINDOW, this); IPCHandle ipcHandle = new * IPCHandle(IPCHandle.RequestKind.DBE, ipcContext); ipcHandle.append("getFilterStr"); * ipcHandle.append(window.getID()); ipcHandle.addIPCListener(new IPCListener() { public void * started(int requestId) { System.out.println("*******: MyOwnProgressListener: " + requestId + " * Start..."); } public void progress(int requestId, String what, int percentage) { * System.out.println("*******: MyOwnProgressListener: " + requestId + " " + what + " " + * percentage); } public void finished(int requestId, IPCResult ipcResult) { * System.out.println("*******: MyOwnProgressListener: " + requestId + " " + " Stop..."); } }); * IPCResult ipcResult = ipcHandle.sendRequest(); String result = ipcResult.getString(); // blocking * * <p>// Handling progress, cancellable IPCContext ipcContext = new IPCContext("getFilterStr", * IPCContext.Scope.WINDOW, true, false, IPCContext.Request.SINGLE, 1, this); IPCHandle ipcHandle = * new IPCHandle(IPCHandle.RequestKind.DBE, ipcContext); ipcHandle.append("getFilterStr"); * ipcHandle.append(window.getID()); ipcHandle.addIPCListener(new IPCListener() { public void * started(int requestId) { System.out.println("*******: MyOwnProgressListener: " + requestId + " * Start..."); } public void progress(int requestId, String what, int percentage) { * System.out.println("*******: MyOwnProgressListener: " + requestId + " " + what + " " + * percentage); } public void finished(int requestId, IPCResult ipcResult) { * System.out.println("*******: MyOwnProgressListener: " + requestId + " " + " Stop..."); } }); * IPCResult ipcResult = ipcHandle.sendRequest(); if (ipcResult.getCC() == IPCResult.CC.SUCCESS) { * // blocking // Things are fine String result = ipcResult.getString(); return result; } else * (ipcResult.getCC() == IPCResult.CC.CANCELED) // cancelled } else { // error handling } * * <p>// Handling progress and reading result in finished() callback IPCContext ipcContext = new * IPCContext("getFilterStr", IPCContext.Scope.WINDOW, true, false, IPCContext.Request.SINGLE, 1, * this); IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE, ipcContext); * ipcHandle.append("getFilterStr"); ipcHandle.append(window.getID()); ipcHandle.addIPCListener(new * IPCListener() { public void started(int requestId) { System.out.println("*******: * MyOwnProgressListener: " + requestId + " Start..."); } public void progress(int requestId, String * what, int percentage) { System.out.println("*******: MyOwnProgressListener: " + requestId + " " + * what + " " + percentage); } public void finished(int requestId, IPCResult ipcResult) { * System.out.println("*******: MyOwnProgressListener: " + requestId + " " + " Stop..."); String * result = ipcResult.getString(); // blocking but result is ready System.out.println("*******: * MyOwnProgressListener: " + requestId + " Result=" + result); } }); IPCResult ipcResult = * ipcHandle.sendRequest(); * * <p>// Handling progress and reading result in main flow and in finishd() callback IPCContext * ipcContext = new IPCContext("getFilterStr", IPCContext.Scope.WINDOW, true, false, * IPCContext.Request.SINGLE, 1, this); IPCHandle ipcHandle = new * IPCHandle(IPCHandle.RequestKind.DBE, ipcContext); ipcHandle.append("getFilterStr"); * ipcHandle.append(window.getID()); ipcHandle.addIPCListener(new IPCListener() { public void * started(int requestId) { System.out.println("*******: MyOwnProgressListener: " + requestId + " * Start..."); } public void progress(int requestId, String what, int percentage) { * System.out.println("*******: MyOwnProgressListener: " + requestId + " " + what + " " + * percentage); } public void finished(int requestId, IPCResult ipcResult) { * System.out.println("*******: MyOwnProgressListener: " + requestId + " " + " Stop..."); // Result * can be read here and/or in main flow // Need to rewind input buffer before result is read again * ipcResult.rewindInputBuffer(); String result = ipcResult.getString(); // blocking * System.out.println("*******: MyOwnProgressListener: " + requestId + " Result=" + result); } }); * IPCResult ipcResult = ipcHandle.sendRequest(); String result = ipcResult.getString(); // blocking */ public class IPCHandle { private static int globalRequestID = 0; public enum RequestKind { NON_DBE, DBE }; public enum RequestType { DEFAULT(0), CANCEL(1), HANDSHAKE(2); private final int index; RequestType(int index) { this.index = index; } public int index() { return index; } }; private List<IPCListener> ipcListeners = new ArrayList<IPCListener>(); private RequestType requestType; private IPCContext ipcContext; private IPCRequest ipcRequest; public IPCHandle(RequestKind requestKind) { this(requestKind, null); } public IPCHandle(RequestKind requestKind, IPCContext ipcContext) { requestType = RequestType.DEFAULT; if (ipcContext == null) { if (requestKind == RequestKind.DBE) { ipcContext = IPCContext.getDefaultDBEIPCContext(); } else { ipcContext = IPCContext.getDefaultNONDBEIPCContext(); } } this.ipcContext = ipcContext; this.ipcRequest = new IPCRequest(); } public static IPCHandle newHandshakeIPCHandle() { return new IPCHandle(RequestType.HANDSHAKE, IPCContext.getDefaultNONDBEIPCContext()); } public static IPCHandle newCancelIPCHandle(IPCContext originalIPCContext, int originalRequestID) { IPCContext ipcContext = IPCContext.newCancelContext( originalIPCContext.getChannel(), originalIPCContext.getRequest() == IPCContext.Request.SINGLE ? originalRequestID : -1); return new IPCHandle(RequestType.CANCEL, ipcContext); } protected IPCHandle(RequestType requestType, IPCContext ipcContext) { this.requestType = requestType; this.ipcContext = ipcContext; } public void append(final int i) { ipcRequest.append(i); } public void append(final long l) { ipcRequest.append(l); } public void append(final boolean b) { ipcRequest.append(b); } public void append(final String s) { ipcRequest.append(s); } public void append(final Object object) { ipcRequest.append(object); } private static synchronized int getNextGlobalRequestID() { globalRequestID++; return (globalRequestID); } public synchronized IPCResult sendRequest() { int requestID = getNextGlobalRequestID(); // globalRequestID++; IPCResult ipcResult = new IPCResult(this, requestID, ipcContext); Analyzer.getInstance().IPC_session.getIPCReader().addToRequestPool(ipcResult); OutputStream processInput = Analyzer.getInstance().IPC_session.getOutputStream(); try { String requestBody = null; byte[] requestBodyBytes = new byte[0]; // default empty body if (ipcRequest != null) { requestBody = ipcRequest.getBody(); requestBodyBytes = requestBody.getBytes(); } IPCRequestHeader ipcRequestHeader = null; if (requestType == RequestType.DEFAULT) { ipcRequestHeader = new IPCRequestHeader( requestID, requestType, ipcContext.getChannel(), requestBodyBytes.length); } else if (requestType == RequestType.HANDSHAKE) { ipcRequestHeader = new IPCRequestHeader( requestID, requestType, ipcContext.getChannel(), IPCProtocol.version); } else if (requestType == RequestType.CANCEL) { ipcRequestHeader = new IPCRequestHeader( requestID, requestType, ipcContext.getCancelChannel(), ipcContext.getCancelRequest()); } else { assert false; } String headerBody = ipcRequestHeader.getBody(); byte[] headerBodyBytes = headerBody.getBytes(); IPCLogger.logRequest(headerBody, requestBody); String request = ""; if (requestBodyBytes != null && requestBodyBytes.length > 0) { CurChar curChar = new CurChar(); IPCProtocol.decodeByte(requestBodyBytes, curChar); request = "\"" + IPCProtocol.decodeSVal(requestBodyBytes, curChar) + "\""; } IPCLogger.logTrace( ipcRequestHeader.getRequestID() + " IPCHandle sendRequest " + ipcContext.getChannel() + " " + request); // send header and body using one write String request_str = headerBody; if (null != requestBody) { request_str += requestBody; } byte[] request_arr = request_str.getBytes(); processInput.write(request_arr); processInput.flush(); } catch (IOException ioe) { AnLog.log("sendRequest: IOException" + ioe); // ioe.getStackTrace()); // ioe.printStackTrace(); if (Analyzer.getInstance().known_problem_10.equals(ioe.getMessage())) { // Show error dialog and exit if (null != Analyzer.getInstance().remoteConnection) { String msg = AnLocale.getString("Remote connection closed"); JOptionPane.showMessageDialog( (AnWindow.getInstance()).getFrame(), msg, AnLocale.getString("Error"), JOptionPane.ERROR_MESSAGE); System.err.println(msg); } else { if (Analyzer.getInstance().IPC_started != false) { System.err.println("Connection closed (gp-display-text died unexpectedly)"); } else { // Normal exit System.exit(0); // Should we simply return null here? } } System.exit(1); // AnWindow.getInstance().exitAction(); } throw new IPC.AnIPCException(ioe); } catch (Exception e) { if (null != Analyzer.getInstance().remoteConnection) { String msg = AnLocale.getString("Remote connection closed"); JOptionPane.showMessageDialog( (AnWindow.getInstance()).getFrame(), msg, AnLocale.getString("Error"), JOptionPane.ERROR_MESSAGE); System.err.println(msg); System.exit(1); // AnWindow.getInstance().exitAction(); } AnLog.log("sendRequest: Exception" + e); // e.printStackTrace(); throw new IPC.AnIPCException(e); } return ipcResult; } public void addIPCListener(IPCListener listener) { synchronized (ipcListeners) { ipcListeners.add(listener); } } public void removeIPCListener(IPCListener listener) { synchronized (ipcListeners) { ipcListeners.remove(listener); } } protected void fireResponse(IPCResponse ipcResponse, IPCResult ipcResult) { if (ipcListeners.isEmpty()) { return; } if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.ACK) { synchronized (ipcListeners) { for (IPCListener listener : ipcListeners) { listener.started(ipcResponse.getHeader().getRequestID()); } } } else if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.COMPLETE) { synchronized (ipcListeners) { for (IPCListener listener : ipcListeners) { listener.finished(ipcResponse.getHeader().getRequestID(), ipcResult); } } } else if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.HANDHAKE) { } else if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.PROGRESS) { IPCProtocol.CurChar curChar = new IPCProtocol.CurChar(); int progress = IPCProtocol.decodeByte(ipcResponse.getBody(), curChar); int percentage = IPCProtocol.decodeIVal(ipcResponse.getBody(), curChar); String what = IPCProtocol.decodeSVal(ipcResponse.getBody(), curChar); synchronized (ipcListeners) { for (IPCListener listener : ipcListeners) { listener.progress(ipcResponse.getHeader().getRequestID(), what, percentage); } } } else { assert false; } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCTester.java�������������������������������������������������0000644�0001750�0001750�00000003530�14517772113�017156� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; import org.gprofng.mpmt.util.gui.AnUtility; public class IPCTester { public static int ipcTestCounter = 0; public static class IPCTestSender implements Runnable { @Override public void run() { System.out.println("\nStart"); for (int i = 0; i < 25; i++) { if (i == 10) { IPCLogger.setIpcDelay(500); } IPCHandle ipcHandle = IPCHandle.newHandshakeIPCHandle(); IPCResult ipcResult = ipcHandle.sendRequest(); // no body IPCTestReader ccReader = new IPCTestReader(ipcResult, ipcTestCounter++); System.out.println("Request " + ipcTestCounter + " sent"); AnUtility.dispatchOnAWorkerThread(ccReader, "CCReader" + " " + ipcTestCounter); } System.out.println("End"); } } private static class IPCTestReader implements Runnable { IPCResult ipcResult = null; int counter; public IPCTestReader(IPCResult ipcResult, int counter) { this.ipcResult = ipcResult; this.counter = counter; } @Override public void run() { IPCResult.CC cc = ipcResult.getCC(); // blocking System.out.println("Result " + counter + " received: " + cc); } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCContext.java������������������������������������������������0000644�0001750�0001750�00000015112�14517772113�017333� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; /** */ public class IPCContext { private static final int NON_DBE_CHANNEL = 0; private static final int DEF_DBE_CHANNEL = 1; private static final int UNIQUE_DBE_CHANNEL_START = 2; private static int currentUniqueDBEChannel = UNIQUE_DBE_CHANNEL_START; public enum Scope { SYSTEM, SESSION, NONE }; public enum Request { SINGLE, GROUP }; private static final IPCContext defaultDBEIPCContext = new IPCContext(null, Scope.NONE, false, false, Request.SINGLE, 1, null); private static final IPCContext defaultNONDBEIPCContext = new IPCContext(null, Scope.SYSTEM, false, false, Request.SINGLE, 0, null); private String taskName; private Scope scope; private boolean systemProgressBar; private boolean cancellable; private Request request; private int channel; private AnWindow anWindow; private int cancelChannel; private int cancelRequest; /** * Context for progress updates. Creates a context that has progress updates but task is not * cancellable. * * @param scope the scope of the command. WINDOW: progress update on anWindow only. SESSION: * progress update on all windows. * @param anWindow the current anWindow (owner of progress status panel) */ public IPCContext(Scope scope, AnWindow anWindow) { this(null, scope, true, false, Request.SINGLE, -1, anWindow); } /** * Context for progress updates and cancellable task. Creates a context that has progress updates * and task is cancellable. * * @param userActionName name of task used in cancel dialog * @param scope the scope of the command. WINDOW: progress update in current AnWindow only. * SESSION: progress updates in all windows. * @param systemProgressBar set to true to enable system progress updates * @param cancellable set to true to make this task cancellable via the progress status * @param request whether to cancel a single request or a group of request (on a unique channel) * @param channel the channel to cancel in case of request==GROUP * @param anWindow the current anWindow (owner of progress status panel) */ public IPCContext( String taskName, Scope scope, boolean systemProgressBar, boolean cancellable, Request request, int channel, AnWindow anWindow) { this.taskName = taskName; this.scope = scope; this.systemProgressBar = systemProgressBar; this.cancellable = cancellable; this.request = request; this.channel = channel; this.anWindow = anWindow; } /** * Context for a cancel request * * @param cancelChannel * @param cancelRequest */ private IPCContext(int cancelChannel, int cancelRequest) { this.cancelChannel = cancelChannel; this.cancelRequest = cancelRequest; } public static IPCContext newDBEIPCContext( String userActionName, Scope scope, boolean systemProgressBar, boolean cancellable, Request request, AnWindow anWindow) { return new IPCContext( userActionName, scope, systemProgressBar, cancellable, request, request == Request.SINGLE ? DEF_DBE_CHANNEL : getUniqueDBEChannel(), anWindow); } public static IPCContext newNONDBEIPCContext( String userActionName, boolean systemProgressBar, boolean cancellable) { return new IPCContext( userActionName, Scope.SYSTEM, systemProgressBar, cancellable, Request.SINGLE, NON_DBE_CHANNEL, null); } public static IPCContext newCancelContext(int cancelChannel, int cancelRequest) { return new IPCContext(cancelChannel, cancelRequest); } public static IPCContext getDefaultDBEIPCContext() { return defaultDBEIPCContext; } public static IPCContext getDefaultNONDBEIPCContext() { return defaultNONDBEIPCContext; } /** * @return the taskName */ public String getTaskName() { return taskName; } /** * @param taskName the taskName to set */ public void setTaskName(String taskName) { this.taskName = taskName; } /** * @return the scope */ public Scope getScope() { return scope; } /** * @return the systemProgressBar */ public boolean isSystemProgressBar() { return systemProgressBar; } /** * @return the cancellable */ public boolean isCancellable() { return cancellable; } /** * @param cancellable the cancellable to set */ public void setCancellable(boolean cancellable) { this.cancellable = cancellable; } /** * @return the request */ public Request getRequest() { return request; } /** * @return the channel */ public int getChannel() { return channel; } /** * @return the anWindow */ public AnWindow getAnWindow() { return anWindow; } /** * @return the cancelChannel */ public int getCancelChannel() { return cancelChannel; } /** * @return the cancelRequest */ public int getCancelRequest() { return cancelRequest; } private static int getUniqueDBEChannel() { return currentUniqueDBEChannel++; } /*********/ private static IPCContext currentContext = defaultDBEIPCContext; public static IPCContext newCurrentContext( String userActionName, Scope scope, boolean cancellable, AnWindow anWindow) { if (userActionName == null) { userActionName = AnLocale.getString("Unknown action...."); } currentContext = newDBEIPCContext( userActionName, scope, true, cancellable, Request.GROUP, anWindow); // Default not cancellable // // System.out.print("\n--------------------------------------------------------newCurrentContext: " + currentContext.getChannel()); return currentContext; } public static IPCContext getCurrentContext() { return currentContext; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCCancelledException.java�������������������������������������0000644�0001750�0001750�00000001352�14517772113�021441� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; public class IPCCancelledException extends Error {} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCResponseHeader.java�����������������������������������������0000644�0001750�0001750�00000005061�14517772113�020620� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ /** * <Header, ResponseBody> where * * <p>Header <HeaderMarker, RequestID, ResponseType, ResponseStatus, nBytes> * * <p>HeaderMarker (1 byte, value=255) RequestID (4 bytes) ResponseType (INTEGER): (1 byte) o 0: ACK * o 1: PROGRESS o 2: COMPLETE o 3: HANDSHAKE ResponseStatus: (1 byte) o 0: DEFAULT, IGNORE o 1: * SUCCESS o 2: FAILURE o 3: CANCELED -or- o VersionID in case of Handshake requests nBytes: Number * of bytes in the response body (4 bytes) * * <p>ResponseBody string containing the final result or intermediate status details */ package org.gprofng.mpmt.ipc; class IPCResponseHeader { protected static final int headerSizeInBytes = 11; protected enum ResponseType { ACK(0), PROGRESS(1), COMPLETE(2), HANDHAKE(3); private final int value; private ResponseType(int value) { this.value = value; } protected int value() { return value; } protected static ResponseType fromValue(int val) { for (ResponseType rt : ResponseType.values()) { if (rt.value() == val) { return rt; } } return null; } }; private int requestID; private ResponseType responseType; private IPCResult.CC responseStatus; private int nBytes; protected IPCResponseHeader( int requestID, ResponseType responseType, IPCResult.CC responseStatus, int nBytes) { this.requestID = requestID; this.responseType = responseType; this.responseStatus = responseStatus; this.nBytes = nBytes; } /** * @return the requestID */ protected int getRequestID() { return requestID; } /** * @return the responseType */ protected ResponseType getResponseType() { return responseType; } /** * @return the responseStatus */ protected IPCResult.CC getResponseStatus() { return responseStatus; } /** * @return the nBytes */ protected int getnBytes() { return nBytes; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCResponse.java�����������������������������������������������0000644�0001750�0001750�00000002075�14517772113�017511� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; class IPCResponse { private IPCResponseHeader header; private byte[] body; protected IPCResponse(IPCResponseHeader header, byte[] body) { this.header = header; this.body = body; } /** * @return the header */ protected IPCResponseHeader getHeader() { return header; } /** * @return the body */ protected byte[] getBody() { return body; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCReader.java�������������������������������������������������0000644�0001750�0001750�00000026322�14517772113�017116� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.util.gui.AnUtility; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class IPCReader implements Runnable { private IPC ipc; private Map<Integer, IPCResult> requestPool = new HashMap<Integer, IPCResult>(); private final int READY_TO_RUN = 1; private final int RUNNING = 2; private final int REQUEST_TO_STOP = 3; private final int CONNECTING = 4; // Temporary solution for remote analyzer: special state "CONNECTING" private final int CONNECTION_CLOSDED = 5; // Connection closed by gp-display-text private final int RESTARTING = 6; // Restarting gp-display-text private int state = READY_TO_RUN; private String unknown_input = ""; // Internal statistics private long totalReceivedMessages = 0; private long totalReceivedBytes = 0; public IPCReader(IPC ipc) { this.ipc = ipc; state = RUNNING; new Thread(this, "IPCReader").start(); } // NM Temporary solution for remote analyzer: use flag "run" to decide how to read data public IPCReader(IPC ipc, boolean run) { this.ipc = ipc; if (run) { state = RUNNING; } else { state = CONNECTING; } new Thread(this, "IPCReader").start(); } /** Checks if thread is ready to run */ public boolean isThreadReady() { if (RUNNING == state) return true; if (READY_TO_RUN == state) return true; return (false); } /** Sets request to stop IPCReader thread */ public void stopThread() { state = REQUEST_TO_STOP; try { ipc.getInputStream().close(); ipc.getOutputStream().close(); } catch (IOException ex) { } } /** //NM Temporary solution for remote analyzer: Sets request to run IPCReader thread */ public void runThread() { state = RUNNING; } /** Sets request to suspend IPCReader thread */ public void suspendThread() { state = RESTARTING; // CONNECTING } /** Sets request to resume IPCReader thread */ public void resumeThread() { state = RUNNING; } /** Gets input as a String */ public String getUnknownInput() { return unknown_input; } /** Gets Total Received Bytes */ public long getTotalReceivedBytes() { return totalReceivedBytes; } /** Gets Total Received Messages */ public long getTotalReceivedMessages() { return totalReceivedMessages; } /** * Reads exactly buffer.length() bytes from stream. * * @param buffer * @return bytes read (buffer.length()) */ private int readFromInputStream(byte[] buffer) { try { int nBytesToRead = buffer.length; int nBytesRead = 0; while (nBytesRead < nBytesToRead) { int got = ipc.getInputStream().read(buffer, nBytesRead, nBytesToRead - nBytesRead); if (got < 0) { AnWindow.getInstance().getSystemProgressPanel().reset(); if (state == REQUEST_TO_STOP) { return 0; } if ((state == RESTARTING) || (state == CONNECTING)) { return got; } state = REQUEST_TO_STOP; // CONNECTION_CLOSDED; break; // throw new IPC.AnIPCException(); } totalReceivedBytes += got; nBytesRead += got; } return nBytesToRead; } catch (IOException ioe) { if (state == REQUEST_TO_STOP) { return 0; } state = REQUEST_TO_STOP; // CONNECTION_CLOSDED; return -1; // throw new IPC.AnIPCException(ioe); } } private byte[] readFromStream(int nBytes) { byte[] buffer = new byte[nBytes]; int got = readFromInputStream(buffer); return buffer; } // @Override @Override public void run() { while (true) { IPCResponseHeader ipcResponseHeader = null; byte[] responseBody = null; byte[] responseHeaderBytes = null; if (state != RUNNING) { // Read raw input byte[] responseHeaderBytes_1 = new byte[1]; int nBytes = readFromInputStream(responseHeaderBytes_1); if (state == REQUEST_TO_STOP) { // Connection closed break; } if (state == CONNECTING) { if (nBytes < 0) { // Connection error break; } for (int i = 0; i < nBytes; i++) { unknown_input += (char) responseHeaderBytes_1[i]; } continue; } if (state == RESTARTING) { if (nBytes < 0) { // Connection error // System.err.println("***** NOTE: RESTARTING: nBytes < 0"); break; } for (int i = 0; i < nBytes; i++) { unknown_input += (char) responseHeaderBytes_1[i]; } String restartEngine = "Restart engine"; if (unknown_input.contains(restartEngine)) { // System.err.println("***** NOTE: gp-display-text restarted"); resumeThread(); // System.err.println("***** NOTE: unknown_input:" + unknown_input); // clean unknown input unknown_input = ""; } continue; } if (nBytes < 0) { // Read error state = REQUEST_TO_STOP; // CONNECTION_CLOSDED; break; // throw new IPC.AnIPCException(); } // Read the rest of the header and combine it with the first byte byte[] responseHeaderBytes_2 = readFromStream(IPCResponseHeader.headerSizeInBytes * 2 - 1); if (state == REQUEST_TO_STOP) break; responseHeaderBytes = new byte[responseHeaderBytes_2.length + 1]; responseHeaderBytes[0] = responseHeaderBytes_1[0]; for (int i = 1; i < responseHeaderBytes.length; i++) { responseHeaderBytes[i] = responseHeaderBytes_2[i - 1]; } totalReceivedMessages++; } else { // state == RUNNING // clean unknown input unknown_input = ""; // Read a header and a nBytes (specified in header) body responseHeaderBytes = readFromStream(IPCResponseHeader.headerSizeInBytes * 2); totalReceivedMessages++; } if (state == REQUEST_TO_STOP) { break; } ipcResponseHeader = decodeIPCResponseHeader(responseHeaderBytes); if (ipcResponseHeader.getResponseType() != IPCResponseHeader.ResponseType.HANDHAKE) { int nBytes = ipcResponseHeader.getnBytes(); if (nBytes > 0) { responseBody = readFromStream(nBytes); } } IPCLogger.logResponse(responseHeaderBytes, responseBody); // Send result to IPCResult IPCResult ipcResult = findInRequestPool(ipcResponseHeader.getRequestID()); final int additionalLatency = IPCLogger.getIpcDelay(); // milliseconds if (ipcResult != null) { if (additionalLatency <= 0) { IPCResponse ipcResponse = new IPCResponse(ipcResponseHeader, responseBody); ipcResult.fireResponse(ipcResponse); ipcResult.getIPCHandle().fireResponse(ipcResponse, ipcResult); // Fixup: new thread? } else { // use a "latency" thread final IPCResult my_ipcResult = ipcResult; final IPCResponseHeader my_ipcResponseHeader = ipcResponseHeader; final byte[] my_responseBody = responseBody; AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { if (additionalLatency > 0) { try { Thread.sleep(additionalLatency); // milliseconds } catch (Exception e) { // check that we did sleep enough? } } IPCResponse ipcResponse = new IPCResponse(my_ipcResponseHeader, my_responseBody); my_ipcResult.fireResponse(ipcResponse); my_ipcResult.getIPCHandle().fireResponse(ipcResponse, my_ipcResult); } }, "AdditionalUploadLatency_thread"); } } else { if (IPCResponseHeader.ResponseType.PROGRESS == ipcResponseHeader.getResponseType()) { // System.err.println("***** NOTE: IPCReader: PROGRESS: ipcResult==null"); // // Check responseBody // String restartEngine = "Restart engine"; // IPCProtocol.CurChar curChar = new IPCProtocol.CurChar(); // int progress = IPCProtocol.decodeByte(responseBody, curChar); // int percentage = IPCProtocol.decodeIVal(responseBody, curChar); // String what = IPCProtocol.decodeSVal(responseBody, curChar); // if (100 == percentage) { // if (restartEngine.equals(what)) { // if ((state == RESTARTING) || (state == CONNECTING)) { // resumeThread(); // System.err.println("***** NOTE: gp-display-text restarted"); // } // } // } continue; } // System.err.println("********************ERROR: IPCReader: state="+state+" // ipcResponseHeader="+ipcResponseHeader.toString()+" // responseBody="+responseBody.toString()); if (state != RUNNING) { continue; // ignore all messages } // FIXUP should not happen System.err.println("********************ERROR: IPCReader: ipcHandle==null"); assert false; } } } private IPCResponseHeader decodeIPCResponseHeader(byte[] bytes) { IPCProtocol.CurChar curChar = new IPCProtocol.CurChar(); int headerMarker = IPCProtocol.decodeByte(bytes, curChar); if (headerMarker != IPCProtocol.L_HEADER) { // FIXUP assert false; } int requestID = IPCProtocol.decodeIVal(bytes, curChar); int responseType = IPCProtocol.decodeByte(bytes, curChar); int responseStatus = IPCProtocol.decodeByte(bytes, curChar); int nBytes = IPCProtocol.decodeIVal(bytes, curChar); IPCResponseHeader ipcResponseHeader = new IPCResponseHeader( requestID, IPCResponseHeader.ResponseType.fromValue(responseType), IPCResult.CC.fromValue(responseStatus), nBytes); return ipcResponseHeader; } protected void addToRequestPool(IPCResult ipcResult) { IPCLogger.logTrace("\n" + ipcResult.getRequestID() + " IPCReader addToRequestPool"); synchronized (requestPool) { requestPool.put(ipcResult.getRequestID(), ipcResult); } } protected IPCResult findInRequestPool(int ipcRequestId) { synchronized (requestPool) { return requestPool.get(ipcRequestId); } } protected void removeFromRequestPool(int ipcRequestId) { IPCLogger.logTrace(ipcRequestId + " IPCReader removeFromRequestPool"); synchronized (requestPool) { requestPool.remove(ipcRequestId); } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCProtocol.java�����������������������������������������������0000644�0001750�0001750�00000006307�14517772113�017516� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; public class IPCProtocol { public static final int version = 38; // IPC PROTOCOL VERSION - DO NOT CHANGE THIS COMMENT public static final String IPC_PROTOCOL_STR = "IPC_PROTOCOL_" + version; // Dodona build 29 protected static final int L_PROGRESS = 0; protected static final int L_INTEGER = 1; protected static final int L_BOOLEAN = 2; protected static final int L_LONG = 3; protected static final int L_STRING = 4; protected static final int L_DOUBLE = 5; protected static final int L_ARRAY = 6; protected static final int L_OBJECT = 7; protected static final int L_CHAR = 8; protected static final int L_HEADER = 255; protected static final char[] hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; protected static String encodeByte(final int b) { StringBuilder buf = new StringBuilder(); buf.append(hex[(b >> 4) & 0xf]); buf.append(hex[b & 0xf]); return buf.toString(); } protected static String encodeVal(final int i) { StringBuilder buf = new StringBuilder(); for (int j = 28; j >= 0; j = j - 4) { buf.append(hex[(i >> j) & 0xf]); } return buf.toString(); } protected static String encodeVal(final long l) { StringBuilder buf = new StringBuilder(); for (int j = 60; j >= 0; j = j - 4) { buf.append(hex[(int) ((l >> j) & 0xf)]); } return buf.toString(); } protected static class CurChar { int pos = 0; } protected static int decodeByte(byte[] bytes, CurChar curChar) { int val = 0; for (int i = 0; i < 2; i++) { final int c = bytes[curChar.pos]; curChar.pos++; switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': val = val * 16 + c - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': val = val * 16 + c - 'a' + 10; break; } } return val; } protected static int decodeIVal(byte[] bytes, CurChar curChar) { int val = decodeByte(bytes, curChar); for (int i = 0; i < 3; i++) { val = val * 256 + decodeByte(bytes, curChar); } return val; } protected static String decodeSVal(byte[] bytes, CurChar curChar) { int len = decodeIVal(bytes, curChar); if (len == -1) { return null; } String s = new String(bytes, curChar.pos, len); curChar.pos += len; return s; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCErrorReader.java��������������������������������������������0000644�0001750�0001750�00000007117�14517772113�020131� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; import org.gprofng.mpmt.IPC; import java.io.IOException; import java.util.HashMap; import java.util.Map; public class IPCErrorReader implements Runnable { private IPC ipc; private Map<Integer, IPCResult> requestPool = new HashMap<Integer, IPCResult>(); private final int READY_TO_RUN = 1; private final int RUNNING = 2; private final int REQUEST_TO_STOP = 3; private final int CONNECTING = 4; // NM Temporary solution for remote analyzer: special state "CONNECTING" private int state = READY_TO_RUN; private String unknown_input = ""; public IPCErrorReader(IPC ipc) { this.ipc = ipc; state = RUNNING; new Thread(this, "IPCErrorReader").start(); } // NM Temporary solution for remote analyzer: use flag "run" to decide how to read data public IPCErrorReader(IPC ipc, boolean run) { this.ipc = ipc; if (run) { state = RUNNING; } else { state = CONNECTING; } new Thread(this, "IPCErrorReader").start(); } /** Sets request to stop IPCErrorReader thread */ public void stopThread() { state = REQUEST_TO_STOP; try { ipc.getErrorStream().close(); } catch (IOException ex) { } } /** //NM Temporary solution for remote analyzer: Sets request to run IPCReader thread */ public void runThread() { state = RUNNING; } /** Sets request to run IPCErrorReader thread */ public String getUnknownInput() { return unknown_input; } /** * Reads bytes from standard error stream. * * @param buffer * @return bytes read (buffer.length()) */ private int readFromErrorStream(byte[] buffer) { try { int nBytesToRead = buffer.length; int nBytesRead = 0; while (nBytesRead < nBytesToRead) { int got = ipc.getErrorStream().read(buffer, nBytesRead, nBytesToRead - nBytesRead); if (got < 0) { if (state == REQUEST_TO_STOP) { return 0; } if (state == CONNECTING) { return got; } throw new IPC.AnIPCException(); } nBytesRead += got; } return nBytesToRead; } catch (IOException ioe) { if (state == REQUEST_TO_STOP) { return 0; } throw new IPC.AnIPCException(ioe); } } // @Override public void run() { while (true) { try { byte[] buffer_1 = new byte[1]; int nBytes = readFromErrorStream(buffer_1); if (state == REQUEST_TO_STOP) { // Connection closed break; } if (nBytes < 0) { // Connection error break; } for (int i = 0; i < nBytes; i++) { char c = (char) buffer_1[i]; if (c == '\n') { System.err.println(unknown_input); unknown_input = ""; } else { unknown_input += c; } } continue; } catch (IPC.AnIPCException ae) { break; // gp-display-text closed stderr } } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCRequestHeader.java������������������������������������������0000644�0001750�0001750�00000005165�14517772113�020457� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; /** * <Header, RequestBody> where * * <p>Header: < HeaderMarker, RequestID, RequestType, ChannelID, nBytes/CancelRequestID/VersionID> * * <p>HeaderMarker (1 byte, value=255) RequestID: Unique numerical identifier generated by GUI - * positive integer - SIZE 4 bytes RequestType (INTEGER: enum SIZE 1 byte) o 0: Default: + Non-DBE * e.g. File Chooser, Remote Shell Command, Signal or + DBE e.g. Load Exp, Drop Exp, Get Data, Set * Filter o 1: Cancel o 2: Handshake ChannelID (INTEGER, SIZE 4 bytes) o 0: Non-DBE, or ignore in * case of Handshake requests o 1, 2, 3, ...: DBE nBytes: number of bytes in the request string. * (SIZE 4 bytes) OR CancelRequestID: For cancellation requests only, the ID of the request being * canceled. 0xFFFF for Cancel all requests OR VersionID: integer indicating version number in case * of Handshake requests * * <p>RequestBody: * * <p>RequestString: Body of the request itself (as a string). */ class IPCRequestHeader { private int requestID; private IPCHandle.RequestType requestType; private int channel; private int value; // nBytes in body (DEFAULT), cancelRequestID (CANCEL), version (HANDSHAKE) protected IPCRequestHeader( int requestID, IPCHandle.RequestType requestType, int channel, int value) { this.requestID = requestID; this.requestType = requestType; this.channel = channel; this.value = value; } protected String getBody() { StringBuilder buf = new StringBuilder(); buf.append(sendByte(IPCProtocol.L_HEADER)); buf.append(sendVal(requestID)); buf.append(sendByte(requestType.index())); buf.append(sendVal(channel)); buf.append(IPCProtocol.encodeVal(value)); return buf.toString(); } private String sendByte(final int b) { return IPCProtocol.encodeByte(b); } private String sendVal(final int i) { return IPCProtocol.encodeVal(i); } /** * @return the requestID */ protected int getRequestID() { return requestID; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCListener.java�����������������������������������������������0000644�0001750�0001750�00000002325�14517772113�017476� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; public interface IPCListener { /** * Fired when ACK is received from IPC * * @param requestId */ public void started(int requestId); /** * Fired when progress is received from IPC * * @param requestId * @param what * @param percentage */ public void progress(int requestId, String what, int percentage); /** * Fired when request has been completed (success, error, canceled, ...) * * @param requestId * @param ipcResult */ public void finished(int requestId, IPCResult ipcResult); } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCLogger.java�������������������������������������������������0000644�0001750�0001750�00000013445�14517772113�017135� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; import java.io.PrintStream; import java.util.Date; import java.util.Formatter; /* * Log Levels checks the following bits in the value of SP_ANALYZER_LOG_IPC * 1: log packages * 2: include time stamps * 4: log full package. Default is to trunckate packages at ~80 chars * 8: tracing * * Example: * SP_ANALYZER_LOG_IPC=0 no logging * SP_ANALYZER_LOG_IPC=1 log packages * SP_ANALYZER_LOG_IPC=3 log packages with timestamps (milliseconds since start) * SP_ANALYZER_LOG_IPC=8 tracing */ public class IPCLogger { private static final String ENVVAR = "SP_ANALYZER_LOG_IPC"; private static final String DELAYENVVAR = "SP_ANALYZER_IPC_DELAY"; private static PrintStream printStream = System.out; private static long now = new Date().getTime(); private static int maxNoCharsLogged = 140; private static int noCharsLogged = 0; private static boolean logPackage = false; private static boolean logTimeStamp = false; private static boolean logFullLine = false; private static boolean logTrace = false; private static Object lock = new Object(); private static int ipcDelay = 0; static { // Log level int logLevel = 0; String logIpc = System.getenv(ENVVAR); if (logIpc == null) { logIpc = System.getProperty(ENVVAR); } // Delay (to similuate slow connection (remote) ipcDelay = 0; String ipcDelayString = System.getenv(DELAYENVVAR); if (ipcDelayString == null) { ipcDelayString = System.getProperty(DELAYENVVAR); } if (ipcDelayString != null) { try { ipcDelay = new Integer(ipcDelayString).intValue(); } catch (NumberFormatException nfe) { } } if (logIpc != null) { try { if (logIpc.startsWith("0x") || logIpc.startsWith("0X")) { logLevel = Integer.parseInt(logIpc.substring(2), 16); } else { logLevel = Integer.parseInt(logIpc); } logPackage = (logLevel & 1) > 0; logTimeStamp = (logLevel & 2) > 0; logFullLine = (logLevel & 4) > 0; logTrace = (logLevel & 8) > 0; } catch (NumberFormatException nfe) { } if (logLevel > 0) { printStream.println( "IPC logging: trace=" + logTrace + " fullLine=" + logFullLine + " timestamp=" + logTimeStamp + " package=" + logPackage + " now=" + now); } } if (ipcDelay > 0) { String txt = "Adding a " + ipcDelay + "ms delay to all IPC packages to simulate a slow (remote) connection."; System.err.println(txt); } } public static void logRequest(String headerBody, String requestBody) { if (!logPackage) { return; } synchronized (lock) { printStream.println(); printTimeStamp(); printStream.print("REQUEST: "); noCharsLogged = 0; logRequest(headerBody); logRequest(" "); logRequest(requestBody); } } private static void logRequest(String s) { if (s == null) { return; } if (!logPackage) { return; } if (!logFullLine && noCharsLogged >= maxNoCharsLogged) { return; } if (logFullLine) { printStream.print(s); return; } if (noCharsLogged + s.length() >= maxNoCharsLogged) { s = s.substring(0, maxNoCharsLogged - noCharsLogged); } printStream.print(s); noCharsLogged += s.length(); if (noCharsLogged >= maxNoCharsLogged) { printStream.print("..."); noCharsLogged += 3; } } public static void logResponse(byte[] responseHeaderBytes, byte[] responseBody) { if (!logPackage) { return; } synchronized (lock) { printStream.println(); printTimeStamp(); printStream.print(".......: "); noCharsLogged = 0; logResponse(responseHeaderBytes); if (responseBody != null) { logResponse(' '); logResponse(responseBody); } } } private static void logResponse(char c) { if (!logPackage) { return; } if (!logFullLine && noCharsLogged >= maxNoCharsLogged) { return; } printStream.print(c); noCharsLogged++; if (logFullLine) { return; } if (noCharsLogged >= maxNoCharsLogged) { printStream.print("..."); noCharsLogged += 3; } } private static void logResponse(byte[] bytes) { if (!logPackage) { return; } for (byte b : bytes) { logResponse((char) b); } } public static void logTrace(String trace) { if (!logTrace) { return; } printTimeStamp(); printStream.println(trace); } private static void printTimeStamp() { if (logTimeStamp) { printStream.print(timeStamp()); } } private static String timeStamp() { long ts = new Date().getTime() - now; return new Formatter().format("%7d: ", ts).toString(); } public static long getTimeStamp() { long ts = new Date().getTime() - now; return ts; } public static int getIpcDelay() { return ipcDelay; } public static void setIpcDelay(int id) { ipcDelay = id; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ipc/IPCResult.java�������������������������������������������������0000644�0001750�0001750�00000032563�14517772113�017176� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.ipc; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.progress.CancelContext; import org.gprofng.mpmt.progress.Cancellable; import org.gprofng.mpmt.util.gui.AnUtility; import java.text.DecimalFormat; import java.text.DecimalFormatSymbols; import java.text.ParseException; import java.util.Locale; /** */ public class IPCResult implements Cancellable { public enum CC { DEFAULT(0), SUCCESS(1), FAILURE(2), CANCELED(3); private final int value; private CC(int value) { this.value = value; } private int value() { return value; } protected static CC fromValue(int val) { for (CC rt : CC.values()) { if (rt.value() == val) { return rt; } } return null; } }; private IPCHandle ipcHandle; private int requestID; private IPCContext ipcContext; private IPCResponse ipcResponse; private boolean resultIsReady = false; private int curChar; private int iVal; private boolean bVal; private long lVal; private String sVal; private Object aVal; private DecimalFormat format; protected IPCResult(IPCHandle ipcHandle, int requestID, IPCContext ipcContext) { this.ipcHandle = ipcHandle; this.requestID = requestID; this.ipcContext = ipcContext; curChar = 0; format = new DecimalFormat(); format.setDecimalFormatSymbols( new DecimalFormatSymbols(Locale.US)); // Use non-localized double values } protected IPCHandle getIPCHandle() { return ipcHandle; } protected int getRequestID() { return requestID; } // Public begin public CC getCC() { waitForResult(); return ipcResponse.getHeader().getResponseStatus(); } public int getInt() { waitForResult(); readResult(); return iVal; } public String getString() { waitForResult(); readResult(); return sVal; } public long getLong() { waitForResult(); readResult(); return lVal; } public boolean getBoolean() { waitForResult(); readResult(); return bVal; } public Object getObject() { waitForResult(); readResult(); return aVal; } public Object[] getObjects() { return (Object[]) getObject(); } public String[] getStrings() { return (String[]) getObject(); } public int[] getInts() { return (int[]) getObject(); } public long[] getLongs() { return (long[]) getObject(); } public boolean[] getBooleans() { return (boolean[]) getObject(); } public void getVoid() { waitForResult(); } public int getVersion() { waitForResult(); if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.HANDHAKE) { return ipcResponse.getHeader().getnBytes(); } return -1; } /** Send a cancel request for this particular request */ public boolean cancel() { IPCHandle cancelIPCHandle = IPCHandle.newCancelIPCHandle(ipcContext, requestID); IPCResult ipcResult = cancelIPCHandle.sendRequest(); // no body if (ipcResult.getCC() == IPCResult.CC.SUCCESS) { IPCLogger.logTrace( ipcResult.getRequestID() + " IPCResult Cancel SUCCESS channel " + ipcContext.getChannel()); return true; // it is being cancelled } else { IPCLogger.logTrace( ipcResult.getRequestID() + " IPCResult Cancel FAILURE channel " + ipcContext.getChannel()); System.err.println( "Cancel FAILURE channel " + ipcContext.getChannel() + " (may not work yet)"); return false; // not being cancelled (not cancellable?) } } /** rewinds input buffer so it can be read again with getXxxx() */ public void rewindInputBuffer() { curChar = 0; } // Public end protected void started(int requestId) { IPCLogger.logTrace(requestId + " IPCResult started "); if (ipcContext.isSystemProgressBar() && ipcContext.isCancellable()) { CancelContext cancelContext = new CancelContext(ipcContext.getTaskName(), this); AnWindow.getInstance().getSystemProgressPanel().setProgressCancelContext(cancelContext); } } protected void progress(IPCResponse ipcResponse) { IPCLogger.logTrace(ipcResponse.getHeader().getRequestID() + " IPCResult progress "); if (ipcContext.isSystemProgressBar()) { IPCProtocol.CurChar curChar = new IPCProtocol.CurChar(); int progress = IPCProtocol.decodeByte(ipcResponse.getBody(), curChar); int percentage = IPCProtocol.decodeIVal(ipcResponse.getBody(), curChar); String what = IPCProtocol.decodeSVal(ipcResponse.getBody(), curChar); AnWindow.getInstance().getSystemProgressPanel().setProgress(percentage, what); } } protected void finished(int requestId, IPCResponse ipcResponse) { IPCLogger.logTrace(requestId + " IPCResult finished "); this.ipcResponse = ipcResponse; resultIsReady(); Analyzer.getInstance().IPC_session.getIPCReader().removeFromRequestPool(requestId); } protected void fireResponse(IPCResponse ipcResponse) { if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.ACK) { started(ipcResponse.getHeader().getRequestID()); } else if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.COMPLETE) { finished(ipcResponse.getHeader().getRequestID(), ipcResponse); } else if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.HANDHAKE) { finished(ipcResponse.getHeader().getRequestID(), ipcResponse); } else if (ipcResponse.getHeader().getResponseType() == IPCResponseHeader.ResponseType.PROGRESS) { progress(ipcResponse); } else { assert false; } } protected void waitForResult() { waitOrNotify(true); if (ipcResponse == null) { System.out.println("" + requestID + " ipcResponse1 " + ipcResponse); } } protected void resultIsReady() { waitOrNotify(false); } protected synchronized void waitOrNotify(boolean readData) { if (readData) { IPCLogger.logTrace(requestID + " IPCResult waitOrNotify 1 " + resultIsReady); if (!resultIsReady) { while (!resultIsReady) { try { IPCLogger.logTrace(requestID + " IPCResult waitOrNotify 2 " + resultIsReady); this.wait(); IPCLogger.logTrace(requestID + " IPCResult waitOrNotify 3 " + resultIsReady); } catch (InterruptedException ie) { IPCLogger.logTrace(requestID + " IPCResult waitOrNotify 4 " + resultIsReady); } } } else { IPCLogger.logTrace(requestID + " IPCResult waitOrNotify 5 " + resultIsReady); } } else { resultIsReady = true; IPCLogger.logTrace(requestID + " IPCResult waitOrNotify 6 " + resultIsReady); this.notify(); } } private int nextChar() { if (curChar < ipcResponse.getBody().length) { return ipcResponse.getBody()[curChar++]; } else { System.err.println("IPCResult " + curChar + " " + ipcResponse.getBody().length); assert false; return 'x'; } } private int readByte() { int val = 0; for (int i = 0; i < 2; i++) { final int c = nextChar(); switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': val = val * 16 + c - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': val = val * 16 + c - 'a' + 10; break; } } return val; } private int readIVal() { int val = readByte(); for (int i = 0; i < 3; i++) { val = val * 256 + readByte(); } return val; } private long readLVal() { long val = readByte(); for (int i = 0; i < 7; i++) { val = val * 256 + readByte(); } return val; } private boolean readBVal() { final int val = readByte(); return val != 0; } private char readCVal() { final int val = readByte(); return (char) val; } /** * Reads double value This method is synchronized because "format" is not thread safe * * @return double value */ private synchronized double readDVal() { final String s = readSVal(); final double DValue; try { DValue = format.parse(s).doubleValue(); // format is not thread safe } catch (ParseException ex) { ex.printStackTrace(); return 0.0; } return DValue; } private String readSVal() { final int len = readIVal(); if (len == -1) { return null; } final String s = new String(ipcResponse.getBody(), curChar, len); curChar = curChar + len; return s; } private Object readAVal() { boolean twoD = false; int type = readByte(); if (type == IPCProtocol.L_ARRAY) { twoD = true; type = readByte(); } final int len = readIVal(); if (len == -1) { return null; } switch (type) { case IPCProtocol.L_INTEGER: if (twoD) { final int[][] array = new int[len][]; for (int i = 0; i < len; i++) { array[i] = (int[]) readAVal(); } return array; } else { final int[] array = new int[len]; for (int i = 0; i < len; i++) { array[i] = readIVal(); } return array; } // break; case IPCProtocol.L_LONG: if (twoD) { final long[][] array = new long[len][]; for (int i = 0; i < len; i++) { array[i] = (long[]) readAVal(); } return array; } else { final long[] array = new long[len]; for (int i = 0; i < len; i++) { array[i] = readLVal(); } return array; } // break; case IPCProtocol.L_DOUBLE: if (twoD) { final double[][] array = new double[len][]; for (int i = 0; i < len; i++) { array[i] = (double[]) readAVal(); } return array; } else { final double[] array = new double[len]; for (int i = 0; i < len; i++) { array[i] = readDVal(); } return array; } // break; case IPCProtocol.L_BOOLEAN: if (twoD) { final boolean[][] array = new boolean[len][]; for (int i = 0; i < len; i++) { array[i] = (boolean[]) readAVal(); } return array; } else { final boolean[] array = new boolean[len]; for (int i = 0; i < len; i++) { array[i] = readBVal(); } return array; } // break; case IPCProtocol.L_CHAR: if (twoD) { final char[][] array = new char[len][]; for (int i = 0; i < len; i++) { array[i] = (char[]) readAVal(); } return array; } else { final char[] array = new char[len]; for (int i = 0; i < len; i++) { array[i] = readCVal(); } return array; } // break; case IPCProtocol.L_STRING: if (twoD) { final String[][] array = new String[len][]; for (int i = 0; i < len; i++) { array[i] = (String[]) readAVal(); } return array; } else { final String[] array = new String[len]; for (int i = 0; i < len; i++) { array[i] = readSVal(); } return array; } // break; case IPCProtocol.L_OBJECT: if (twoD) { final Object[][] array = new Object[len][]; for (int i = 0; i < len; i++) { array[i] = (Object[]) readAVal(); } return array; } else { final Object[] array = new Object[len]; for (int i = 0; i < len; i++) { array[i] = readAVal(); } return array; } // break; } return null; } private void readResult() { if (AnUtility.checkIPCOnWrongThread()) { AnUtility.checkIfOnAWTThread(false); } for (; ; ) { // AnMemoryManager.getInstance().checkMemoryUsage(); final int tVal = readByte(); switch (tVal) { case IPCProtocol.L_INTEGER: iVal = readIVal(); break; case IPCProtocol.L_LONG: lVal = readLVal(); break; case IPCProtocol.L_BOOLEAN: bVal = readBVal(); break; case IPCProtocol.L_STRING: sVal = readSVal(); break; case IPCProtocol.L_ARRAY: aVal = readAVal(); break; default: System.err.println("Unknown code: " + tVal); break; } return; } } } ���������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/CalledByCallsDisassemblyView.java����������������������������������0000644�0001750�0001750�00000002004�14517772113�022265� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; public final class CalledByCallsDisassemblyView extends CalledByCallsDisp { public CalledByCallsDisassemblyView() { super( AnWindow.getInstance(), AnDisplay.DSP_Callers, AnVariable.HELP_TabsDisassembly, AnDisplay.DSP_Disassembly); setAccessibility(AnLocale.getString("Called By Calls")); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnAction.java������������������������������������������������������0000644�0001750�0001750�00000010464�14517772113�016301� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Insets; import java.awt.event.ActionEvent; import javax.accessibility.AccessibleContext; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.KeyStroke; public class AnAction extends AbstractAction { private String text; private Icon icon; private String tooltipText; private String accDescription; private Action action; private KeyStroke keyStroke = null; private Character mnemonic = null; private JMenuItem menuItem = null; public AnAction(String text, Action action) { this(text, null, null, null, action); } public AnAction(String text, Icon icon, Action action) { this(text, icon, null, null, action); } public AnAction( String text, Icon icon, String tooltipText, String accDescription, Action action) { super(text, icon); this.text = text; this.icon = icon; this.tooltipText = tooltipText; if (accDescription != null) { this.accDescription = accDescription; } else { this.accDescription = text; } this.action = action; } public JButton createActionButton() { JButton actionButton = new AnIconButton(icon); actionButton.setMargin(new Insets(4, 5, 4, 5)); actionButton.setHideActionText(true); actionButton.setAction(this); actionButton.setActionCommand((String) getValue(Action.NAME)); actionButton.setToolTipText(getTooltipText()); AccessibleContext context = actionButton.getAccessibleContext(); context.setAccessibleName(text); context.setAccessibleDescription(accDescription); return actionButton; } public JMenuItem getMenuItem() { return getMenuItem(true); } public JMenuItem getMenuItem(boolean addAccelerator) { if (menuItem == null) { menuItem = new JMenuItem(); menuItem.setText(text); menuItem.setAction(this); if (keyStroke != null) { if (addAccelerator) { menuItem.setAccelerator(keyStroke); } else { menuItem.setText(text + AnUtility.keyStrokeToStringFormatted(keyStroke)); } } if (mnemonic != null) { menuItem.setMnemonic(mnemonic); } } return menuItem; } public void setKeyboardShortCut(KeyStroke keyStroke) { setKeyboardShortCut(AnWindow.getInstance().getMainPanel(), keyStroke.toString(), keyStroke); } public void setKeyboardShortCut(JPanel panel, String id, KeyStroke keyStroke) { this.keyStroke = keyStroke; if (panel != null) { panel.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(keyStroke, id); panel .getActionMap() .put( id, new AbstractAction() { @Override public void actionPerformed(ActionEvent ev) { AnAction.this.actionPerformed(ev); } }); } } public void setMnemonic(char m) { mnemonic = m; } @Override public void actionPerformed(final ActionEvent event) { action.actionPerformed(event); } public String getTooltipText() { String tt = tooltipText; if (tt == null) { tt = text; } if (tt != null && keyStroke != null) { tt = tt + AnUtility.keyStrokeToStringFormatted(keyStroke); } return tt; } public String getText() { return text; } public String getTextNoDots() { String textnd = text; if (textnd != null && textnd.endsWith("...")) { textnd = textnd.substring(0, textnd.length() - 3); } return textnd; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/MiniFuncListDisp.java����������������������������������������������0000644�0001750�0001750�00000016673�14517772113�020001� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.overview.OverviewPanel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import javax.swing.JLabel; import javax.swing.JScrollPane; public class MiniFuncListDisp extends FuncListDisp { private int[] src_type; public MiniFuncListDisp(final AnWindow window, final int type, final String help_id) { super(window, type, 0, help_id); } // Initialize GUI components @Override protected void initComponents() { // System.err.println("XXX In FLD initComponents()"); setLayout(new BorderLayout()); String acName = null; String acDesc = null; JLabel acLabel = null; switch (type) { case AnDisplay.DSP_Functions: acName = AnLocale.getString("Functions"); acDesc = AnLocale.getString("Show function list"); break; } if (acName != null) { acLabel = new JLabel(acName, JLabel.RIGHT); } table = new AnTable( DSP_MiniFunctions, true, true, false, false, true, true, false, acName, acDesc, acLabel); // HERE table.setParent(this); if (acLabel != null) { acLabel.setVisible(false); acLabel.setDisplayedMnemonic(acName.charAt(0)); table.add(acLabel); } table.addAnListener(new TableHandler()); table.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); add(table, BorderLayout.CENTER); } // static int count = 0; @Override public void doCompute() { // System.out.println("MiniFuncListDisp - doCompute " + count++ + selected + " " + // computed + " " + type); final long sel_obj; int new_ind; final int sort_ind; final Object[] raw_data; final String errstr, pwarnstr; final MetricLabel[] label; AnUtility.checkIfOnAWTThread(false); // Not selected if (!selected) { return; } if (inCompute) { // NM TEMPORARY should be synchronized return; } else { inCompute = true; } // System.err.println("XXX In FLD doCompute - 1 ()"); // window.setBusyCursor(true); // System.err.println("XXX In FLD doCompute - 3 ()"); sel_obj = window.getSelectedObject().getSelObj(type, subtype); if (can_sort) { // Function/LINE/PC sel_func = sel_obj; } else { // Annotated src/dis sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) // Required to initialize Functions list } // Special code for Index tabs and for OpenMP tabs int typeForPresentation = type; String typeStr = "INDEXOBJ"; String subtypeStr = "" + subtype; String modeStr = "ALL"; String mlistStr = "MET_INDX"; if (isOmpInxObj()) { mlistStr = "MET_NORMAL"; typeForPresentation = AnDisplay.DSP_Functions; } if (!computed) { // need re-compute // System.err.println("XXX In FLD doCompute - 4 ()"); reset(); // window.setBusyCursor(true); // new_ind = setFuncData(sel_func, type, subtype); window .getFunctionsView() .computeIfNeeded(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) errstr = window.getMsg(AnUtility.ERROR_MSG); // Update table if (errstr == null) { // System.err.println("XXX In FLD doCompute - 5 ()"); table.setViewport(); Object[][] table_data; raw_data = getFuncListMini(type, subtype); if ((raw_data == null) || (raw_data.length < 1)) { String txt = "IPC ERROR (?) in MiniFuncListDisp: raw_data is null or empty"; AnLog.log(txt); inCompute = false; return; // No data } final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(typeForPresentation); table_data = localProcessData( mlist, raw_data); // first index is for column, second index is for rows // System.err.println("XXX after processData table_data.length = " + table_data.length + "; // row_length " + table_data[0].length ); src_type = (int[]) raw_data[raw_data.length - 1]; // AnTable.AT_SRC, DIS, QUOTE, etc. String[] hdrContent = getNames(typeForPresentation, 0); // name column table header contents (?) label = getSettings() .getMetricsSetting() .getLabel(table_data, null, typeForPresentation, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(getMetricMType()); sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(typeForPresentation); new_ind = 0; table.setData(label, table_data, hdrContent, src_type, new_ind, name_col, sort_ind); table.repaint(); } else { // System.err.println("XXX In FLD doCompute - 6 ()"); window.getExperimentsView().appendLog(AnLocale.getString("Error: ") + errstr); table.showMessage(errstr); } OverviewPanel.getInstance().previewChanged(); } // table.requestFocus(); computed = true; // pstatstr = window.getMsg(AnUtility.PSTAT_MSG); pwarnstr = window.getMsg(AnUtility.PWARN_MSG); // if (pstatstr != null) { // window.appendLog(pstatstr); // } if (pwarnstr != null) { window.showProcessorWarning(pwarnstr); } inCompute = false; } // Listener for updating table private final class TableHandler implements AnListener { @Override public void valueChanged(final AnEvent event) { final int from; final int to; int stype = 0; final boolean can_nav; switch (event.getType()) { case AnEvent.EVT_SELECT: // Selecting break; case AnEvent.EVT_SORT: // Sorting break; case AnEvent.EVT_COPY_ALL: // Copy all lines copyAll(); break; case AnEvent.EVT_COPY_SEL: // Copy selected lines copySelected(); break; case AnEvent.EVT_SWITCH: // Column switching if (table != null) { table.columnsSaved = false; } from = event.getValue(); to = ((Integer) event.getAux()).intValue(); getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, getMetricMType()); break; } } } private Object[] getFuncListMini(final int type, final int subtype) { synchronized (IPC.lock) { window.IPC().send("getFuncListMini"); window.IPC().send(0); window.IPC().send(type); window.IPC().send(subtype); return (Object[]) window.IPC().recvObject(); } } } ���������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/Analyzer.java������������������������������������������������������0000644�0001750�0001750�00000240255�14517772113�016375� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.collect.Collector; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCLogger; import org.gprofng.mpmt.ipc.IPCProtocol; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.metrics.MetricColors; import org.gprofng.mpmt.metrics.MetricColors.MetricColor; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.persistence.UserPref.ConnectionProperties; import org.gprofng.mpmt.remote.Authentication; import org.gprofng.mpmt.remote.ConnectionDialog; import org.gprofng.mpmt.remote.ConnectionManager; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.nio.file.Files; import java.nio.file.Paths; import java.util.Date; import java.util.List; import java.util.Locale; import javax.swing.JOptionPane; public final class Analyzer { // Runtime environment public static final String PERFORMANCE_ANALYZER_RELEASE_NAME = "gprofng GUI"; public static final String THIS_VERSION = "12.6"; public static final String jvm_ver = System.getProperty("java.version", "unknown"); public static final String jvm_home = System.getProperty("java.home", "unknown"); public static final String home_dir = UserPref.getHomeDirectory(); // System.getProperty("user.home", "."); private String workingDirectory = System.getProperty("user.dir", "."); public String os_name = null; public String er_print = null; public String localHost = null; public String remoteConnection = null; public String remoteHost = null; public String remoteShell = "/usr/bin/ssh"; public static ClassLoader cls_loader = null; public boolean normalSelection = false; // Right click changes selection public boolean IPC_started = false; public boolean connectingToRemoteHost = false; // true during the connecting process // public int kernelProfilingEnabled = 0; // 0 - not initialized, 1 - "er_kernel" is available, // 2 - not available public Boolean kernelProfilingEnabled = null; public boolean old_IPC_status = false; public int cur_id = 0; public static boolean compareMode = false; public static String fdversion, fdhome, licpath, licsts; public IPC IPC_session; public IPC old_IPC_session = null; // the variables to control the availability of certain menus and toolbars // these are default values for all IPC sessions public static boolean m_is_open_exp_avail_default = true; public static boolean m_is_aggregate_exp_avail_default = true; public static boolean m_is_compare_exp_avail_default = true; public static boolean m_is_print_dsp_avail_default = true; public static boolean m_is_new_win_avail_default = true; public static boolean m_is_close_act_avail_default = true; public static boolean m_is_exit_act_avail_default = true; public static boolean m_is_sel_present_avail_default = true; public static boolean m_is_sel_filter_avail_default = true; public static boolean m_is_show_hide_obj_avail_default = true; public static boolean m_is_tbar_color_avail_default = true; public static boolean m_is_find_avail_default = true; public static boolean m_is_find_up_avail_default = true; public static boolean m_is_find_down_avail_default = true; public static boolean m_is_edit_filter_avail_default = true; public static boolean m_is_collect_exp_avail_default = true; public static boolean m_exit_as_last_win_closed = true; public static boolean m_dispose_frame_as_win_closed = true; // these are values for the IPC session public boolean m_is_open_exp_avail_session = m_is_open_exp_avail_default; public boolean m_is_aggregate_exp_avail_session = m_is_aggregate_exp_avail_default; public boolean m_is_compare_exp_avail_session = m_is_compare_exp_avail_default; public boolean m_is_print_dsp_avail_session = m_is_print_dsp_avail_default; public boolean m_is_new_win_avail_session = m_is_new_win_avail_default; public boolean m_is_close_act_avail_session = m_is_close_act_avail_default; public boolean m_is_exit_act_avail_session = m_is_exit_act_avail_default; public boolean m_is_sel_present_avail_session = m_is_sel_present_avail_default; public boolean m_is_sel_filter_avail_session = m_is_sel_filter_avail_default; public boolean m_is_show_hide_obj_avail_session = m_is_show_hide_obj_avail_default; public boolean m_is_tbar_color_avail_session = m_is_tbar_color_avail_default; public boolean m_is_find_avail_session = m_is_find_avail_default; public boolean m_is_find_up_avail_session = m_is_find_up_avail_default; public boolean m_is_find_down_avail_session = m_is_find_down_avail_default; public boolean m_is_edit_filter_avail_session = m_is_edit_filter_avail_default; public boolean m_is_collect_exp_avail_session = m_is_collect_exp_avail_default; private static Analyzer instance; private static String[] arguments = null; private AnFrame anFrame = null; private ConnectionManager connectionManager = null; private String emptyString = ""; // Known connection problems private String known_problem_0 = AnLocale.getString("Empty host name is not valid."); private String known_problem_1 = AnLocale.getString("Authentication failed. User name or password did not match"); private String known_problem_2 = AnLocale.getString("Authentication failed. Password is required."); private String known_problem_3 = AnLocale.getString("Connection failed. Timeout."); private String known_problem_4 = AnLocale.getString("Authentication failed. Password was not requested."); private String known_problem_5 = AnLocale.getString("Connection failed. Host is unreachable."); private String known_problem_6 = AnLocale.getString("Connection failed. Installation path is not correct."); private String known_problem_7 = AnLocale.getString("Connection failed. Unrecognized reply from remote host."); private String known_problem_8 = AnLocale.getString("Connection failed. Canceled by user."); private String known_problem_9 = AnLocale.getString("Connection failed. Incompatible versions."); public String known_problem_10 = AnLocale.getString("Stream Closed"); // Explanations for known connection problems private String explanation_0 = AnLocale.getString("Empty host name is not valid. Please specified remote host."); private String explanation_3_1 = AnLocale.getString( "gprofng GUI did not get a reply from the remote host. Please check that the" + " specified remote host exists, and the specified Installation Path exists on the" + " remote host."); private String explanation_3_2 = AnLocale.getString( "gprofng GUI did not get a reply from the remote host. Please check that the" + " specified Installation Path exists on the remote host."); private String explanation_9 = AnLocale.getString( "gprofng GUI version does not match version on the remote host as specified by" + " the Installation Path."); // Connection protocol version private static String IPC_PROTOCOL = IPCProtocol.IPC_PROTOCOL_STR; private final String ipc_protocol = IPC_PROTOCOL; private static final String JSSH_jar = "/share/gprofng-gui/JSSH3.jar"; private static final String DisplayAppName = "gp-display-text"; private static final String CollectAppName = "gp-collect-app"; private static final String KernelAppName = "gp-collect-kernel"; public Analyzer() { instance = this; IPC_session = new IPC(this); } public static Analyzer getInstance() { return instance; } public void initMetricColors() { UserPref userPref = UserPref.getInstance(); if (userPref.getCustomMetricColors() != null) { for (MetricColor metricColor : userPref.getCustomMetricColors()) { MetricColors.setCustomMetricColor(metricColor.getMetricName(), metricColor.getColor()); } } } public static boolean initPath(final boolean in_netbeans) { // Analyzer.in_netbeans = in_netbeans; // Done initialize if (cls_loader != null) { return in_netbeans; // Analyzer.in_netbeans; } // Find installed directory fdhome & nbhome cls_loader = Analyzer.class.getClassLoader(); fdhome = AnUtility.findResourceHome(cls_loader, "org/gprofng/mpmt/Analyzer.class"); // Method AnUtility.findResourceHome()returns wrong path on Windows // System.err.println("AnUtility.findResourceHome returned fdhome = " + fdhome); if (fdhome.charAt(2) == ':') { if (fdhome.charAt(0) == '/') { String os_name = System.getProperty("os.name"); if (os_name.contains("Windows")) { fdhome = fdhome.substring(1); // System.err.println("Corrected for Windows fdhome = " + fdhome); } } } licpath = System.getProperty("analyzer.licpath", fdhome + "/lib/serial.dat"); return in_netbeans; // Analyzer.in_netbeans; } /** * @return the workingDirectory */ public String getWorkingDirectory() { // System.out.println("getWorkingDirectory: " + workingDirectory); return workingDirectory; } /** * @param workingDirectory the workingDirectory to set */ public void setWorkingDirectory(String workingDirectory) { // System.out.println("setWorkingDirectory: " + workingDirectory); this.workingDirectory = workingDirectory; setCurrentDirectory(workingDirectory); // IPC call AnWindow.getInstance().updateWorkingDirectoryStatus(); } /** * @param workingDirectory the workingDirectory to set */ public void initWorkingDirectory() { String wd = getCurrentDirectory(); // IPC call! // System.out.println("initWorkingDirectory: " + wd); if (wd != null) { this.workingDirectory = wd; } } /** * @return returns name of remote host in case of a remote connection otherwise it returns * "localhost" */ public String getHost() { String host = "localhost"; if (remoteConnection != null) { host = remoteHost; } return host; } /** * @return returns name of local host */ public String getLocalHost() { return localHost; } /** * @return returns name of remote host in case of a remote connection otherwise it returns null */ public String getRemoteHost() { String remoteHostName = null; if (isRemote()) { remoteHostName = remoteHost; } return remoteHostName; } /** * @return returns whether it is connected remotely */ public boolean isRemote() { return remoteConnection != null; } /** * @return returns whether it is connected locally or remotely */ public boolean isConnected() { return (IPC_started); } /** * @return returns whether kernel profiling is enabled */ public boolean isKernelProfilingEnabled() { if (kernelProfilingEnabled == null) { if (IPC_started) { if (er_print != null) { kernelProfilingEnabled = false; // not enabled String er_kernel = er_print.replace("/gp-display-text", "/er_kernel"); AnFile ek = new AnFile(er_kernel); if (ek.exists()) { kernelProfilingEnabled = true; // enabled } } } } return kernelProfilingEnabled; } /** Start Connection Manager */ public void startConnectionManager() { if (null == connectionManager) { connectionManager = new ConnectionManager(); if (connectionManager != null) { connectionManager.start(); } } if (connectionManager != null) { connectionManager.startChecking(); } } /** Stop Connection Manager */ public void stopConnectionManager() { if (connectionManager != null) { connectionManager.stopChecking(); } } private String get_exe_name(String nm) { if (nm != null && !nm.equals(emptyString) && Files.exists(Paths.get(nm))) { return nm; } return null; } public void startIPC() throws Exception { if (IPC_started) { return; } fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CHANGING); // $SP_ANALYZER_CONFIG_MODE may be set to "R" to tell the spawned // gp-display-text to configure for race detection // It will spawn gp-display-text -RIPC, rather than -IPC in that case // // $SP_COLLECTOR_IPC_DEBUG may be set to a string to use to prepend // to the gp-display-text -[R]IPC command -- examples: // "LD_PRELOAD mem.so; " // "collect -Z -O /dev/null" -- to do the same thing // "collect -p on -H on -O /dev/null" to collect an experiments // The -O command is necessary, since any IO from // collect to stdout before the gp-display-text target is // spawned will confuse the GUI and gp-display-text // communication channel. // "dbx ..." can not be prepended, because there's no way to convince // dbx to not write anything to stdout, and anything written // will confuse the gp-display-text process String str = null; // AnUtility.getenv("SP_COLLECTOR_IPC_DEBUG"); if (str != null && !str.equals(emptyString)) { IPCLogger.logTrace("\n" + "analyzer: SP_COLLECTOR_IPC_DEBUG `" + str + "'"); } else { str = emptyString; } String cmode = AnUtility.getenv("SP_ANALYZER_CONFIG_MODE"); if (cmode == null) { cmode = emptyString; } else if (cmode.equals(emptyString)) { // OK, but why was this set? } else if (!cmode.equals("R")) { System.err.println("analyzer: SP_ANALYZER_CONFIG_MODE `" + cmode + "' unrecognized"); System.exit(1); } // SP_ANALYZER_ER_PRINT may be set to use the other gp-display-text. // Also SP_ANALYZER_ER_PRINT can be used instead SP_COLLECTOR_IPC_DEBUG // For example:: // "ssh host /bin/gp-display-text" - to use // the other gp-display-text on the other machine. // "LD_PRELOAD mem.so /opt/SUNWSpro/bin/gp-display-text" // "collect -H on -O /dev/null /bin/gp-display-text" - // to collect an experiments. // The -O command is necessary, since any IO from // collect to stdout before the gp-display-text target is // spawned will confuse the GUI and gp-display-text // communication channel. if (er_print == null || er_print.equals(emptyString)) { er_print = AnUtility.getenv("SP_ANALYZER_ER_PRINT"); } if (er_print == null || er_print.equals(emptyString)) { er_print = null; if (UserPref.gprofngdir != null) { er_print = get_exe_name(UserPref.gprofngdir + "/" + DisplayAppName); } if (er_print == null && fdhome != null) { er_print = get_exe_name(fdhome + "/bin/" + DisplayAppName); } if (er_print == null) { er_print = "" + DisplayAppName; } } else { IPCLogger.logTrace("\n" + "analyzer: SP_ANALYZER_ER_PRINT='" + er_print + "'"); if (remoteConnection != null) { if (str.equals(emptyString)) { str = remoteConnection; } else { str = remoteConnection + " " + str; } } } System.err.println("fdhome: " + (fdhome == null ? "" : fdhome)); System.err.println("gp-display-text: " + er_print); AnLog.log("analyzer: gp-display-text=" + er_print + "\n"); // Check the OS - only Solaris and Linux are supported if (remoteHost == null) { if (null == os_name) { throw new Exception("OS is not supported yet."); } if ((!os_name.equals("SunOS")) && (!os_name.equals("Linux"))) { throw new Exception("OS " + os_name + " is not supported yet."); } } String er_printCmd; if (str.equals(emptyString)) { er_printCmd = er_print + " -" + cmode + "IPC"; } else { er_printCmd = str + " " + er_print + " -" + cmode + "IPC"; } // IPC_session.init(er_printCmd + " -" + cmode + "IPC"); String tracelevel = null; // AnUtility.getenv("SP_ER_PRINT_TRACE_LEVEL"); if (tracelevel != null) { String er_printCmd_extn = " -E SP_ER_PRINT_TRACE_LEVEL=" + tracelevel; er_printCmd = er_printCmd + er_printCmd_extn; } stopConnectionManager(); IPC_session.init(er_printCmd, true); setIPCStarted(true); startConnectionManager(); fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CHANGED); } /** * Creates new IPC connection Connection_thread * * @param cc * @param host * @param name * @param p * @param path */ public String createNewIPC( ConnectionDialog cc, String host, String name, char[] p, String path, ConnectionProperties connectionProperties) { AnUtility.checkIPCOnWrongThread(false); kernelProfilingEnabled = null; fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CHANGING); stopConnectionManager(); // Destroy old IPC session if (null != old_IPC_session) { IPC new_IPC_session = IPC_session; IPC_session = old_IPC_session; setIPCStarted(old_IPC_status); // win.QUIT(); old_IPC_session.destroyIPCProc(); IPC_session = new_IPC_session; } // Save current IPC session old_IPC_session = IPC_session; old_IPC_status = IPC_started; IPC newIPC = new IPC(this); String str_gp_display_text = "gp-display-text"; String path_to_er_print = str_gp_display_text; String l_fdhome = emptyString; if (null != path) { l_fdhome = path.trim(); if (l_fdhome.length() > 0) { if (!l_fdhome.equals(path_to_er_print)) { if (l_fdhome.endsWith("/" + str_gp_display_text)) { path_to_er_print = l_fdhome; } else { if (l_fdhome.endsWith("/bin") || l_fdhome.endsWith("/bin/")) { path_to_er_print = l_fdhome + "/" + str_gp_display_text; } else { path_to_er_print = l_fdhome + "/bin/" + str_gp_display_text; } } } } System.out.println("path: " + path); } System.out.println("l_fdhome: " + l_fdhome); System.out.println("str_gp_display_text: " + str_gp_display_text); String str_collect = "gp-collect-app"; int i = path_to_er_print.lastIndexOf(str_gp_display_text); String path_to_collect = path_to_er_print.substring(0, i) + str_collect; String er_printCmd = path_to_er_print; String rc = null; String emsg = null; // Authentication String ra = emptyString; // default - password if (null != connectionProperties) { ra = Authentication.toKeyString(connectionProperties.getAuthentications()); if (null == ra) { ra = emptyString; } else { ra = " -a " + ra; } } String rh = host; if (rh != null) { rh = rh.trim(); // remove spaces } // Empty host name is not accepted if ((rh == null) || (rh.equals(emptyString))) { return (known_problem_0); } if ((!rh.equals(emptyString)) && (!rh.equals("localhost"))) { // Add user name if it is not empty if ((name != null)) { name = name.trim(); // remove spaces if (!name.equals(emptyString)) { rh = name + "@" + rh; } } String rs = AnUtility.getenv("SP_ANALYZER_REMOTE_SHELL"); if (rs != null) { // Special way to login rc = remoteShell + " " + rh; } else { rc = remoteShell + ra + " " + rh; } er_printCmd = rc + " " + path_to_er_print; } String cmode = AnUtility.getenv("SP_ANALYZER_CONFIG_MODE"); if ((cmode != null) && (cmode.equals("R"))) { er_printCmd = er_printCmd + " -RIPC"; } else { er_printCmd = er_printCmd + " -IPC"; } String tracelevel = null; // AnUtility.getenv("SP_ER_PRINT_TRACE_LEVEL"); if (tracelevel != null) { String er_printCmd_extn = " -E SP_ER_PRINT_TRACE_LEVEL=" + tracelevel; er_printCmd = er_printCmd + er_printCmd_extn; } if (ipc_protocol != null) { String er_printCmd_extn = " -E SP_IPC_PROTOCOL=" + ipc_protocol; er_printCmd = er_printCmd + er_printCmd_extn; } // Initialize new IPC connection - start gp-display-text try { newIPC.init(er_printCmd, false); sendP(newIPC, p, cc); er_print = path_to_er_print; } catch (Exception e) { newIPC.destroyIPCProc(); fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); return (e.getMessage()); } newIPC.getIPCReader().runThread(); // TEMPORARY FOR DEBUG AnWindow win = AnWindow.getInstance(); if (IPC_started) { // see newinit() // AnFrame if fully initialized try { IPC_session = newIPC; // Version Handshake int res = versionHandshake(); if (res != 0) { fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); return AnLocale.getString("Connection failed: versions do not match"); } IPC_initView(0, -1); if (cc.cancelRequest) { emsg = AnLocale.getString("Connection canceled"); } } catch (Exception e) { emsg = AnLocale.getString("Cannot establish connection with remote host ") + rh; } if (emsg != null) { // Could not establish new connection IPC_session = old_IPC_session; setIPCStarted(old_IPC_status); // win.QUIT(); newIPC.destroyIPCProc(); fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); return (emsg); } // Successfully connected! remoteHost = rh; remoteConnection = rc; // Clean everything that belongs to the old IPC session IPC_session = old_IPC_session; setIPCStarted(old_IPC_status); // Use new IPC session IPC_session = newIPC; // Version Handshake int res = versionHandshake(); if (res != 0) { fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); return AnLocale.getString("Connection failed: versions do not match"); } syncTime(); // Call initApplication String l_licpath = System.getProperty("analyzer.licpath", l_fdhome + "/lib/serial.dat"); String[] args = new String[1]; args[0] = er_print; String[] license_info = new String[2]; license_info[0] = "ERROR"; license_info[1] = "Unknown"; try { license_info = initApplication(false, l_fdhome, l_licpath, args); } catch (Exception e) { if (null == license_info[0]) { license_info[0] = "ERROR"; } } String l_licsts = license_info[0]; String l_fdversion = license_info[1]; if (l_licsts != null && l_licsts.equals("ERROR")) { // Problem getting license emsg = AnLocale.getString("License Path: ") + l_licpath + "\n" + AnLocale.getString("Error: ") + l_fdversion; // Restore old IPC_session IPC_session = old_IPC_session; setIPCStarted(old_IPC_status); newIPC.destroyIPCProc(); fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); return (emsg); } } else { // need AnFrame initialization if (old_IPC_status) { // can it be true? // Clean everything that belongs to the old IPC session IPC_session = old_IPC_session; setIPCStarted(old_IPC_status); } // Use new IPC session IPC_session = newIPC; IPC_started = true; // Version Handshake int res = versionHandshake(); if (res != 0) { return AnLocale.getString("Connection failed: versions do not match"); } // Call initApplication String l_licpath = System.getProperty("analyzer.licpath", l_fdhome + "/lib/serial.dat"); String[] args = new String[1]; args[0] = er_print; String[] license_info = new String[2]; license_info[0] = "ERROR"; license_info[1] = "Unknown"; try { license_info = initApplication(false, l_fdhome, l_licpath, args); } catch (Exception e) { if (null == license_info[0]) { license_info[0] = "ERROR"; } } String l_licsts = license_info[0]; String l_fdversion = license_info[1]; if (l_licsts != null && l_licsts.equals("ERROR")) { emsg = AnLocale.getString("License Path: ") + l_licpath + "\n" + AnLocale.getString("Error: ") + l_fdversion; // Restore old IPC_session IPC_session = old_IPC_session; setIPCStarted(old_IPC_status); // win.QUIT(); newIPC.destroyIPCProc(); fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); return (emsg); } try { // Successfully connected! remoteHost = rh; remoteConnection = rc; // Use new IPC session IPC_session = newIPC; setIPCStarted(true); try { initAnalyzerIPC(); } catch (Exception e) { fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); return AnLocale.getString("Initialization failed"); } win = AnWindow.getInstance(); if (cc.cancelRequest) { emsg = AnLocale.getString("Connection canceled"); } } catch (Exception e) { emsg = AnLocale.getString("Cannot establish connection with remote host ") + rh; } if (emsg != null) { // Could not establish new connection IPC_session = old_IPC_session; setIPCStarted(old_IPC_status); // win.QUIT(); newIPC.destroyIPCProc(); fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); return (emsg); } // Successfully connected! remoteHost = rh; remoteConnection = rc; } // Use new IPC session IPC_session = newIPC; setIPCStarted(true); startConnectionManager(); fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CHANGED); // Measure connection performance (DEBUG) measureConnectionPerformance(cc); // // Check if "er_kernel" is enabled // checkKernelProfilingEnabled(); // Update connection information updateConnectionInfo(host, name, p, path_to_collect); // Synchronize Locale with remote engine if (isRemote()) { synchronizeLocale(); } logInit(); // Create Collector GUI dialog using a background thread (optimization) Thread createCollectorDialog = new Thread( new Runnable() { // @Override @Override public void run() { AnWindow.getInstance().resetProfileDialogs(); // AnWindow.getInstance().getRemoteCollectDialog(); } }); createCollectorDialog.run(); AnUtility.checkIPCOnWrongThread(false); return null; } /** * Explain Connection Problem * * @param msg * @return explanation */ public String explainConnectionProblem(String msg, String un) { String explanation = msg; if (msg == null) { return explanation; } if (msg.equals(known_problem_0)) { explanation = explanation_0; } if (msg.equals(known_problem_3) || msg.equals(known_problem_10)) { if ((un == null) || (un.length() < 1)) { explanation = explanation_3_1; } else { explanation = explanation_3_2; } } if (msg.equals(known_problem_9)) { explanation = explanation_9; } return explanation; } private static int connectionID = 0; /** Send pass */ private void sendP(IPC ipc, char[] pass, ConnectionDialog cc) throws Exception { // This is a temporary code, just to prove the concept connectionID++; long ts = System.currentTimeMillis(); boolean skip_pass = false; boolean auth_failed = true; String pattern1 = "Password"; String pattern2 = " " + pattern1 + ":"; String pattern3 = pattern1 + " for "; String pattern4 = "ER_IPC: IPC_PROTOCOL_"; String pattern5 = "Fatal error: host not found: "; String pattern6 = ": not found"; String pattern7 = "Killed"; String pattern8 = "ER_IPC: " + ipc_protocol + "\n"; String pattern9 = "ER_IPC: IPC_PROTOCOL_UNKNOWN\n"; String pattern10 = ": No such file"; String status1 = AnLocale.getString("Looking for remote host..."); String status2 = AnLocale.getString("Verifying authentication..."); String status3 = AnLocale.getString("Connection established. Compatibility checking..."); String status4 = AnLocale.getString("Password is not requested (!?)"); String ask = emptyString; AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") started. Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(status1); if ((null != pass) && (pass.length > 0)) { // this hangs if jssh+er_print do not send anything int c = 190; // timeout 19 seconds // Don't read - another thread (IPCReader) is already reading it. while (c-- > 0) { Thread.sleep(100); ask = ipc.getIPCReader().getUnknownInput(); if (ask.contains(pattern2)) { break; } if (ask.contains(pattern3)) { break; } if (ask.contains(pattern8)) { // Connection established skip_pass = true; cc.updateConnectionStatus(status3); auth_failed = false; break; } if (ask.contains(pattern4) || ask.contains(pattern9)) { auth_failed = true; // Incompatible IPC protocol ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_9 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_9); throw new Exception(known_problem_9); } if (ask.contains(pattern5)) { auth_failed = true; // Unreachable host ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_5 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_5); throw new Exception(known_problem_5); } if (ask.contains(pattern6) || ask.contains(pattern10)) { auth_failed = true; // Installation path is not correct cc.updateConnectionStatus(known_problem_6); ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG throw new Exception(known_problem_6); } if (ask.contains(pattern7)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } // if (ask.length() > 100000) { // break; // Why so many? Something wrong. // } } if (!skip_pass) { // got request for the password ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Verifying authentication... Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(status2); for (int i = 0; i < pass.length; i++) { ipc.processInput.write(pass[i]); } ipc.processInput.write('\n'); // ipc.processInput.write('\0'); ipc.processInput.flush(); } else { if (auth_failed) { // Probably the delay is not enough to get the request for the password cc.updateConnectionStatus(status4); System.err.println("Error 1: unrecognized request: " + ask); ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Error 1: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_4 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_4); throw new Exception(known_problem_4); } } c = 190; // timeout 19 seconds while (c-- > 0) { Thread.sleep(100); ask = ipc.getIPCReader().getUnknownInput(); // Check if request for password appeared twice if (ask.contains(pattern1)) { if (skip_pass) { System.err.println("Error 2: unrecognized request: " + ask); auth_failed = true; // Delay is not enough to get request for password ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Error 2: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_1 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_1); throw new Exception(known_problem_1); } int p = ask.indexOf(pattern1); String s = ask.substring(p + 1); if (s.contains(pattern1)) { auth_failed = true; // Password does not match // System.err.println("Error 3: unrecognized request: " + ask); DEBUG ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Error 3: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_1 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_1); throw new Exception(known_problem_1); } } if (ask.contains(pattern8)) { // Connection established cc.updateConnectionStatus(status3); auth_failed = false; break; } if (ask.contains(pattern4) || ask.contains(pattern9)) { auth_failed = true; // Incompatible IPC protocol ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_9 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_9); throw new Exception(known_problem_9); } if (ask.contains(pattern5)) { auth_failed = true; // Unreachable host ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_5 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_5); throw new Exception(known_problem_5); } if (ask.contains(pattern6) || ask.contains(pattern10)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } if (ask.contains(pattern7)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } if (ask.length() > 100000) { // Why so many? Something wrong. auth_failed = true; System.err.println("Error 4: unrecognized request: " + ask); ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Error 4: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_7 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_7); throw new Exception(known_problem_7); } } // Check if connection failed if (ipc_protocol == null) { auth_failed = false; // we don't know for sure } if (auth_failed) { System.err.println("Error 5: unrecognized request: " + ask); ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Error 5: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_3 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_3); throw new Exception(known_problem_3); } // Looks like everything is ok. Try to continue } else { // connection without password if (ipc_protocol != null) { ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Connecting ... Timestamp=" + ts); // DEBUG // this hangs if er_print do not send confirmation int c = 190; // timeout 19 seconds // Don't read - another thread (IPCReader) is already reading it. ask = emptyString; while (c-- > 0) { Thread.sleep(100); ask = ipc.getIPCReader().getUnknownInput(); if (ask.contains(pattern8)) { // Connection established cc.updateConnectionStatus(status3); auth_failed = false; break; } if (ask.contains(pattern1)) { auth_failed = true; // System.err.println("Error 6: unrecognized request: " + ask); DEBUG ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Error 6: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_2 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_2); throw new Exception(known_problem_2); } if (ask.contains(pattern4) || ask.contains(pattern9)) { auth_failed = true; // Incompatible IPC protocol ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_9 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_9); throw new Exception(known_problem_9); } if (ask.contains(pattern5)) { auth_failed = true; // Unreachable host ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_5 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_5); throw new Exception(known_problem_5); } if (ask.contains(pattern6) || ask.contains(pattern10)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } if (ask.contains(pattern7)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } if (ask.length() > 100000) { // Why so many? Something wrong. auth_failed = true; System.err.println("Error 7: unrecognized request: " + ask); ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Error 7: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_3 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_3); throw new Exception(known_problem_3); } } } } if (auth_failed) { System.err.println("Error 8: unrecognized request: " + ask); ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") Error 8: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_3 + " Timestamp=" + ts); // DEBUG cc.updateConnectionStatus(known_problem_3); throw new Exception(known_problem_3); } // Sleep a little to make sure IPCReader got all bytes from the connection step Thread.sleep(100); ts = System.currentTimeMillis(); AnLog.log( "analyzer: Connect to Remote Host(Connection ID=" + connectionID + ") succeeded. Timestamp=" + ts); // DEBUG } private void measureConnectionPerformance(ConnectionDialog cc) { String runTest = null; // AnUtility.getenv("SP_ANALYZER_SPEED_TEST"); runTest = AnUtility.getenv("SP_ANALYZER_SPEED_TEST"); // DEBUG XXX SWITCH OFF WHEN RELEASE if (runTest == null || runTest.equals("0")) { return; } // Measure connection performance - loop of SYNC calls if (cc != null) { cc.updateConnectionStatus( AnLocale.getString("Connection established. Checking connection performance...")); } long totalBytes = IPC_session.getIPCReader().getTotalReceivedBytes(); long totalMsg = IPC_session.getIPCReader().getTotalReceivedMessages(); // System.err.println("Connection performance (SYNC): Total bytes 1=" + totalBytes + " bytes. // Total messages 1=" + totalMsg + " msg."); // DEBUG long t1 = System.currentTimeMillis(); int max = 100; Integer k = new Integer(runTest); if (k > 0) { max = max * k.intValue(); } for (int i = 0; i < max; i++) { versionHandshake(); // syncTime(); } long t2 = System.currentTimeMillis(); totalBytes = IPC_session.getIPCReader().getTotalReceivedBytes() - totalBytes; totalMsg = IPC_session.getIPCReader().getTotalReceivedMessages() - totalMsg; // System.err.println("Connection performance (SYNC): Total bytes 2=" + totalBytes + " bytes. // Total messages 2=" + totalMsg + " msg."); // DEBUG long delta = t2 - t1; if (delta <= 0) { delta = 1; } double upload = (((double) totalBytes * 1000) / delta); double temp = (((double) totalMsg * 1000) / delta); System.err.println("Connection performance (SYNC): Loop count=" + max); // DEBUG System.err.printf( "Connection performance (SYNC): Upload=%.2f bytes/sec. Temp=%.2f messages/sec.\n", upload, temp); // DEBUG AnLog.log( "Connection performance (SYNC): Upload=" + upload + " bytes/sec. Temp=" + temp + " messages/sec."); // DEBUG System.err.println( "Connection performance (SYNC): Received bytes=" + totalBytes + " bytes. Received messages=" + totalMsg + " msg. Time=" + delta + " ms."); // DEBUG AnLog.log( "Connection performance (SYNC): Received bytes=" + totalBytes + " bytes. Received messages=" + totalMsg + " msg. Time=" + delta + " ms."); // DEBUG if (cc != null) { cc.updateConnectionStatus( "Connection performance (SYNC): Upload " + upload + " bytes/msec. Handshaking..."); } // Measure connection performance - loop of ASYNC calls totalBytes = IPC_session.getIPCReader().getTotalReceivedBytes(); totalMsg = IPC_session.getIPCReader().getTotalReceivedMessages(); // System.err.println("Connection performance (ASYNC): Total bytes 3=" + totalBytes + " bytes. // Total messages 3=" + totalMsg + " msg."); // DEBUG t1 = System.currentTimeMillis(); IPCResult ipcResults[] = new IPCResult[max]; for (int i = 0; i < max; i++) { IPCHandle ipcHandle = IPCHandle.newHandshakeIPCHandle(); ipcResults[i] = ipcHandle.sendRequest(); // no body } for (int i = 0; i < max; i++) { IPCResult.CC c = ipcResults[i].getCC(); // blocking } t2 = System.currentTimeMillis(); totalBytes = IPC_session.getIPCReader().getTotalReceivedBytes() - totalBytes; totalMsg = IPC_session.getIPCReader().getTotalReceivedMessages() - totalMsg; // System.err.println("Connection performance (ASYNC): Total bytes 4=" + totalBytes + " bytes. // Total messages 4=" + totalMsg + " msg."); // DEBUG delta = t2 - t1; if (delta <= 0) { delta = 1; } upload = ((totalBytes * 1000) / delta); temp = ((totalMsg * 1000) / delta); System.err.println("Connection performance (ASYNC): Loop count=" + max); // DEBUG System.err.printf( "Connection performance (ASYNC): Upload=%.2f bytes/sec. Temp=%.2f messages/sec.\n", upload, temp); // DEBUG AnLog.log( "Connection performance (ASYNC): Upload=" + upload + " bytes/sec. Temp=" + temp + " messages/sec."); // DEBUG System.err.println( "Connection performance (ASYNC): Received bytes=" + totalBytes + " bytes. Received messages=" + totalMsg + " msg. Time=" + delta + " ms."); // DEBUG AnLog.log( "Connection performance (ASYNC): Received bytes=" + totalBytes + " bytes. Received messages=" + totalMsg + " msg. Time=" + delta + " ms."); // DEBUG if (cc != null) { cc.updateConnectionStatus( "Connection performance (ASYNC): Upload " + upload + " bytes/msec. Handshaking..."); } } private String last_CC_host = null; private String last_CC_un = null; private char[] last_CC_p = null; private String last_CC_collect = null; /** * Update connection information to run collect * * @param host * @param name * @param p */ private void updateConnectionInfo(String host, String name, char[] p, String path_to_collect) { last_CC_host = host; last_CC_un = name; last_CC_collect = path_to_collect; if (null != last_CC_p) { for (int i = 0; i < last_CC_p.length; i++) { last_CC_p[i] = 0; } } if (null != p) { last_CC_p = p.clone(); } else { last_CC_p = null; } } /** Start Remote Collect */ public void startRemoteCollect(Collector collector, ConnectionDialog cc) throws Exception { char[] p = last_CC_p; sendPCollect(collector, p, cc); } /** Get path to local or remote collect */ public String getPathToCollect() { if (!isRemote()) { String collectPath = null; // AnUtility.getenv("SP_ANALYZER_COLLECT"); if (collectPath == null || collectPath.length() == 0) { collectPath = UserPref.binDirFromCommandLine != null ? UserPref.binDirFromCommandLine + "/" + CollectAppName : CollectAppName; AnLog.log("analyzer: collect=" + collectPath + "\n"); } else { AnLog.log("analyzer: SP_ANALYZER_COLLECT=" + collectPath + "\n"); // DEBUG } return collectPath; } return last_CC_collect; } /** * Get path to er_kernel * * @return */ public String getPathToCollectKernel() { String cmd = getPathToCollect(); if (cmd.endsWith(CollectAppName)) { cmd = cmd.substring(0, cmd.length() - CollectAppName.length()) + KernelAppName; } return cmd; } /** * Connect to remote host * * @param rp * @param pass * @param cc * @throws Exception */ private void sendPCollect(Collector collector, char[] pass, ConnectionDialog cc) throws Exception { // This is a temporary code, just to prove the concept connectionID++; long ts = System.currentTimeMillis(); String remote_protocol = null; boolean skip_pass = false; boolean auth_failed = true; String pattern1 = "Password"; String pattern2 = " " + pattern1 + ":"; String pattern3 = pattern1 + " for "; String pattern4 = "Process ID:"; String pattern5 = "Fatal error: host not found: "; String pattern6 = ": not found"; String pattern7 = "Killed"; String pattern10 = ": No such file"; String ask = emptyString; AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") started. Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus("Looking for remote host..."); if ((null != pass) && (pass.length > 0)) { // this hangs if remote process does not send anything, so we use a timeout int c = 190; // timeout 19 seconds while (c-- > 0) { Thread.sleep(100); ask = collector.getCurrentOutput(); if (ask.contains(pattern2)) { break; } if (ask.contains(pattern3)) { break; } if (ask.contains(pattern4)) { // Connection established skip_pass = true; // cc.updateConnectionStatus("Connection established. Compatibility checking..."); auth_failed = false; break; } if (ask.contains(pattern5)) { auth_failed = true; // Unreachable host ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_5 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_5); throw new Exception(known_problem_5); } if (ask.contains(pattern6) || ask.contains(pattern10)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } if (ask.contains(pattern7)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } // if (ask.length() > 100000) { // break; // Why so many? Something wrong. // } } if (!skip_pass) { // got request for the password ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") Verifying authentication... Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus("Verifying authentication..."); for (int i = 0; i < pass.length; i++) { collector.writeInputChar(pass[i]); } collector.writeInputChar('\n'); } else { if (auth_failed) { // Probably the delay is not enough to get the request for the password // cc.updateConnectionStatus("Password is not requested (!?)"); System.err.println("Error 11: unrecognized request: " + ask); // DEBUG ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") Error 11: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_4 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_4); throw new Exception(known_problem_4); } } c = 190; // timeout 19 seconds while (c-- > 0) { Thread.sleep(100); ask = collector.getCurrentOutput(); // rp.getUnknownInput(); // Check if request for password appeared twice if (ask.contains(pattern1)) { if (skip_pass) { System.err.println("Error 12: unrecognized request: " + ask); // DEBUG auth_failed = true; // Delay is not enough to get request for password ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") Error 12: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_1 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_1); throw new Exception(known_problem_1); } int p = ask.indexOf(pattern1); String s = ask.substring(p + 1); if (s.contains(pattern1)) { auth_failed = true; // Password does not match System.err.println("Error 13: unrecognized request: " + ask); // DEBUG ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") Error 13: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_1 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_1); throw new Exception(known_problem_1); } } if (ask.contains(pattern4)) { // Connection established // cc.updateConnectionStatus("Connection established. Compatibility checking..."); auth_failed = false; break; } if (ask.contains(pattern5)) { auth_failed = true; // Unreachable host ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_5 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_5); throw new Exception(known_problem_5); } if (ask.contains(pattern6) || ask.contains(pattern10)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } if (ask.contains(pattern7)) { auth_failed = true; // Installation path is not correct ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_6 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_6); throw new Exception(known_problem_6); } if (ask.length() > 100000) { // Why so many? Something wrong. auth_failed = true; System.err.println("Error 14: unrecognized request: " + ask); // DEBUG ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") Error 14: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_7 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_7); throw new Exception(known_problem_7); } } // Check if connection failed if (remote_protocol == null) { auth_failed = false; // we don't know for sure } if (auth_failed) { System.err.println("Error 15: unrecognized request: " + ask); // DEBUG ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") Error 15: unrecognized request: " + ask + " Timestamp=" + ts); // DEBUG AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") failed: " + known_problem_3 + " Timestamp=" + ts); // DEBUG // cc.updateConnectionStatus(known_problem_3); throw new Exception(known_problem_3); } // Looks like everything is ok. Try to continue // cc.updateConnectionStatus("Finished authentication. Handshaking..."); // } else { // connection without password - nothing to do // return; } ts = System.currentTimeMillis(); AnLog.log( "collector: Connect to Remote Host(Connection ID=" + connectionID + ") succeeded. Timestamp=" + ts); // DEBUG } private void logInit() { AnLog.log(new Date().toString()); AnLog.log(Analyzer.fdversion); AnLog.log(Analyzer.fdhome); // AnLog.log(Analyzer.getInstance().getWorkingDirectory()); AnLog.log(Analyzer.getInstance().er_print); AnLog.log(Analyzer.getInstance().remoteHost); AnLog.log(Analyzer.jvm_home); AnLog.log("-----------------------------------------------------"); } private static void helpInit(final Window win) {} public static void showHelp(final String help_id) { // System.out.println("Analyzer.showHelp: " + help_id); // Mez: Not supported yet because jh-2.0_05.jar cannot be used. } public static final class HelpAction implements ActionListener { final String id; public HelpAction(final String id) { this.id = id; } @Override public void actionPerformed(final ActionEvent event) { // System.out.println("Analyzer.HelpAction.actionPerformed: " + id); showHelp(id); } } /** Doesn't require running IPC. Called once. AWT thread */ private void initAnalyzer() { String strNormalSelection = AnUtility.getenv("SP_ANALYZER_NORMAL_SELECTION"); if (strNormalSelection != null && !strNormalSelection.equals("NO")) { normalSelection = true; AnLog.log("analyzer: SP_ANALYZER_NORMAL_SELECTION is set"); } // if (remoteHost == null) { // remoteHost = AnUtility.getenv("SP_ANALYZER_REMOTE_HOST"); // } String specialRemoteShell = AnUtility.getenv("SP_ANALYZER_REMOTE_SHELL"); if (specialRemoteShell != null && !specialRemoteShell.equals(emptyString)) { remoteShell = specialRemoteShell; } else { if (fdhome.charAt(2) == ':') { if (fdhome.charAt(0) == '/') { String os_name = System.getProperty("os.name"); if (os_name.contains("Windows")) { fdhome = fdhome.substring(1); AnLog.log("analyzer: Corrected path for Windows: fdhome = " + fdhome + "\n"); } } } // if ( ("SunOS".equals(os_name)) || ("Linux".equals(os_name)) ) { // remoteShell = fdhome + "/../../../bin/jssh"; // } else { // remoteShell = "java -Djava.awt.headless=true -cp " + fdhome + // "/../../../lib/analyzer/lib/jssh/lib/jssh.jar jssh.Main "; // remoteShell = "java -cp " + fdhome + "/../../../lib/analyzer/lib/jssh/lib/jssh.jar // jssh.Main "; // } String jar_name = fdhome + JSSH_jar; // Escape spaces if (jar_name.contains("%20")) { jar_name = jar_name.replace("%20", " "); } if (jar_name.contains(" ")) { jar_name = emptyString + '"' + jar_name + '"'; } // System.err.println("Java home: "+Analyzer.jvm_home); // String java = emptyString + Analyzer.jvm_home + "/bin/java"; // System.err.println("Java : "+java); // remoteShell = emptyString + java + " -jar " + jar_name; remoteShell = "java -jar " + jar_name; // System.err.println("remoteShell = " + remoteShell); AnLog.log("analyzer: remoteShell = " + remoteShell + "\n"); } if (remoteHost != null && !remoteHost.equals(emptyString)) { // System.err.println("analyzer: SP_ANALYZER_REMOTE_HOST `" + remoteHost + "'"); AnLog.log("analyzer: SP_ANALYZER_REMOTE_HOST=" + remoteHost + "\n"); remoteConnection = remoteShell + " " + remoteHost; } else { remoteHost = null; remoteConnection = null; } localHost = getLocalHostName(); os_name = System.getProperty("os.name"); logInit(); } public String getLocalHostName() { String localHostName = null; try { java.net.InetAddress addr = java.net.InetAddress.getLocalHost(); localHostName = addr.getHostName(); } catch (Exception e) { } return localHostName; } /** Synchronize Locale with remote engine */ private void synchronizeLocale() { // Set client's locale on remote server // Only 3 locales are supported: ja, zh, C String lc = Locale.getDefault().getLanguage(); String rlc = getLocale(); boolean change = false; if (lc == null) { lc = "C"; } else { if (lc.contains("ja")) { lc = "ja"; } else { if (lc.contains("zh")) { lc = "zh"; } else { lc = "C"; } } } if ((rlc == null) || (rlc.length() < 1) || (!lc.equals(rlc))) { // Set locale change = true; } if (change) { rlc = setLocale(lc); // System.out.println(rlc); } } /** * AWT thread * * @return @throws Exception */ private String initIPC() throws Exception { AnUtility.checkIPCOnWrongThread(false); String temporaryRemoteVersion = getAnalyzerReleaseName() + " " + THIS_VERSION; fdversion = temporaryRemoteVersion; String emsg = null; startIPC(); // Version Handshake if (IPC_started) { versionHandshake(); // Measure connection performance (DEBUG) measureConnectionPerformance(null); } // Initialize gp-display-text final String[] license_info; if (IPC_started) { license_info = initApplication(false, fdhome, licpath, arguments); } else { license_info = new String[2]; license_info[0] = "UNKNOWN"; license_info[1] = temporaryRemoteVersion; } licsts = license_info[0]; fdversion = license_info[1]; String oldVersion = "Sun Analyzer"; String temporaryNewVersion = getAnalyzerReleaseName(); if ((null != fdversion) && (fdversion.startsWith(oldVersion))) { int c1 = oldVersion.length(); fdversion = temporaryNewVersion + fdversion.substring(c1); } if (licsts.equals("ERROR")) { emsg = AnLocale.getString("License Path: ") + licpath + "\n" + AnLocale.getString("Error: ") + fdversion; System.err.println(emsg); System.exit(1); } else if (licsts.equals("WARN") || licsts.equals("FATAL")) { emsg = AnLocale.getString("License Path: ") + licpath + "\n" + AnLocale.getString("Warning: ") + fdversion; System.err.println(emsg); } if (IPC_started) { anFrame.getWindow().initializeAfterIPCStarted(); } AnUtility.checkIPCOnWrongThread(true); return emsg; } /** * AWT Thread * * @throws Exception */ private void initAnalyzerIPC() throws Exception { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { try { String errmsg = initIPC(); // Possible exception // We only get here if IPC is successfully running List<String> expList = AnUtility.getExpList(arguments); // Here we will try to guess what user wants: open an experiment or profile a target? boolean profile = true; if ((arguments != null) && (arguments.length > 0)) { // We will check if the first argument has suffix .er or .erg String target = arguments[0]; if (target.length() > 3) { if (target.endsWith(".er")) { // Experiment directory profile = false; } if (target.endsWith("/")) { // Experiment directory profile = false; } if (target.endsWith(".erg")) { // Experiment group profile = false; } } } else { profile = false; // No arguments } if (profile) { // Clear expList String[] noarguments = new String[0]; expList = AnUtility.getExpList(noarguments); } boolean cmp = compareMode && (expList.size() > 1); anFrame.setVisible(true); String configurationPath; if (!Analyzer.getInstance().isRemote() && expList.size() > 0) { String expPath = expList.get(0); if (!expPath.startsWith("/")) { expPath = Analyzer.getInstance().getWorkingDirectory() + "/" + expPath; } configurationPath = UserPref.getAsWhenClosedConfigPath(expPath); if (!new File(configurationPath).exists()) { configurationPath = UserPref.getConfigurationDirPath(expPath) + "/" + UserPref.getDefaultConfigurationName(); if (!new File(configurationPath).exists()) { String parent = new AnFile(expPath).getParentFile().getAbsolutePath(); configurationPath = parent + "/" + UserPref.getDefaultConfigurationName(); if (!new File(configurationPath).exists()) { configurationPath = UserPref.getHomeConfigurationDirPath() + "/" + UserPref.getDefaultConfigurationName(); // if (!new File(configurationPath).exists()) { // configurationPath = // UserPref.getInstance().getLastClosedExpConfPath(); // } } } } } else { configurationPath = null; } if (null == AnWindow.getInstance().getExperimentGroups()) { // first time here anFrame .getWindow() .loadExperimentList(expList, cmp, null, true, configurationPath, false); } if (profile) { AnWindow.getInstance() .getProfileApplicationAction() .setEnabled(true); // Not enabled this early!!!!!! AnWindow.getInstance().profileApplicationAction(arguments); } if (errmsg != null) { popError(errmsg); } } catch (Exception e) { // IPC didn't run (remote) fireConnectionStatus(AnChangeEvent.Type.REMOTE_CONNECTION_CANCELLED_OR_FAILED); if (IPC_started) { e.printStackTrace(); } try { anFrame.getWindow().welcomeViewOnly(); anFrame.setVisible(true); if (System.getProperty("os.name").contains("Mac")) { // A HACK: Resize +1 Dimension d0 = anFrame.getSize(); Dimension d1 = new Dimension(d0.width + 1, d0.height + 1); anFrame.setSize(d1); anFrame.setSize(d0); // System.out.println("Resized: old size=("+d0.width+","+d0.height+") new // size=("+d1.width+","+d1.height+")"); } // Show pop-up // String msg = "The Analyzer is now running in remote mode. You can connect to a // remote host."; // AnUtility.showMessage(anFrame, msg, JOptionPane.INFORMATION_MESSAGE); } catch (Exception e2) { // Not our day e2.printStackTrace(); // exit? } } } }); } /** * Main init function. Called from AnMain. Called once. AWT Thread * * @param args * @throws Exception */ public void initAnalyzer(final String[] args) throws Exception { AnUtility.checkIfOnAWTThread(true); arguments = args; anFrame = new AnFrame(this); anFrame.initComponents(); initAnalyzer(); initAnalyzerIPC(); } private void popError(final String msg) { AnWindow.getInstance().getExperimentsView().appendLog(AnLocale.getString("Error: ") + msg); AnUtility.showMessage(anFrame, msg, JOptionPane.ERROR_MESSAGE); } public void endIPC(final String err_msg) { popError(err_msg); if (!IPC_started) { return; } setIPCStarted(false); IPC_session.destroyIPCProc(); } // Experimental code - currently on wrong thread (AWT) public void restartEngine() { AnWindow aw = AnWindow.getInstance(); stopConnectionManager(); try { Thread.sleep(100); // A delay in hope all IPC requests finished if (isRemote()) { Thread.sleep(1000); // An additional delay in hope all IPC requests finished // System.err.println("***** NOTE: Waited 1 second before restart engine"); } } catch (Exception e) { // nothing } // Switch IPCReader to restarting mode IPC_session.getIPCReader().suspendThread(); // Restart gp-display-text reExec(); // Wait till gp-display-text is ready. Maximum 10 seconds int maxmsec = 10000; boolean restarted = false; int msec = 0; for (; msec < maxmsec; msec++) { try { if (isRemote()) { Thread.sleep(1000); // wait 1000 milliseconds msec += 1000; } else { Thread.sleep(100); // wait 100 milliseconds msec += 100; } if (IPC_session.getIPCReader().isThreadReady()) { restarted = true; // Connection established // System.err.println("***** NOTE: Connection established"); DEBUG break; } } catch (Exception e) { // nothing } } if (restarted == false) { // Here we should show an error dialog System.err.println("***** ERROR: Cannot restart gp-display-text. Please, reconnect."); } IPC_session.getIPCReader().runThread(); // Version Handshake int res = versionHandshake(); // Call initApplication String l_fdhome = emptyString; String l_licpath = System.getProperty("analyzer.licpath", l_fdhome + "/lib/serial.dat"); String[] args = new String[1]; args[0] = er_print; String[] license_info = new String[2]; license_info[0] = "ERROR"; license_info[1] = "Unknown"; try { license_info = initApplication(false, l_fdhome, l_licpath, args); } catch (Exception e) { if (null == license_info[0]) { license_info[0] = "ERROR"; } } // Init view aw.initView(0, 0); startConnectionManager(); } // Native methods from liber_dbe.so /** Restart gp-display-text */ public void reExec() { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE, null); ipcHandle.append("reExec"); IPCResult ipcResult = ipcHandle.sendRequest(); } // Native methods from liber_dbe.so private String[] initApplication( final boolean in_netbeans, final String fdhome, final String licpath, final String[] args) { synchronized (IPC.lock) { IPC_session.send("initApplication"); IPC_session.send(in_netbeans); IPC_session.send(fdhome); IPC_session.send(licpath); IPC_session.send(args); return (String[]) IPC_session.recvObject(); } } /** * Get backend version and compare with frontend version * * @return 1 if versions do not match, return 0 is versions match */ private int versionHandshake() { synchronized (IPC.lock) { IPCHandle ipcHandle = IPCHandle.newHandshakeIPCHandle(); IPCResult ipcResult = ipcHandle.sendRequest(); // no body IPCResult.CC cc = ipcResult.getCC(); // blocking if (cc == IPCResult.CC.SUCCESS) { int er_printVersion = ipcResult.getVersion(); if (er_printVersion != IPCProtocol.version) { System.err.println("Frontend/backend protocol version mis-match:"); System.err.println("GUI version: " + IPCProtocol.version); System.err.println("gp-display-text version: " + er_printVersion); return (1); } } } return (0); } private int syncTime() { synchronized (IPC.lock) { IPC_session.send("syncTime"); IPC_session.send(IPCLogger.getTimeStamp()); IPC_session.recvString(); // blocking } return (0); } /** * Get backend locale * * @return result : current locale */ final String getLocale() { synchronized (IPC.lock) { IPC_session.send("getLocale"); return IPC_session.recvString(); // blocking } } /** * Set backend locale * * @return result : current locale */ private String setLocale(final String locale) { synchronized (IPC.lock) { IPC_session.send("setLocale"); IPC_session.send(locale); return IPC_session.recvString(); // blocking } } /** * Initialize backend application * * @param win_id * @param clone_id * @return String */ public String IPC_initView(final int win_id, final int clone_id) { IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE); ipcHandle.append("initView"); ipcHandle.append(win_id); ipcHandle.append(clone_id); IPCResult ipcResult = ipcHandle.sendRequest(); String result = ipcResult.getString(); // blocking return result; } /** * Get current directory * * @return result : full path */ final String getCurrentDirectory() { synchronized (IPC.lock) { IPC_session.send("getCurrentDirectory"); return IPC_session.recvString(); } } /** * Set current directory * * @param dir_name * @return result : 0 done, -1 error */ final int setCurrentDirectory(final String dir_name) { synchronized (IPC.lock) { IPC_session.send("setCurrentDirectory"); IPC_session.send(dir_name); return IPC_session.recvInt(); } } public static String getAnalyzerReleaseName() { return PERFORMANCE_ANALYZER_RELEASE_NAME; } /** Update IPC connection status */ public void setIPCStarted(boolean started) { IPC_started = started; } private void fireConnectionStatus(AnChangeEvent.Type type) { AnChangeEvent anChangeEvent = new AnChangeEvent(this, type); AnEventManager.getInstance().fireAnChangeEvent(anChangeEvent); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/�������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�016376� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/StatusLabelValueHandle.java����������������������������0000644�0001750�0001750�00000006255�14517772113�023507� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statuspanel; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JLabel; public class StatusLabelValueHandle { public enum Mode { DEFAULT, SET, ERROR }; public static final Color DEFAULT_COLOR = Color.BLACK; public static final Color SET_COLOR = new Color(44, 121, 6); public static final Color ERROR_COLOR = Color.RED; private StatusLabel statusLabel; protected StatusLabelValueHandle( AnWindow anWindow, ImageIcon icon, String labelTxt, String toolTipText, ActionListener actionListener) { String txt = null; if (labelTxt != null) { txt = labelTxt + ": "; } statusLabel = anWindow.getStatusPanel().addStatusLabel(icon, txt, toolTipText, actionListener); } public String get() { return statusLabel.getValueLabel().getText(); } public void update(String text) { update(text, Mode.DEFAULT); } public void updateToolTip(String text) { statusLabel.getTextLabel().setToolTipText(text); statusLabel.getValueLabel().setToolTipText(text); } public void update(String text, Mode mode) { Color color = DEFAULT_COLOR; if (mode == Mode.DEFAULT) { color = DEFAULT_COLOR; } else if (mode == Mode.SET) { color = SET_COLOR; } else if (mode == Mode.ERROR) { color = ERROR_COLOR; } update(text, color); } private void update(final String valueText, final Color color) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { statusLabel.getValueLabel().setForeground(color); statusLabel.getValueLabel().setText(valueText); } }); } public void update(final ImageIcon icon) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { statusLabel.setTextLabelIcon(icon); } }); } public void setVisible(boolean visible) { statusLabel.setVisible(visible); } public void setEnabled(final boolean enabled) { statusLabel.setEnabled(enabled); } public boolean isVisible() { return statusLabel.getValueLabel().isVisible(); } /** * @return the text label */ public JLabel getTextLabel() { return statusLabel.getTextLabel(); } /** * @return the value label */ public JLabel getValueLabel() { return statusLabel.getValueLabel(); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/StatusPanel.form���������������������������������������0000644�0001750�0001750�00000003742�14517772113�021436� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Form> ������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/StatusLabel.java���������������������������������������0000644�0001750�0001750�00000014051�14517772113�021367� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statuspanel; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Cursor; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JLabel; import javax.swing.JSeparator; class StatusLabel { private JSeparator separator; private JLabel textLabel; private JLabel valueLabel; private ActionListener actionListener; private MouseListener mouseListener = null; private KeyboardListener keyboardListener = null; /** * @return the separator */ protected JSeparator getSeparator() { return separator; } /** * @param separator the separator to set */ protected void setSeparator(JSeparator separator) { this.separator = separator; } /** * @return the labelTxt */ protected JLabel getTextLabel() { return textLabel; } protected void setTextLabelIcon(ImageIcon icon) { textLabel.setIcon(icon); } /** * @param textLabel the labelTxt to set */ protected void setTextLabel(final JLabel textLabel) { this.textLabel = textLabel; if (textLabel != null) { textLabel.addFocusListener( new FocusAdapter() { @Override public void focusGained(FocusEvent e) { textLabel.setBorder( BorderFactory.createLineBorder(AnEnvironment.STATUS_SELECTED_BORDER_COLOR)); } @Override public void focusLost(FocusEvent e) { textLabel.setBorder(null); } }); } } /** * @return the labelValue */ protected JLabel getValueLabel() { return valueLabel; } /** * @param valueLabel the labelValue to set */ protected void setValueLabel(final JLabel valueLabel) { this.valueLabel = valueLabel; if (valueLabel != null) { valueLabel.addFocusListener( new FocusAdapter() { @Override public void focusGained(FocusEvent e) { valueLabel.setBorder( BorderFactory.createLineBorder(AnEnvironment.STATUS_SELECTED_BORDER_COLOR)); } @Override public void focusLost(FocusEvent e) { valueLabel.setBorder(null); } }); } } public void setEnabled(final boolean enabled) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { if (enabled && getValueLabel().isEnabled()) { return; } if (!enabled && !getValueLabel().isEnabled()) { return; } if (!enabled && getMouseListener() != null) { textLabel.removeMouseListener(getMouseListener()); valueLabel.removeMouseListener(getMouseListener()); } // getTextLabel().setEnabled(enabled); getValueLabel().setEnabled(enabled); if (getSeparator() != null) { getSeparator().setEnabled(enabled); } if (enabled && getMouseListener() != null) { textLabel.addMouseListener(getMouseListener()); valueLabel.addMouseListener(getMouseListener()); } } }); } public void setVisible(final boolean visible) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { getTextLabel().setVisible(visible); getValueLabel().setVisible(visible); if (getSeparator() != null) { getSeparator().setVisible(visible); } } }); } protected void addActionListener(ActionListener actionListener) { this.actionListener = actionListener; if (actionListener != null) { textLabel.addMouseListener(getMouseListener()); textLabel.addKeyListener(getKeyboardListener()); valueLabel.addMouseListener(getMouseListener()); valueLabel.addKeyListener(getKeyboardListener()); } } private MouseListener getMouseListener() { if (mouseListener == null) { mouseListener = new MouseListener(); } return mouseListener; } class MouseListener extends MouseAdapter { private Cursor oldCursor = null; // @Override @Override public void mouseEntered(MouseEvent e) { oldCursor = textLabel.getCursor(); textLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); valueLabel.setCursor(new Cursor(Cursor.HAND_CURSOR)); } // @Override @Override public void mouseExited(MouseEvent e) { textLabel.setCursor(oldCursor); valueLabel.setCursor(oldCursor); } // @Override @Override public void mouseClicked(MouseEvent e) { if (actionListener != null) { actionListener.actionPerformed(null); } } } private KeyboardListener getKeyboardListener() { if (keyboardListener == null) { keyboardListener = new KeyboardListener(); } return keyboardListener; } class KeyboardListener extends KeyAdapter { @Override public void keyPressed(KeyEvent e) { if (e.getKeyChar() == ' ' && actionListener != null) { actionListener.actionPerformed(null); } } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/StatusPanel.java���������������������������������������0000644�0001750�0001750�00000015347�14517772113�021420� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statuspanel; import org.gprofng.analyzer.AnEnvironment; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.event.ActionListener; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSeparator; public class StatusPanel extends JPanel { public enum Orientation { LEFT, RIGHT }; private int gridxLeft = 0; private int gridxCenter = 50; private int gridxRight = 100; public StatusPanel() { initComponents(); // setBackground(AnEnvironment.STATUS_PANEL_BACKGROUND_COLOR); // setTopBorderColor(AnEnvironment.STATUS_PANEL_BORDER_COLOR); // setTopBorderColor(Color.red); setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, AnEnvironment.STATUS_PANEL_BORDER_COLOR)); addCenterFill(); } @Override protected void paintComponent(Graphics g) { int width = getWidth(); int height = getHeight(); Graphics2D g2d = (Graphics2D) g; GradientPaint gp; gp = new GradientPaint( 0, 0, AnEnvironment.STATUS_PANEL_BACKGROUND_COLOR1, 0, height, AnEnvironment.STATUS_PANEL_BACKGROUND_COLOR2); g2d.setPaint(gp); g2d.fillRect(0, 0, width, height); } private final void addCenterFill() { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridxCenter; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.anchor = GridBagConstraints.CENTER; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; add(new JLabel(""), gridBagConstraints); } protected final StatusComponent addStatusComponent( JComponent component, Orientation orientation) { StatusComponent statusComponent = new StatusComponent(); statusComponent.setComponent(component); GridBagConstraints gridBagConstraints = new GridBagConstraints(); if (orientation == Orientation.LEFT) { if (gridxLeft > 0) { gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridxLeft++; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(6, 4, 4, 4); gridBagConstraints.fill = GridBagConstraints.VERTICAL; gridBagConstraints.anchor = GridBagConstraints.LINE_START; JSeparator separator = new JSeparator(JSeparator.VERTICAL); statusComponent.setSeparator(separator); add(separator, gridBagConstraints); } gridBagConstraints.gridx = gridxLeft++; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(4, 4, 2, 8); gridBagConstraints.anchor = GridBagConstraints.LINE_START; } else { gridBagConstraints.gridx = gridxRight--; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(2, 4, 0, gridxRight == 99 ? 18 : 4); gridBagConstraints.anchor = GridBagConstraints.LINE_END; } add(component, gridBagConstraints); return statusComponent; } protected final StatusLabel addStatusLabel( ImageIcon icon, String txt, String toolTipText, ActionListener actionListener) { StatusLabel statusLabel = new StatusLabel(); // String formattedTxt = txt; // int i = txt.indexOf(":"); // if (i > 0 ) { // formattedTxt = "<html>" + txt.substring(0, i+1) + "<font color=#2c7906>" + // txt.substring(i+1); // } JLabel txtLabel = new JLabel(); if (txt != null) { txtLabel.setText(txt); } if (icon != null) { txtLabel.setIcon(icon); } statusLabel.setTextLabel(txtLabel); txtLabel.setFont(txtLabel.getFont().deriveFont(Font.PLAIN)); if (toolTipText != null) { txtLabel.setToolTipText(toolTipText); } JLabel valueLabel = new JLabel(); statusLabel.setValueLabel(valueLabel); valueLabel.setFont(txtLabel.getFont().deriveFont(Font.PLAIN)); if (toolTipText != null) { valueLabel.setToolTipText(toolTipText); } GridBagConstraints gridBagConstraints; if (gridxLeft > 0) { gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridxLeft++; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(6, 4, 4, 4); gridBagConstraints.fill = GridBagConstraints.VERTICAL; gridBagConstraints.anchor = GridBagConstraints.LINE_START; JSeparator separator = new JSeparator(JSeparator.VERTICAL); statusLabel.setSeparator(separator); add(separator, gridBagConstraints); } gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridxLeft++; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(4, 6, 2, 0); gridBagConstraints.anchor = GridBagConstraints.LINE_START; add(txtLabel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = gridxLeft++; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(4, 2, 2, 8); gridBagConstraints.anchor = GridBagConstraints.LINE_START; add(valueLabel, gridBagConstraints); if (actionListener != null) { statusLabel.addActionListener(actionListener); } return statusLabel; } public final void removeStatusComponent(JComponent component) { remove(component); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.GridBagLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/StatusComponent.java�����������������������������������0000644�0001750�0001750�00000002517�14517772113�022316� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statuspanel; import javax.swing.JComponent; import javax.swing.JSeparator; class StatusComponent { private JSeparator separator; private JComponent component; /** * @return the separator */ protected JSeparator getSeparator() { return separator; } /** * @param separator the separator to set */ protected void setSeparator(JSeparator separator) { this.separator = separator; } /** * @return the component */ protected JComponent getComponent() { return component; } /** * @param component the labelTxt to set */ protected void setComponent(JComponent component) { this.component = component; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/StatusHandleFactory.java�������������������������������0000644�0001750�0001750�00000003167�14517772113�023101� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statuspanel; import org.gprofng.mpmt.AnWindow; import java.awt.event.ActionListener; import javax.swing.ImageIcon; import javax.swing.JComponent; public class StatusHandleFactory { public static StatusLabelValueHandle createStatusLabelValue( AnWindow anWindow, ImageIcon icon, String labelTxt, String labelToolTip, ActionListener actionListener) { return new StatusLabelValueHandle(anWindow, icon, labelTxt, labelToolTip, actionListener); } public static StatusLabelHandle createStatusLabel( AnWindow anWindow, String labelTxt, String labelToolTip, StatusPanel.Orientation orientation) { return new StatusLabelHandle(anWindow, labelTxt, labelToolTip, orientation); } public static StatusComponentHandle createStatusComponent( AnWindow anWindow, JComponent component, StatusPanel.Orientation orientation) { return new StatusComponentHandle(anWindow, component, orientation); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/StatusLabelHandle.java���������������������������������0000644�0001750�0001750�00000004170�14517772113�022504� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statuspanel; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.AnUtility; import javax.swing.JLabel; public class StatusLabelHandle { private JLabel label; private StatusComponent statusComponent; protected StatusLabelHandle( AnWindow anWindow, String labelTxt, String toolTipText, StatusPanel.Orientation orientation) { label = new JLabel(labelTxt); label.setToolTipText(toolTipText); statusComponent = anWindow.getStatusPanel().addStatusComponent(label, orientation); } public void setText(String text) { label.setText(text); } public String getText() { return label.getText(); } public void update(final String text) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { label.setText(text); } }); } public void updateToolTip(String text) { label.setToolTipText(text); } public void setVisible(boolean visible) { statusComponent.getComponent().setVisible(visible); if (statusComponent.getSeparator() != null) { statusComponent.getSeparator().setVisible(visible); } } public void setEnabled(final boolean enabled) { statusComponent.getComponent().setEnabled(enabled); if (statusComponent.getSeparator() != null) { statusComponent.getSeparator().setEnabled(enabled); } } public boolean isVisible() { return statusComponent.getComponent().isVisible(); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/statuspanel/StatusComponentHandle.java�����������������������������0000644�0001750�0001750�00000002407�14517772113�023430� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.statuspanel; import org.gprofng.mpmt.AnWindow; import javax.swing.JComponent; public class StatusComponentHandle { private StatusComponent statusComponent; protected StatusComponentHandle( AnWindow anWindow, JComponent component, StatusPanel.Orientation orientation) { statusComponent = anWindow.getStatusPanel().addStatusComponent(component, orientation); } public void setVisible(boolean visible) { statusComponent.getComponent().setVisible(visible); if (statusComponent.getSeparator() != null) { statusComponent.getSeparator().setVisible(visible); } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/SummaryPanel.java��������������������������������������������������0000644�0001750�0001750�00000061771�14517772113�017231� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.collect.CollectUtility; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.event.AnSelectionEvent; import org.gprofng.mpmt.util.gui.AnJPanel; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.gui.AnUtility.AnLabel; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.GridLayout; import javax.accessibility.AccessibleContext; import javax.swing.Box; import javax.swing.BoxLayout; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextArea; import javax.swing.JTextField; public final class SummaryPanel extends AnJPanel implements AnChangeListener { private final int win_id; private final AnWindow window; private long cur_sel_obj, cur_sel_type, last_sel_obj; private JPanel info_panel; private AnList func_info, metrics_info; private AnLabel metric_title; private JComponent[] func_text, excl_text, ev_text, incl_text, iv_text; private boolean computed, cur_is_data_or_index, func_renew, metrics_renew; private int[] align; private Object summaryPanelLock = new Object(); // Constructor public SummaryPanel() { window = AnWindow.getInstance(); win_id = 0; computed = false; cur_sel_obj = 0; last_sel_obj = 0; cur_sel_type = AnDisplay.DSP_Null; cur_is_data_or_index = false; func_renew = true; metrics_renew = true; align = null; // Initialize GUI components & set preferred size initComponents(); registerKeyboardAction( new Analyzer.HelpAction(AnVariable.HELP_TabsSummary), "help", KeyboardShortcuts.helpActionShortcut, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); AccessibleContext context = getAccessibleContext(); String loc_string = AnLocale.getString("Summary"); context.setAccessibleName(loc_string); context.setAccessibleDescription(loc_string); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("OverviewView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: reset(); break; case EXPERIMENTS_LOADED_FAILED: case EXPERIMENTS_LOADED: setBaseOnly(window.getSettings().getCompareModeSetting().comparingExperiments()); // Nothing break; case FILTER_CHANGED: computed = false; break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SETTING_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_UPDATE: // Nothing break; case SELECTION_CHANGED: AnSelectionEvent selectionEvent = (AnSelectionEvent) e.getSource(); computed = false; computeOnAWorkerThread( selectionEvent.getSelObj(), selectionEvent.getType(), selectionEvent.getSubtype(), selectionEvent.getVersion()); break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } private void debug() { System.out.println(this.getClass().getSimpleName()); } // public GraphControls toolbar_gctl; // Initialize GUI components private void initComponents() { setLayout(new BorderLayout()); Dimension fillerDim = new Dimension(10, 10); // toolbar_gctl = new GraphControls(this.m_window); // toolbar_gctl.is_UpDownAvail = false; // toolbar_gctl.is_ColorAvail = false; // toolbar_gctl.getCreateToolbar(); // toolbar_gctl.tbar_backward.setEnabled (false); // toolbar_gctl.tbar_forward.setEnabled(false); // toolbar_gctl.tbar_zoom_in.setEnabled(false); // toolbar_gctl.tbar_zoom_out.setEnabled(false); // toolbar_gctl.tbar_zoom_reset.setEnabled(false); info_panel = new AnJPanel(); info_panel.setLayout(new BoxLayout(info_panel, BoxLayout.Y_AXIS)); info_panel.add(new Box.Filler(fillerDim, fillerDim, fillerDim)); // AnLabel anf = (AnLabel) AnUtility.getHeader(AnLocale.getString("Selected Object:")); // info_panel.add(anf); // JToolBar tb = toolbar_gctl.getToolbar(); // tb.setFloatable(false); // JPanel tbPanel = new ANJPanel(new BorderLayout()); // tbPanel.add(tb, BorderLayout.PAGE_START); // // info_panel.add(tbPanel); func_info = new AnList(true); info_panel.add(func_info); // anf.setLabelFor(func_info); func_info.getAccessibleContext().setAccessibleName(AnLocale.getString("Function info")); func_info.getAccessibleContext().setAccessibleDescription(AnLocale.getString("Function info")); // info_panel.add(new JSeparator(SwingConstants.HORIZONTAL)); info_panel.add(new Box.Filler(fillerDim, fillerDim, fillerDim)); AnLabel anm = (AnLabel) AnUtility.getHeader(""); metric_title = anm; info_panel.add(anm); metrics_info = new AnList(true); info_panel.add(metrics_info); info_panel.add(new Box.Filler(fillerDim, fillerDim, fillerDim)); anm.setLabelFor(metrics_info); metrics_info.getAccessibleContext().setAccessibleName(AnLocale.getString("Metrics info")); metrics_info .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Metrics info")); // JScrollPane scrollPane = new AnJScrollPane(info_panel); // scrollPane.setBorder(null); add(info_panel, BorderLayout.CENTER); // func_info.setBorder(AnVariable.boxBorder); // metrics_info.setBorder(AnVariable.boxBorder); // setPreferredSize(new Dimension(AnVariable.INFO_PRF_SIZE)); setMinimumSize(AnVariable.INFO_MIN_SIZE); } // Reset the metrics items (number of func items remains the same). private void reset() { metrics_renew = true; } /* * Use summaryPanelLock so doCompute is called in the same order as computeOnAWorkerThread is called. See 18765370 - Selection Details incorrect after "go back" and "go forward" in src/dis view */ private void computeOnAWorkerThread( final long[] sel_obj, final int type, final int subtype, final int version) { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { synchronized (summaryPanelLock) { synchronized (AnVariable.mainFlowLock) { doCompute(sel_obj, type, subtype, version); } } } }, "Summary_thread"); ; } // Compute summary display private void doCompute( final long[] sel_obj, final int type, final int subtype, final int version) { AnUtility.checkIfOnAWTThread(false); final boolean is_data_or_index; if (computed && (cur_sel_type == type) && (type != AnDisplay.DSP_CallerCalleeSelf) && (cur_sel_obj == sel_obj[0]) && (last_sel_obj == sel_obj[sel_obj.length - 1])) { // multiselection return; } if ((type == AnDisplay.DSP_MemoryObject) || (type == AnDisplay.DSP_DataLayout) || (type == AnDisplay.DSP_DataObjects) || (type == AnDisplay.DSP_IndexObject) || (type == AnDisplay.DSP_IO) || (type == AnDisplay.DSP_IOFileDescriptors) || (type == AnDisplay.DSP_IOCallStacks) || (type == AnDisplay.DSP_Heap)) { is_data_or_index = true; } else { is_data_or_index = false; } if ((cur_is_data_or_index != is_data_or_index) || ((is_data_or_index == true) && (cur_sel_type != type))) { func_renew = true; metrics_renew = true; } cur_sel_obj = sel_obj[0]; cur_sel_type = type; cur_is_data_or_index = is_data_or_index; final Object[] data; if (version == 1) { data = getSummary(sel_obj, type, subtype); // IPC } else if (version == 2) { data = getSummaryV2(sel_obj, type, subtype); // IPC } else { data = null; } final Object[] marks; if (type == AnDisplay.DSP_Source || type == AnDisplay.DSP_SourceV2 || type == AnDisplay.DSP_Disassembly || type == AnDisplay.DSP_DisassemblyV2 || type == AnDisplay.DSP_SourceDisassembly) { marks = getSummaryHotMarks(sel_obj, type); } else { marks = null; } AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { updateSummary(data, type, marks); } }); computed = true; } private void updateSummary(final Object[] data, int type, final Object[] marks) { // System.out.println("SummaryPanel type: " + type); if (data == null) { return; } boolean need_validate = false; char[] mnemonic; final String[] value, iv_label, e_label, ev_label, i_label; final double[] clock, exclusive, e_percent, inclusive, i_percent; final int[] vtype; int size, columns, len, i; JLabel jlabel; JPanel panel; JScrollPane tx_scroll; String[] label; final Dimension msize; final boolean show_inclusive, exclusive_is_data_derived; if ((type == AnDisplay.DSP_MemoryObject) || (type == AnDisplay.DSP_DataLayout) || (type == AnDisplay.DSP_DataObjects)) { show_inclusive = false; exclusive_is_data_derived = true; } else if ((type == AnDisplay.DSP_IndexObject) || (type == AnDisplay.DSP_IO) || (type == AnDisplay.DSP_IOFileDescriptors) || (type == AnDisplay.DSP_IOCallStacks) || (type == AnDisplay.DSP_Heap)) { show_inclusive = false; exclusive_is_data_derived = false; } else { show_inclusive = true; exclusive_is_data_derived = false; } // "Bugs 16624403 and 19539622" (leave this string intact for searches) boolean func_is_Total = false; final Object[] func = (Object[]) data[0]; if (func != null) { align = (int[]) func[0]; mnemonic = (char[]) func[1]; label = (String[]) func[2]; value = (String[]) func[3]; size = label.length; // "Bugs 16624403 and 19539622" (leave this string intact for searches) // check if this func is <Total> for (i = 0; i < size; i++) { if (label[i].equals("Name") && value[i].equals("<Total>")) func_is_Total = true; } if (func_renew) { func_info.removeAll(); func_text = new JComponent[size]; for (i = 0; i < size; i++) { jlabel = (JLabel) AnUtility.getItem(label[i] + ":"); // jlabel.setDisplayedMnemonic(mnemonic[i]); jlabel.getAccessibleContext().setAccessibleName(label[i]); jlabel.getAccessibleContext().setAccessibleDescription(label[i]); if ((type == AnDisplay.DSP_DataObjects) && (i == size - 1)) { func_text[i] = AnUtility.getTextArea(value[i] != null ? value[i] : ""); (func_text[i]).setFont(CollectUtility.text_font); tx_scroll = new AnJScrollPane(func_text[i]); tx_scroll.setPreferredSize(new Dimension(func_text[0].getPreferredSize().width, 120)); tx_scroll.setMaximumSize(new Dimension(func_text[0].getMaximumSize().width, 120)); func_info.add(jlabel, tx_scroll); } else { func_text[i] = AnUtility.getText(value[i] != null ? value[i] : "", 30); func_info.add(jlabel, func_text[i]); } jlabel.setLabelFor(func_text[i]); } // Fix the height msize = func_info.getMaximumSize(); msize.height = func_info.getPreferredSize().height; func_info.setMaximumSize(msize); func_info.invalidate(); func_renew = false; need_validate = true; } else { for (i = 0; i < size; i++) { if (value.length < size) { // TEMPORARY TRAP AnLog.log( "analyzer: race condition in updateSummary(): size=" + size + " value.length=" + value.length); return; } else if ((type == AnDisplay.DSP_DataObjects) && (i == size - 1)) { if (!(func_text[i] instanceof JTextArea)) { AnLog.log( "analyzer: invalid cast in updateSummary(): " + func_text[i] + " is not a JTextArea"); return; } ((JTextArea) func_text[i]).setText(value[i] != null ? value[i] : ""); } else { if (!(func_text[i] instanceof JTextField)) { AnLog.log( "analyzer: invalid cast in updateSummary(): " + func_text[i] + " is not a JTextField"); return; } ((JTextField) func_text[i]).setText(value[i] != null ? value[i] : ""); } } } } else { func_info.removeAll(); func_info.addLabel(new JLabel(AnLocale.getString("No Data"))); } final Object[] metric = (Object[]) data[1]; if (metric != null) { label = (String[]) metric[0]; clock = (double[]) metric[1]; exclusive = (double[]) metric[2]; e_percent = (double[]) metric[3]; inclusive = (double[]) metric[4]; i_percent = (double[]) metric[5]; vtype = (int[]) metric[6]; size = label.length; e_label = new String[size]; ev_label = new String[size]; i_label = new String[size]; iv_label = new String[size]; columns = 0; for (i = 0; i < size; i++) { ev_label[i] = iv_label[i] = null; switch (vtype[i]) { case AnMetric.VT_DOUBLE: e_label[i] = (new AnDouble(exclusive[i])).toPercentQuote(e_percent[i]); if (show_inclusive) { i_label[i] = (new AnDouble(inclusive[i])).toPercentQuote(i_percent[i]); } break; case AnMetric.VT_INT: e_label[i] = (new AnInteger((int) exclusive[i])).toPercentQuote(e_percent[i]); if (show_inclusive) { i_label[i] = (new AnInteger((int) inclusive[i])).toPercentQuote(i_percent[i]); } break; case AnMetric.VT_LLONG: case AnMetric.VT_ULLONG: if (clock[i] == 0.0) { e_label[i] = (new AnLong((long) exclusive[i])).toPercentQuote(e_percent[i]); if (show_inclusive) { i_label[i] = (new AnLong((long) inclusive[i])).toPercentQuote(i_percent[i]); } } else { ev_label[i] = (new AnLong((long) exclusive[i])).toQuoteSpace(); e_label[i] = (new AnDouble(exclusive[i] / clock[i])).toPercentQuote(e_percent[i]); if (show_inclusive) { iv_label[i] = (new AnLong((long) inclusive[i])).toQuoteSpace(); i_label[i] = (new AnDouble(inclusive[i] / clock[i])).toPercentQuote(i_percent[i]); } } break; default: e_label[i] = i_label[i] = " "; break; } // "Bugs 16624403 and 19539622" (leave this string intact for searches) if (func_is_Total) { if (label[i].equals("Block Covered %") || label[i].equals("Instr Covered %")) { if (e_label[i] != null && !e_label[i].equals(" ")) e_label[i] = " "; if (i_label[i] != null && !i_label[i].equals(" ")) i_label[i] = " "; if (ev_label[i] != null && !ev_label[i].equals(" ")) ev_label[i] = " "; if (iv_label[i] != null && !iv_label[i].equals(" ")) iv_label[i] = " "; } } // Compute the maximum width len = e_label[i].length(); if (columns < len) { columns = len; } if (show_inclusive) { len = i_label[i].length(); if (columns < len) { columns = len; } } if (ev_label[i] != null) { len = ev_label[i].length(); if (columns < len) { columns = len; } if (show_inclusive) { len = iv_label[i].length(); if (columns < len) { columns = len; } } } } if (metrics_renew) { metrics_info.removeAll(); panel = new AnJPanel(new GridLayout(1, 2)); if (show_inclusive) { panel.add(AnUtility.getHeader(AnLocale.getString("Exclusive"), AnUtility.excl_icon)); panel.add(AnUtility.getHeader(AnLocale.getString("Inclusive"), AnUtility.incl_icon)); } else if (exclusive_is_data_derived) { panel.add(AnUtility.getHeader(AnLocale.getString("Data-derived"), AnUtility.data_icon)); } else { panel.add(AnUtility.getHeader(AnLocale.getString("Exclusive"), AnUtility.excl_icon)); } metrics_info.add((JComponent) null, panel); excl_text = new AnUtility.AnText[size]; ev_text = new AnUtility.AnText[size]; incl_text = new AnUtility.AnText[size]; iv_text = new AnUtility.AnText[size]; for (i = 0; i < size; i++) { excl_text[i] = AnUtility.getNumber(e_label[i], columns); incl_text[i] = AnUtility.getNumber(i_label[i], columns); if (show_inclusive) { panel = new AnJPanel(new GridLayout(1, 2)); panel.add(excl_text[i]); panel.add(incl_text[i]); } else { panel = new AnJPanel(new GridLayout(1, 1)); panel.add(excl_text[i]); } jlabel = (JLabel) AnUtility.getItem(label[i] + ":"); /* YXXX TBR Thomas, feel free to delete this if (mnemonic[i] != '\0') { jlabel.setDisplayedMnemonic(mnemonic[i]); } */ jlabel.setLabelFor(excl_text[i]); metrics_info.add(jlabel, panel); // A11y: add labels for inclusive metrics if (show_inclusive) { JLabel inclabel = new JLabel(label[i]); /* YXXX TBR Thomas, feel free to delete this if (mnemonic[i] != '\0') { inclabel.setDisplayedMnemonic(mnemonic[i]); } */ inclabel.setLabelFor(incl_text[i]); inclabel.setVisible(false); metrics_info.add(inclabel, panel); } if (ev_label[i] != null) { ev_text[i] = AnUtility.getNumber(ev_label[i], columns); iv_text[i] = AnUtility.getNumber(iv_label[i], columns); if (show_inclusive) { panel = new AnJPanel(new GridLayout(1, 2)); panel.add(ev_text[i]); panel.add(iv_text[i]); } else { panel = new AnJPanel(new GridLayout(1, 1)); panel.add(ev_text[i]); } metrics_info.add(AnUtility.getItem(AnLocale.getString("\" count:")), panel); } else { ev_text[i] = iv_text[i] = null; } } if (marks != null) { int[] nmetric = (int[]) marks[0]; int[] inc = (int[]) marks[1]; for (i = 0; i < nmetric.length; i++) { if (inc[i] == 1) { ((JTextField) incl_text[nmetric[i]]).setBackground(AnVariable.HILIT_INC_COLOR); } else { ((JTextField) excl_text[nmetric[i]]).setBackground(AnVariable.HILIT_COLOR); } } } metrics_info.setAlignmentX(); metrics_info.invalidate(); metrics_renew = false; need_validate = true; } else { if (columns != 0) { columns += 2; } for (i = 0; i < size; i++) { ((JTextField) excl_text[i]).setText(e_label[i]); ((JTextField) excl_text[i]).setColumns(columns); ((JTextField) incl_text[i]).setText(i_label[i]); ((JTextField) incl_text[i]).setColumns(columns); ((JTextField) excl_text[i]).setBackground(Color.white); ((JTextField) incl_text[i]).setBackground(Color.white); if ((ev_text[i] != null) && (ev_label[i] != null)) { ((JTextField) ev_text[i]).setText(ev_label[i]); ((JTextField) ev_text[i]).setColumns(columns); ((JTextField) iv_text[i]).setText(iv_label[i]); ((JTextField) iv_text[i]).setColumns(columns); } } if (marks != null) { int[] nmetric = (int[]) marks[0]; int[] inc = (int[]) marks[1]; for (i = 0; i < nmetric.length; i++) { if (inc[i] == 1) { ((JTextField) incl_text[nmetric[i]]).setBackground(AnVariable.HILIT_INC_COLOR); } else { ((JTextField) excl_text[nmetric[i]]).setBackground(AnVariable.HILIT_COLOR); } } } } } else { metrics_info.removeAll(); final JLabel lab = new JLabel(AnLocale.getString("No Data")); metrics_info.addLabel(lab); lab.getAccessibleContext().setAccessibleName(AnLocale.getString("No Data")); lab.getAccessibleContext().setAccessibleDescription(AnLocale.getString("No Data")); } if (need_validate) { info_panel.validate(); } // Make the most interesting part, the end, visible size = func_text.length; for (i = 0; i < size; i++) { if ((type == AnDisplay.DSP_DataObjects) && (i == size - 1)) { if (!(func_text[i] instanceof AnUtility.AnTextArea)) { AnLog.log( "analyzer: invalid cast in updateSummary(): " + func_text[i] + " is not an AnUtility.AnTextArea"); continue; } ((AnUtility.AnTextArea) func_text[i]).setCaretPosition(0); } else { int align_v = 0; if (align.length > i) { align_v = align[i]; } if (!(func_text[i] instanceof AnUtility.AnText)) { AnLog.log( "analyzer: invalid cast in updateSummary(): " + func_text[i] + " is not an AnUtility.AnText"); continue; } ((AnUtility.AnText) func_text[i]).setVisibleAlign(align_v, need_validate); } } } // Clear summary display after error public void clear() { func_renew = true; func_info.removeAll(); metrics_info.removeAll(); } // XXXX set metrics title for compare mode to indicate base group only public void setBaseOnly(boolean baseOnly) { if (baseOnly == true) { metric_title.setText(AnLocale.getString("Metrics (base group only)")); } else { metric_title.setText(""); } metric_title.repaint(); } // Native methods from liber_dbe.so private Object[] getSummary(final long[] sel_obj, final int type, final int subtype) { synchronized (IPC.lock) { window.IPC().send("getSummary"); window.IPC().send(win_id); window.IPC().send(sel_obj); window.IPC().send(type); window.IPC().send(subtype); return (Object[]) window.IPC().recvObject(); } } private Object[] getSummaryV2(final long[] sel_obj, final int type, final int subtype) { synchronized (IPC.lock) { window.IPC().send("getSummaryV2"); window.IPC().send(0); window.IPC().send(sel_obj); window.IPC().send(type); window.IPC().send(subtype); return (Object[]) window.IPC().recvObject(); } } private Object[] getSummaryHotMarks(final long[] sel_obj, final int type) { synchronized (IPC.lock) { window.IPC().send("getSummaryHotMarks"); window.IPC().send(win_id); window.IPC().send(sel_obj); window.IPC().send(type); return (Object[]) window.IPC().recvObject(); } } } �������gprofng-gui-1.0/org/gprofng/mpmt/DisasmDisp.java����������������������������������������������������0000644�0001750�0001750�00000203723�14517772113�016647� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnTable.SelObjInfo; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Font; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelListener; import java.math.BigInteger; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JTextPane; import javax.swing.border.LineBorder; import javax.swing.text.BadLocationException; import javax.swing.text.Highlighter; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyledDocument; public class DisasmDisp extends SourceDisp { private int[] src_type; private int prevScroll = -1; private boolean inCompute = false; private int my_src_type = AnTable.AT_DIS; private int my_src_type_only = AnTable.AT_DIS_ONLY; private long lastSelObj = 0; // Constructor public DisasmDisp(final AnWindow window, final int type, final String help_id) { super(window, type, help_id); } // Constructor public DisasmDisp(final AnWindow window, final int type, final String help_id, final int ptype) { super(window, type, help_id, ptype); } // Initialize GUI components @Override protected void initComponents() { setLayout(new BorderLayout()); String acName = AnLocale.getString("Disassembly"); String acDesc = AnLocale.getString("Show disassemled code for selected function"); JLabel acLabel = new JLabel(acName, JLabel.RIGHT); table = new AnTable(type, true, true, can_sort, false, true, true, true, acName, acDesc, acLabel); table.setParent(this); acLabel.setVisible(false); // acLabel.setDisplayedMnemonic(acName.charAt(0)); table.add(acLabel); table.addAnListener(new TableHandler()); add(table, BorderLayout.CENTER); HotGapPanel hotGapPanel = new HotGapPanel(this); table.setHotGapPanel(hotGapPanel); add(hotGapPanel, BorderLayout.EAST); warningPane = new JPanel(); warningPane.setVisible(false); // warningPane.setBorder(AnVariable.textBorder); warningPane.setBorder(new LineBorder(AnEnvironment.SPLIT_PANE_BORDER_COLOR)); add(warningPane, BorderLayout.SOUTH); } // Clear display @Override public void clear() { if (table != null) { table.removeAll(); } } // Compute & update function list table @Override public void doCompute() { final long sel_obj; int new_ind; final int sort_ind; final Object[] raw_data; final String pwarnstr; final MetricLabel[] label; AnUtility.checkIfOnAWTThread(false); // Not selected if (!selected) { return; } if (inCompute) { // NM TEMPORARY should be synchronized return; } else { inCompute = true; } if (lastFilterSelection != null) { window.getSelectedObject().setSelObjV2(lastFilterSelection.id); } sel_obj = window.getSelectedObject().getSelObj(type, subtype); // sel_func = window.getSelObj(DSP_FUNCTION, 0); // if (-1 == sel_func) { long lastSelFunc = sel_func; sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) if (!forceCompute && parent_type != AnDisplay.DSP_SourceDisassembly && lastSelFunc == sel_func && lastSelObj == sel_obj) { computed = true; } if (forceCompute) { forceCompute = false; } // } if (!computed) { // need re-compute lastSelObj = sel_obj; reset(); Object[] res = setFuncData(sel_func, type, subtype); new_ind = (int) ((long[]) (res[0]))[0]; String errstr = ((String[]) (res[1]))[0]; long sf_id = ((long[]) (res[0]))[1]; String sf_name = ((String[]) (res[1]))[1]; // Update table if (errstr == null) { updateWarningPanel(); table.setViewport(); Object[][] table_data; raw_data = getFuncList(type, subtype); Object[] raw_marks = getHotMarks(type); Object[] raw_marks_inc = getHotMarksInc(type); int[][] marks = new int[2][]; marks[0] = (int[]) raw_marks[0]; marks[1] = (int[]) raw_marks[1]; int[][] marks_inc = new int[2][]; marks_inc[0] = (int[]) raw_marks_inc[0]; marks_inc[1] = (int[]) raw_marks_inc[1]; final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(type); table_data = localProcessData( mlist, raw_data); // first index is for column, second index is for rows src_type = (int[]) raw_data[raw_data.length - 1]; // AnTable.AT_SRC, DIS, QUOTE, etc. String[] hdrContent = getNames(type, 0); // name column table header contents (?) label = getSettings().getMetricsSetting().getLabel(table_data, null, type, table); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); int func_ind = (new_ind == -1) ? 0 : new_ind; new_ind = window.getSelectedObject().getSelIndex(sel_obj, type, subtype); new_ind = (new_ind == -1) ? func_ind : new_ind; table.setData(label, table_data, hdrContent, src_type, new_ind, name_col, sort_ind, marks, marks_inc); if (sel_func == 0) { window.getSelectedObject().setSelObj(new_ind, type, subtype); } } else { window.getExperimentsView().appendLog(AnLocale.getString("Error: ") + errstr); table.showMessage(errstr); } } // Update selected row new_ind = window.getSelectedObject().getSelIndex(sel_obj, type, subtype); if (new_ind == -1) { new_ind = table.getSelectedRow(); table.showSelectedRow(); window.getSelectedObject().setSelObj(new_ind, type, subtype); // if (-1 == sel_func) { // Do we need sel_func? sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) // } } else { table.setSelectedRow(new_ind); } // scroll to previous location after re-sort if (prevScroll > 0) { table.setScroll(prevScroll); prevScroll = -1; } updateGap(); // Update summary display if (parent_type != AnDisplay.DSP_SourceDisassembly) { updateSummary(new_ind); } computed = true; // pstatstr = window.getMsg(AnUtility.PSTAT_MSG); pwarnstr = window.getMsg(AnUtility.PWARN_MSG); // if (pstatstr != null) { // window.appendLog(pstatstr); // } if (pwarnstr != null) { window.showProcessorWarning(pwarnstr); } if (lastFilterSelection != null) { if (lastSelSrc == sel_src) { table.setSelectedRow(lastFilterSelection.lineno); // XXX we should not call setSelObj when we go to the Source tab window.getSelectedObject().setSelObj(lastFilterSelection.lineno, type, subtype); } lastFilterSelection = null; lastSelSrc = -1; } window .getCalledByCallsDisassemblyView() .doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) // Set toolbar and select subviews updateToolBar(); if (tailAction != null) { tailAction.tailFunction(); tailAction = null; } inCompute = false; } // Is current selected tab? public void setSelected(final boolean set) { selected = set; window.getCalledByCallsDisassemblyView().setSelected(set); } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { // Update Total value AnObject[] totals = getTotals(type, subtype); // IPC call if (totals != null) { if (MaximumValues == null) { MaximumValues = new Object[2][totals.length]; MaximumValues[1] = totals; } MaximumValues[0] = totals; } // Call super.exportAsText String text = super.exportAsText(limit, format, delimiter); return text; } // Set current func/load-object in 'selected func' & summary display private void updateSummary(final int new_ind) { // Use "AWT-EventQueue-0" thread to avoid race conditions AnUtility.dispatchOnSwingThread( new Runnable() { public void run() { int[] rows = table.getSelectedRows(); if (null != rows) { if (rows.length > 1) { // Special case for multiselection: pass only lines with my_src_type int len = 0; for (int i = 0; i < rows.length; i++) { int k = rows[i]; if (k < src_type.length) { int stype = src_type[k]; if (stype < 0) { stype = -stype; } if ((stype == my_src_type) || (stype == my_src_type_only)) { len++; } } } if ((len > 0) && (len != rows.length)) { long[] filtered_rows = new long[len]; for (int i = 0, m = 0; i < rows.length; i++) { int k = rows[i]; int stype = src_type[k]; if (stype < 0) { stype = -stype; } if ((stype == my_src_type) || (stype == my_src_type_only)) { filtered_rows[m] = rows[i]; m++; } } window.getSelectionManager().updateSelection(filtered_rows, type, subtype, 1); return; } } window.getSelectionManager().updateSelection(rows, type, subtype, 1); // } else { // no source } } }); } // Listener for updating table private final class TableHandler implements AnListener { public void valueChanged(final AnEvent event) { final int from; final int to; int stype = 0; final boolean can_nav; switch (event.getType()) { case AnEvent.EVT_SELECT: // Selecting from = event.getValue(); if (can_sort) { can_nav = true; } else { stype = src_type[from]; if (stype < 0) { stype = -stype; } can_nav = (stype == AnTable.AT_SRC) || (stype == AnTable.AT_DIS) || (stype == AnTable.AT_QUOTE); } if ((type == DSP_Source)) { deselectRaceStack(subtype); // FIXUP: REARCH window.getSourceDisassemblyView().focusInHalf(AnTable.AT_SRC); } if ((type == DSP_SourceDisassembly) || (type == DSP_Disassembly)) { if (stype == AnTable.AT_DIS) { window.getSourceDisassemblyView().focusInHalf(AnTable.AT_DIS); } else { // SOURCE window.getSourceDisassemblyView().focusInHalf(AnTable.AT_SRC); } } // Set selected object & Update summary display if (can_nav) { window.getSelectedObject().setSelObj(from, type, subtype); window.getCalledByCallsDisassemblyView().setComputed(false); window.getCalledByCallsDisassemblyView().computeOnAWorkerThread(); updateSummary(from); if (parent_type == DSP_SourceDisassembly) { window.getSourceDisassemblyView().syncHalf(AnTable.AT_SRC); } } else // in other cases (eg. AT_SRC_ONLY), just update summary { window.getCalledByCallsDisassemblyView().setComputed(false); window.getCalledByCallsDisassemblyView().computeOnAWorkerThread(); updateSummary(from); } if (parent_type == DSP_SourceDisassembly) { updateToolBar(); } break; case AnEvent.EVT_SORT: // Sorting // save current scroll location prevScroll = table.getScroll(); int func_sort_col = getFuncSortColumn(((Integer) event.getAux()).intValue()); getSettings() .getMetricsSetting() .setSortMetricByDType(this, func_sort_col, AnDisplay.DSP_Functions); break; case AnEvent.EVT_COPY_ALL: // Copy all lines copyAll(); break; case AnEvent.EVT_COPY_SEL: // Copy selected lines copySelected(); break; case AnEvent.EVT_SWITCH: // Column switching if (table != null) { table.columnsSaved = false; } from = event.getValue(); to = ((Integer) event.getAux()).intValue(); getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, type); break; } } } /* * Class to render source code for simple syntax highlighting */ static class DisRenderer extends SrcRenderer { private final String[] BRANCH_INSTRS = { "goto", // branch for java byte code "goto_w", "jsr", "jsr_w", "if_acmpeq", "if_acmpne", "if_icmpeq", "if_icmpne", "if_icmplt", "if_icmpge", "if_icmpgt", "if_icmple", "ifeq", "ifne", "iflt", "ifge", "ifgt", "ifle", "ifnonnull", "ifnull" }; private final String[] X86_BRANCH_INSTRS = { "jmp", "jno", "jb", "jnae", "jc", "jnb", "jae", "jnc", "jz", "je", "jnz", "jne", "jbe", "jna", "jnbe", "ja", "js", "jns", "jp", "jpe", "jnp", "jpo", "jl", "jnge", "jnl", "jge", "jle", "jng", "jnle", "jg", "jo", "jmpf", "loopnz", "loopne", "loopz", "loope", "loop", "jecxz", "jrcxz", "jmpe", "syscall", "sysenter", "sysexit", "rsm", "loadall" }; private static final String SPLIT_PATTERN = "[(),:* \\[\\]]"; public static final int AT_DIS = 3; protected static final int AT_DIS_ONLY = 8; protected int maxDisCachedNumber = 1; // XXXX don't cache disasm view data since there is no consistant row to content map protected int caretLinePosition = -1; protected String previousSelectedReg = ""; protected Integer previousSelectedFunction = -1; protected HashMap<Integer, HashMap<String, ArrayList<Integer>>> regsInFunction = new HashMap< Integer, HashMap< String, ArrayList<Integer>>>(); // stores for each reg which rows it's in for each function protected HashMap<Integer, DisTextMarker> disRendered = null; // stores cached DisTextMarker of each line protected HashMap<Integer, DisTextPane> disPaneCreated = null; // stores cached DisTextPane of each line protected HashMap<Long, HashMap<Integer, DisTextMarker>> disRenderedMap = new HashMap< Long, HashMap< Integer, DisTextMarker>>(); // stores cached disRendered of each selected object that has // been shown in Source View before protected HashMap<Long, HashMap<Integer, DisTextPane>> disPaneCreatedMap = new HashMap<Long, HashMap<Integer, DisTextPane>>(); protected HashMap<String, Integer> addrToRow = new HashMap<String, Integer>(); protected HashMap<Integer, String> rowToAddr = new HashMap<Integer, String>(); protected HashMap<String, Boolean> addrIsBranch = new HashMap<String, Boolean>(); protected boolean isJavaByteCode = false; protected boolean isX86 = false; protected boolean reachedMemLimit = false; protected int numRows = 0; protected final HashMap<String, Boolean> branchInstrMap; protected final HashMap<String, Boolean> x86BranchInstrMap; public DisRenderer(AnTable table) { super(table); branchInstrMap = new HashMap<String, Boolean>(); for (int i = 0; i < BRANCH_INSTRS.length; i++) { branchInstrMap.put(BRANCH_INSTRS[i], Boolean.TRUE); } x86BranchInstrMap = new HashMap<String, Boolean>(); for (int i = 0; i < X86_BRANCH_INSTRS.length; i++) { x86BranchInstrMap.put(X86_BRANCH_INSTRS[i], Boolean.TRUE); } } public boolean regEquals(String r0, String r1) { if ((r0 == null && r1 != null) || (r1 == null && r0 != null)) { return false; } else if (r0 == null && r1 == null) { return true; } String reg0 = r0.replaceFirst("%", ""); String reg1 = r1.replaceFirst("%", ""); if (reg0.equalsIgnoreCase(reg1)) { return true; } else { if (reg0.matches("[rR]([89]|[1][0-6])[bwdBWD]?") && reg1.matches("[rR]([89]|[1][0-6])[bwdBWD]?")) { String number0 = reg0.replaceFirst("[rR]", ""); number0 = number0.replaceFirst("[bwdBWD]", ""); String number1 = reg1.replaceFirst("[rR]", ""); number1 = number1.replaceFirst("[bwdBWD]", ""); return number0.equalsIgnoreCase(number1); } else if (reg0.matches("[erER]?[a-dA-D][xX]|[a-dA-D][hlHL]") && reg1.matches("[erER]?[a-dA-D][xX]|[a-dA-D][hlHL]")) { String number0 = reg0.replaceFirst("[erER]", ""); number0 = number0.replaceFirst("[xhlXHL]", ""); String number1 = reg1.replaceFirst("[erER]", ""); number1 = number1.replaceFirst("[xhlXHL]", ""); return number0.equalsIgnoreCase(number1); } else if (reg0.matches("[erER]?(SI|si|DI|di|BP|bp|SP|sp)|(SI|si|DI|di|BP|bp|SP|sp)[lL]") && reg1.matches("[erER]?(SI|si|DI|di|BP|bp|SP|sp)|(SI|si|DI|di|BP|bp|SP|sp)[lL]")) { String number0 = reg0.replaceFirst("[erER]", ""); number0 = number0.replaceFirst("[lL]", ""); String number1 = reg1.replaceFirst("[erER]", ""); number1 = number1.replaceFirst("[lL]", ""); return number0.equalsIgnoreCase(number1); } else if (reg0.matches("[xyXY](MM|mm)([0-9]|[1][0-5])") && reg1.matches("[xyXY](MM|mm)([0-9]|[1][0-5])")) { String number0 = reg0.replaceFirst("[xyXY](MM|mm)", ""); String number1 = reg1.replaceFirst("[xyXY](MM|mm)", ""); return number0.equalsIgnoreCase(number1); } return false; } } public String regFullName(final String r) { if (r == null) { return r; } String reg = r.replaceFirst("%", ""); if (reg.matches("[rR]([89]|[1][0-6])[bwdBWD]?")) { String number = reg.replaceFirst("[rR]", ""); number = number.replaceFirst("[bwdBWD]", ""); return "%r" + number; } else if (reg.matches("[erER]?[a-dA-D][xX]|[a-dA-D][hlHL]")) { isX86 = true; String number = reg.replaceFirst("[erER]", ""); number = number.replaceFirst("[xhlXHL]", ""); return "%r" + number + "x"; } else if (reg.matches("[erER]?(SI|si|DI|di|BP|bp|SP|sp)|(SI|si|DI|di|BP|bp|SP|sp)[lL]")) { String number = reg.replaceFirst("[erER]", ""); number = number.replaceFirst("[lL]", ""); return "%r" + number; } else if (reg.matches("[xyXY](MM|mm)([0-9]|[1][0-5])")) { isX86 = true; String number = reg.replaceFirst("[xyXY](MM|mm)", ""); return "%ymm" + number; } return r; } protected void renderDis( final Object[][] table_data, final int[] src_type, final long sel_instr) { tableData = table_data; srcTypeData = src_type; previousSelectedReg = ""; previousSelectedFunction = -1; // initialize or store new cached data for the selected object // cache disasm data per function since we don't have a unique id for disasm data in dbe if (disRenderedMap.size() >= maxDisCachedNumber) { // clear data cache before it gets too large disRenderedMap.clear(); disPaneCreatedMap.clear(); } disRendered = disRenderedMap.get(sel_instr); disPaneCreated = disPaneCreatedMap.get(sel_instr); if (disRendered == null || sel_instr == 0) { if (disRendered == null) { disRendered = new HashMap<Integer, DisTextMarker>(); } disRendered.clear(); regsInFunction.clear(); addrToRow.clear(); rowToAddr.clear(); addrIsBranch.clear(); isJavaByteCode = false; isX86 = false; numRows = table_data[fl_table.getNameCol()].length; for (int i = 0; i < numRows; i++) { Object value = table_data[fl_table.getNameCol()][i]; int type = src_type[i] < 0 ? (-src_type[i]) : src_type[i]; if (value instanceof String && (type == AT_DIS || type == AT_DIS_ONLY)) { if (AnMemoryManager.getInstance().checkMemoryThreshold()) { reachedMemLimit = true; break; } DisTextMarker dm = new DisTextMarker(i, ((String) value)); disRendered.put(i, dm); } } Set<Integer> rows = disRendered.keySet(); if (reachedMemLimit) { rows = new TreeSet<Integer>(); for (int i = 0; i < numRows; i++) { Object value = table_data[fl_table.getNameCol()][i]; int type = src_type[i] < 0 ? (-src_type[i]) : src_type[i]; if (value instanceof String && (type == AT_DIS || type == AT_DIS_ONLY)) { rows.add(i); } } } if (rows != null) { for (final Integer r : rows) { if (calleeInfo != null && calleeInfo.get(r) != null) { continue; // skip callsite instruction } DisTextMarker dm = disRendered.get(r); if (reachedMemLimit && dm == null) { dm = newTextMarker(r); dm.renderCode(r, true); } if (dm.addrPositions != null && !dm.addrPositions.isEmpty()) { Set<String> addrs = dm.addrPositions.keySet(); if (addrs.size() > 1) { continue; } for (final String addr : addrs) { Integer addrRow = addrToRow.get(addr); addrIsBranch.put(addr, true); String targetFunc = addrRow == null ? null : getFunction(addrRow.intValue()); String curFunc = getFunction(r.intValue()); if (targetFunc == null || curFunc == null || (!curFunc.equalsIgnoreCase(targetFunc))) { dm.replaceMarkerStyle("jmp_back", "jmp_outside"); dm.replaceMarkerStyle("jmp_other", "jmp_outside"); } } } } } // render block start addresses renderBlocks(0, table_data[fl_table.getNameCol()].length, false); disRenderedMap.put(sel_instr, disRendered); } if (disPaneCreated == null || sel_instr == 0) { if (disPaneCreated == null) { disPaneCreated = new HashMap<Integer, DisTextPane>(); } disPaneCreated.clear(); disPaneCreatedMap.put(sel_instr, disPaneCreated); } if (calleeInfo != null) { for (final Integer callsite : calleeInfo.keySet()) { DisTextMarker dm = disRendered.get(callsite); if (dm != null) { dm.isCallSite = true; } } } // add new obj to history if it's different from current if (fl_table.getNavigationHistoryPool().getHistory().enabled) { int row = fl_table.getSelectedRow(); DisTextMarker dm = disRendered.get(row); if (dm == null) { dm = newTextMarker(row); } if (dm != null) { String baseAddrStr = getRowToAddr(row, row); long fun_id = -1; if (functionId != null && row > 0 && row <= functionId.size()) { fun_id = functionId.get(row); } if (fun_id == 0) { fun_id = fl_table.getAnParent().window.getSelectedObject().getSelObjV2("FUNCTION"); } SelObjInfo cur_so = fl_table.getNavigationHistoryPool().getHistory().getCurrent(); if (cur_so == null || cur_so.id != fun_id || (cur_so.name != null && !cur_so.name.equalsIgnoreCase(baseAddrStr))) { SelObjInfo new_so = new SelObjInfo(fun_id, row, baseAddrStr); fl_table.getNavigationHistoryPool().getHistory().goToNew(new_so); } else { fl_table.getNavigationHistoryPool().getHistory().newAdded = false; } } } } private void renderBlocks( final Integer startRow, final Integer endRow, final boolean allocateMemroy) { if (allocateMemroy) { for (Integer r = startRow; r < endRow; r++) { Object value = tableData[fl_table.getNameCol()][r]; int type = srcTypeData[r] < 0 ? (-srcTypeData[r]) : srcTypeData[r]; if (!(value instanceof String && (type == AT_DIS || type == AT_DIS_ONLY))) { continue; } if (calleeInfo != null && calleeInfo.get(r) != null) { continue; // skip callsite instruction } DisTextMarker dm = disRendered.get(r); DisTextPane dt = disPaneCreated == null ? null : disPaneCreated.get(r); if (dm == null) { dm = new DisTextMarker(r, (String) value); disRendered.put(r, dm); } if (dt == null) { // only create JTextPanel when it needs to be shown if (dm != null) { dm.renderCode(r, true); } if (dm != null && calleeInfo.get(r) != null) { dm.isCallSite = true; } } if (dm.addrPositions != null && !dm.addrPositions.isEmpty()) { Set<String> addrs = dm.addrPositions.keySet(); if (addrs.size() > 1) { continue; } for (final String addr : addrs) { Integer addrRow = getAddrToRow(addr, r); addrIsBranch.put(addr, true); String targetFunc = addrRow == null ? null : getFunction(addrRow.intValue()); String curFunc = getFunction(r.intValue()); if (targetFunc == null || curFunc == null || (!curFunc.equalsIgnoreCase(targetFunc))) { dm.replaceMarkerStyle("jmp_back", "jmp_outside"); dm.replaceMarkerStyle("jmp_other", "jmp_outside"); } } } } } // render block start addresses if (!isJavaByteCode) { int funcStart = 0; int seenCB = 0; for (int i = startRow; i < endRow; i++) { Object value = tableData[fl_table.getNameCol()][i]; int type = srcTypeData[i] < 0 ? (-srcTypeData[i]) : srcTypeData[i]; if (type == AnTable.AT_FUNC) { funcStart = 1; seenCB = 0; } if (value instanceof String && (type == AT_DIS || type == AT_DIS_ONLY)) { DisTextMarker dm = disRendered.get(i); DisTextPane dt = disPaneCreated == null ? null : disPaneCreated.get(i); if (dm == null && allocateMemroy) { dm = new DisTextMarker(i, (String) value); disRendered.put(i, dm); } if (dt == null && allocateMemroy) { // only create JTextPanel when it needs to be shown if (dm != null) { dm.renderCode(i, true); } if (dm != null && calleeInfo.get(i) != null) { dm.isCallSite = true; } } if (i > 0) { int type_pre = srcTypeData[i - 1] < 0 ? (-srcTypeData[i - 1]) : srcTypeData[i - 1]; if (type_pre == AnTable.AT_FUNC) { funcStart = 1; seenCB = 0; } } if (dm != null) { String addr = dm.getAddr(); Boolean isBranch = addrIsBranch.get(addr); if (isBranch != null && isBranch == true) { dm.replaceMarkerStyle("address", "block_start_address"); } if (dm.hasCall || dm.hasBranch || dm.isRet) { seenCB = 1; } } } } } } public DisTextPane getDisTextPane(final String content, final JComponent cmp, final int row) { Integer function = getFunctionBaseRowWhenCompare(row); if (functionCallerCalleeAdded.get(function) == null) { addFunctionByRow(function); } DisTextMarker dm = disRendered.get(row); if (dm == null) { renderBlocks( row - 100 > 0 ? row - 100 : 0, row + 100 > tableData[fl_table.getNameCol()].length ? tableData[fl_table.getNameCol()].length : row + 100, true); } dm = disRendered.get(row); DisTextPane dt = disPaneCreated.get(row); if (dt == null) { // only create JTextPanel when it needs to be shown if (dm != null) { dm.renderCode(row, true); } if (dm != null && calleeInfo.get(row) != null) { dm.isCallSite = true; } dt = new DisTextPane(content, cmp, dm); disPaneCreated.put(row, dt); } final int[] anno_set = fl_table.getAnParent().window.getSettings().getSourceDisassemblySetting().get(); boolean scope_only = false; if (anno_set.length > 8) { // To accomodate older configurations that don't have scope... scope_only = (anno_set[8] != 0); } if (scope_only || (function != null && function.equals(previousSelectedFunction))) { dt.updateRegSelection(previousSelectedReg); } HashMap<String, ArrayList<Integer>> regRows = regsInFunction.get(function); if (regRows == null) { regRows = new HashMap<String, ArrayList<Integer>>(); regsInFunction.put(function, regRows); } if (dm != null) { Set<String> regs = dm.regPositions.keySet(); if (regs != null) { for (final String r : regs) { if (scope_only) { for (Map.Entry entry : regsInFunction.entrySet()) { HashMap<String, ArrayList<Integer>> regMap = (HashMap<String, ArrayList<Integer>>) entry.getValue(); ArrayList<Integer> list = regMap.get(regFullName(r)); if (list == null) { list = new ArrayList<Integer>(); regMap.put(regFullName(r), list); } if (!list.contains(row)) { list.add(row); } } } else { ArrayList<Integer> list = regRows.get(regFullName(r)); if (list == null) { list = new ArrayList<Integer>(); regRows.put(regFullName(r), list); } if (!list.contains(row)) { list.add(row); } } } } } return dt; } protected final class DisTextPane extends JTextPane { private DisTextMarker textMarker = null; private String selectedReg = null; private UnderlineHighlighter highlighter = new UnderlineHighlighter(AnVariable.OPCODE_COLOR); private Highlighter.HighlightPainter painter = highlighter.new UnderlineHighlightPainter(AnVariable.OPCODE_COLOR); public DisTextPane(final String content, final JComponent cmp, final DisTextMarker tm) { textMarker = tm; setEditable(false); setForeground(cmp.getForeground()); setBackground(cmp.getBackground()); setHighlighter(highlighter); Style style1 = addStyle("opcode", null); StyleConstants.setForeground(style1, AnVariable.OPCODE_COLOR); Style style2 = addStyle("oprandreg", null); StyleConstants.setForeground(style2, AnVariable.OPRANDREG_COLOR); Style style3 = addStyle("oprandvalue", null); StyleConstants.setForeground(style3, AnVariable.OPRANDVALUE_COLOR); Style style4 = addStyle("address", null); // StyleConstants.setBold(style4, true); Style style5 = addStyle("selected", null); StyleConstants.setBackground(style5, AnVariable.REGSEL_COLOR); Style style6 = addStyle("defaultbackground", null); StyleConstants.setBackground(style6, cmp.getBackground()); Style style7 = addStyle("jmp_other", null); StyleConstants.setUnderline(style7, true); StyleConstants.setForeground(style7, AnVariable.JMPOTHER_COLOR); Style style8 = addStyle("jmp_back", null); StyleConstants.setUnderline(style8, true); StyleConstants.setForeground(style8, AnVariable.JMPBACK_COLOR); Style style9 = addStyle("jmp_outside", null); StyleConstants.setUnderline(style9, true); StyleConstants.setForeground(style9, AnVariable.JMPOUTSIDE_COLOR); Style style10 = addStyle("line_no", null); // StyleConstants.setBold(style10, true); StyleConstants.setUnderline(style10, true); Style style11 = addStyle("callsite", null); StyleConstants.setUnderline(style11, true); StyleConstants.setBold(style11, true); Style style12 = addStyle("line_no_bold", null); // StyleConstants.setForeground(style12, AnVariable.LINENO_COLOR_BOLD); StyleConstants.setBold(style12, true); StyleConstants.setUnderline(style12, true); Style style13 = addStyle("block_start_address", null); StyleConstants.setBold(style13, true); StyledDocument doc = getStyledDocument(); try { doc.insertString(0, content, null); if (textMarker == null) { return; } for (int i = 0; i < textMarker.marker.size(); i++) { int from = textMarker.marker.get(i).from; int length = textMarker.marker.get(i).length; String style = textMarker.marker.get(i).style; doc.setCharacterAttributes(from, length, getStyle(style), true); } if (textMarker.isCallSite) { highlighter.addHighlight(textMarker.opcodeBegin, textMarker.opcodeEnd, painter); } } catch (BadLocationException e) { } final MouseMotionListener[] ls = getMouseMotionListeners(); for (final MouseMotionListener l : ls) { removeMouseMotionListener(l); } DisTextPaneMouseAdapter ma = new DisTextPaneMouseAdapter(cmp, this); DisTextPaneMouseMotionAdapter mam = new DisTextPaneMouseMotionAdapter(cmp, this); DisTextPaneMouseWheelAdapter maw = new DisTextPaneMouseWheelAdapter(cmp, this); SrcTextPaneKeyAdapter ka = new SrcTextPaneKeyAdapter(cmp); this.addMouseListener(ma); this.addMouseMotionListener(mam); this.addMouseWheelListener(maw); addKeyListener(ka); this.setDragEnabled(false); // this.setFont(cmp.getFont()); this.setFont(new Font(Font.MONOSPACED, Font.PLAIN, cmp.getFont().getSize())); this.setBorder(AnVariable.labelBorder); this.setForeground(cmp.getForeground()); this.setBackground(cmp.getBackground()); this.setOpaque(false); setEditable(false); } public void updateRegSelection(String reg) { if (selectedReg == null) { selectedReg = reg; } else if (regEquals(selectedReg, reg)) { return; } else { // remove previous highlightings if (textMarker == null) { return; } ArrayList<Position> list = textMarker.regPositions == null ? null : textMarker.regPositions.get(regFullName(selectedReg)); if (list != null) { StyledDocument doc = getStyledDocument(); for (int i = 0; i < list.size(); i++) { int start = list.get(i).start; int length = list.get(i).length; doc.setCharacterAttributes(start, length, getStyle("oprandreg"), true); } } selectedReg = reg; } if (textMarker == null) { return; } ArrayList<Position> list = textMarker.regPositions == null ? null : textMarker.regPositions.get(regFullName(reg)); if (list != null) { StyledDocument doc = getStyledDocument(); for (int i = 0; i < list.size(); i++) { int start = list.get(i).start; int length = list.get(i).length; doc.setCharacterAttributes(start, length, getStyle("selected"), true); } } } public String getReg(int pos) { return textMarker.regMap.get(pos); } public String getAddr(int pos) { return textMarker.addrMap.get(pos); } public String getLineNo(int pos) { return textMarker.lineNoMap.get(pos); } } public final class Position { int start; int length; public Position(int s, int l) { start = s; length = l; } } protected final class DisTextPaneMouseMotionAdapter extends MouseMotionAdapter { private Component parentComponent; private JTextPane pane; public DisTextPaneMouseMotionAdapter(JComponent cmp, JTextPane p) { pane = p; parentComponent = cmp; } public void mouseMoved(MouseEvent e) {} } protected final class DisTextPaneMouseWheelAdapter implements MouseWheelListener { private Component parentComponent; private JTextPane pane; public DisTextPaneMouseWheelAdapter(JComponent cmp, JTextPane p) { pane = p; parentComponent = cmp; } public void mouseWheelMoved(MouseWheelEvent e) { propagateToTable(e, true, parentComponent); } } protected final class DisTextPaneMouseAdapter extends MouseAdapter { private Component parentComponent; private JTextPane pane; public DisTextPaneMouseAdapter(JComponent cmp, JTextPane p) { pane = p; parentComponent = cmp; } public void mouseClicked(MouseEvent e) { propagateToTable(e, true, parentComponent); } public void mousePressed(MouseEvent e) { caretLinePosition = pane.getCaretPosition(); } public void mouseReleased(MouseEvent e) {} public void mouseEntered(MouseEvent e) {} public void mouseExited(MouseEvent e) {} } protected final class DisTextMarker { public HashMap<String, ArrayList<Position>> regPositions = new HashMap<String, ArrayList<Position>>(); public HashMap<Integer, String> regMap = new HashMap<Integer, String>(); public HashMap<String, ArrayList<Position>> addrPositions = new HashMap<String, ArrayList<Position>>(); public HashMap<Integer, String> addrMap = new HashMap<Integer, String>(); public HashMap<String, ArrayList<Position>> lineNoPositions = new HashMap<String, ArrayList<Position>>(); public HashMap<Integer, String> lineNoMap = new HashMap<Integer, String>(); public int opcodeBegin = -1; public int opcodeEnd = -1; public boolean isCallSite = false; public boolean hasCall = false; public boolean hasBranch = false; public boolean isBranchTargetMarker = false; public boolean isRet = false; public boolean isNop = false; protected final class Highlighter { public int from; public int length; public String style; public Highlighter(int f, int l, String s) { from = f; length = l; style = s; } } public ArrayList<Highlighter> marker = new ArrayList<Highlighter>(); private String text = ""; private int curRow = -1; public DisTextMarker(final int row, final String content) { text = content; curRow = row; renderCode(row, false); } public DisTextMarker(final int row, final String content, final boolean doWork) { text = content; curRow = row; if (doWork) { renderCode(row, false); } } public int getRow() { return curRow; } public String getAddr() { String[] words = text.split(SPLIT_PATTERN); int numWords = 0; for (int i = 0; i < words.length; i++) { if (words[i].length() == 0) { } else { numWords++; if (numWords == 2) { return addrStripZero(words[i]); } } } return null; } public void replaceMarkerStyle(String oldStyle, String newStyle) { for (int i = 0; i < marker.size(); i++) { if (marker.get(i).style.equalsIgnoreCase(oldStyle)) { marker.get(i).style = newStyle; } } } public String addrStripZero(final String addr) { if (addr == null) { return addr; } int i = 0; for (i = 0; i < addr.length(); i++) { if (addr.charAt(i) != '0') { break; } } if (i == addr.length()) { i--; } String stripped = addr.substring(i); if (!isJavaByteCode) { return stripped; } else { try { long funcBase = getFunctionBaseRowWhenCompare(curRow) * 100; // XXXX ugly assumption that the longest java bytecode instruction is 100 // bytes BigInteger addrValue = new BigInteger(stripped, 16); BigInteger fBase = BigInteger.valueOf(funcBase); addrValue = fBase.add(addrValue); return addrValue.toString(16); } catch (NumberFormatException e) { return stripped; } } } public void renderCode(final int row, final boolean allocateMemory) { String[] words = text.split(SPLIT_PATTERN); int numWords = 0; int curPos = 0; int hexPos = -1; int hexIdx = -1; boolean seenOpcode = false; boolean seenCall = false; boolean seenBranch = false; String curAddr = null; for (int i = 0; i < words.length; i++) { if (words[i].length() == 0) { } else { numWords++; if (numWords == 1 && allocateMemory) { if (calleeInfo != null && calleeInfo.get(row) != null) { // it's a callsite marker.add(new Highlighter(curPos, words[i].length(), "line_no_bold")); } else { marker.add(new Highlighter(curPos, words[i].length(), "line_no")); } if (!words[i].equals("?")) { for (int temp = curPos; temp < curPos + words[i].length(); temp++) { lineNoMap.put(temp, words[i]); } } } else if (numWords == 2) { if (!allocateMemory) { marker.add(new Highlighter(curPos, words[i].length(), "address")); } if (!isJavaByteCode) { if (words[i].equalsIgnoreCase( "00000000")) { // XXXX this is ugly, need a better solution to detect java byte // code isJavaByteCode = true; } } curAddr = addrStripZero(words[i]); if (!words[i].equals("?") && !allocateMemory) { addrToRow.put(curAddr, row); rowToAddr.put(row, curAddr); } } else if (numWords == 3) { if (words[i].length() == 2 && words[i].matches("[0-9a-fA-F][0-9a-fA-F]") && !(curPos + words[i].length() + 1 < text.length() && text.charAt(curPos + words[i].length()) == ',' && text.charAt(curPos + words[i].length() + 1) != ' ')) { // if it seems like a 2 digit hex number we skip it unless there is no opcode found numWords--; hexPos = curPos; hexIdx = i; } else if ((words[i].length() >= 2 && words[i].matches("[0-9._a-zA-Z]*") && !words[i].matches("0x[0-9a-fA-F]*")) || (words[i].length() == 1 && words[i].matches("[a-zA-Z]"))) { if (!allocateMemory) { marker.add(new Highlighter(curPos, words[i].length(), "opcode")); } opcodeBegin = (opcodeBegin == -1) ? curPos : opcodeBegin; opcodeEnd = (opcodeEnd < (curPos + words[i].length())) ? (curPos + words[i].length()) : opcodeEnd; seenOpcode = true; if (words[i].equalsIgnoreCase("call")) { seenCall = true; hasCall = true; } else if (branchInstrMap.get(words[i].toLowerCase()) != null || (isX86 && x86BranchInstrMap.get(words[i].toLowerCase()) != null)) { seenBranch = true; hasBranch = true; } if ((curPos + words[i].length() + 1 < text.length() && text.charAt(curPos + words[i].length()) == ',' && text.charAt(curPos + words[i].length() + 1) != ' ') || ((words[i].equalsIgnoreCase("lock") // lock prefix for x86 || words[i].equalsIgnoreCase("rep") // rep* prefix of x86 || words[i].equalsIgnoreCase("repe") || words[i].equalsIgnoreCase("repz") || words[i].equalsIgnoreCase("repne") || words[i].equalsIgnoreCase("repnz")) && curPos + words[i].length() + 1 < text.length() && text.charAt(curPos + words[i].length()) == ' ' && text.charAt(curPos + words[i].length() + 1) != ' ')) { numWords--; } if (words[i].toLowerCase().contains("ret")) { isRet = true; } else if (words[i].equalsIgnoreCase("nop")) { isNop = true; } } else if (words[i].equalsIgnoreCase("<branch") && words[i + 1].equalsIgnoreCase("target>")) { isBranchTargetMarker = true; } } else if (words[i].charAt(0) == '$') { if (!allocateMemory) { marker.add(new Highlighter(curPos, words[i].length(), "oprandvalue")); } } else if (words[i].charAt(0) == '%') { if (!allocateMemory) { marker.add(new Highlighter(curPos, words[i].length(), "oprandreg")); } if (allocateMemory) { addRegPosition(words[i], curPos, words[i].length()); for (int temp = curPos; temp < curPos + words[i].length(); temp++) { regMap.put(temp, words[i]); } } else if (!isX86) { regFullName(words[i]); // detect whether it's X86 } } else if (calleeInfo != null && calleeInfo.get(row) != null) { // it's a callsite if (words[i].charAt(0) == '0' && words[i].length() > 2 && words[i].charAt(1) == 'x' && ((curPos - 2 >= 0 && curPos + words[i].length() + 1 < text.length() && text.charAt(curPos - 2) == '[' // [ addr ] or [ addr, .-offset] for x86 && (text.charAt(curPos + words[i].length() + 1) == ']' || text.charAt(curPos + words[i].length() + 1) == ' ')) || ((seenCall || seenBranch) && curPos - 1 >= 0 && text.charAt(curPos - 1) != '*'))) { String style = "callsite"; String newAddr = words[i].substring(2); String realAddr = addrStripZero(newAddr); marker.add(new Highlighter(curPos, words[i].length(), style)); addAddrPosition(realAddr, curPos, words[i].length()); if (allocateMemory) { for (int temp = curPos; temp < curPos + words[i].length(); temp++) { addrMap.put(temp, realAddr); } } hasBranch = true; } } else if (!seenCall && words[i].charAt(0) == '0' && words[i].length() > 2 && words[i].charAt(1) == 'x' && ((curPos - 2 >= 0 && curPos + words[i].length() + 1 < text.length() && text.charAt(curPos - 2) == '[' // [ addr ] or [ addr, .-offset] for x86 && (text.charAt(curPos + words[i].length() + 1) == ']' || text.charAt(curPos + words[i].length() + 1) == ' ')) || (seenBranch && (curPos - 2 < 0 || text.charAt(curPos - 2) != ',' // ingnore midle operand || curPos + words[i].length() >= text.length() || text.charAt(curPos + words[i].length()) != ',') && curPos - 1 >= 0 && text.charAt(curPos - 1) != '*'))) { String newAddr = words[i].substring(2); String realAddr = addrStripZero(newAddr); BigInteger realAddrNum = new BigInteger(realAddr, 16); BigInteger curAddrNum = new BigInteger(curAddr, 16); String style = null; if (realAddrNum.compareTo(curAddrNum) > 0) { style = "jmp_other"; } else { style = "jmp_back"; } if (!allocateMemory) { marker.add(new Highlighter(curPos, words[i].length(), style)); } addAddrPosition(realAddr, curPos, words[i].length()); if (allocateMemory) { for (int temp = curPos; temp < curPos + words[i].length(); temp++) { addrMap.put(temp, realAddr); } } } } if (i < words.length - 1) { curPos += words[i].length() + 1; } } if (!seenOpcode && hexPos != -1) { marker.add(new Highlighter(hexPos, words[hexIdx].length(), "opcode")); opcodeBegin = (opcodeBegin == -1) ? curPos : opcodeBegin; opcodeEnd = (opcodeEnd < (curPos + words[hexIdx].length())) ? (curPos + words[hexIdx].length()) : opcodeEnd; seenOpcode = true; seenBranch = false; int i = hexIdx; for (i = hexIdx + 1; i < words.length; i++) { if (words[i].length() != 0 && words[i].charAt(0) == '0' && words[i].length() > 2 && words[i].charAt(1) == 'x' && seenBranch) { String newAddr = words[i].substring(2); String realAddr = addrStripZero(newAddr); BigInteger realAddrNum = new BigInteger(realAddr, 16); BigInteger curAddrNum = new BigInteger(curAddr, 16); String style = null; if (realAddrNum.compareTo(curAddrNum) > 0) { style = "jmp_other"; } else { style = "jmp_back"; } if (!allocateMemory) { marker.add(new Highlighter(curPos, words[i].length(), style)); } addAddrPosition(realAddr, curPos, words[i].length()); if (allocateMemory) { for (int temp = curPos; temp < curPos + words[i].length(); temp++) { addrMap.put(temp, realAddr); } } break; } } } } private void addRegPosition(String reg, int start, int length) { ArrayList<Position> positions = regPositions.get(regFullName(reg)); if (positions == null) { positions = new ArrayList<Position>(); regPositions.put(regFullName(reg), positions); } positions.add(new Position(start, length)); } private void addAddrPosition(String realAddr, int start, int length) { ArrayList<Position> positions = addrPositions.get(realAddr); if (positions == null) { positions = new ArrayList<Position>(); if (!realAddr.equals("?")) { addrPositions.put(realAddr, positions); } } positions.add(new Position(start, length)); } } private void clearSelectedRegs() { final int[] anno_set = fl_table.getAnParent().window.getSettings().getSourceDisassemblySetting().get(); boolean scope_only = false; if (anno_set.length > 8) { // To accomodate older configurations that don't have scope... scope_only = (anno_set[8] != 0); } if (scope_only) { for (Map.Entry entry : regsInFunction.entrySet()) { HashMap<String, ArrayList<Integer>> oldMap = (HashMap<String, ArrayList<Integer>>) entry.getValue(); ArrayList<Integer> oldList = null; if (oldMap != null) { oldList = oldMap.get(regFullName(previousSelectedReg)); } if (oldList != null) { for (final int r : oldList) { DisTextPane oldDt = disPaneCreated.get(r); if (oldDt != null) { oldDt.updateRegSelection(null); } } } } previousSelectedFunction = -1; previousSelectedReg = ""; return; } HashMap<String, ArrayList<Integer>> oldMap = regsInFunction.get(previousSelectedFunction); ArrayList<Integer> oldList = null; if (oldMap != null) { oldList = oldMap.get(regFullName(previousSelectedReg)); } if (oldList != null) { for (final int r : oldList) { DisTextPane oldDt = disPaneCreated.get(r); if (oldDt != null) { oldDt.updateRegSelection(null); } } } previousSelectedFunction = -1; previousSelectedReg = ""; } protected void updateSelectedRegs(int row) { DisTextPane dt = disPaneCreated.get(row); if (dt != null) { String reg = dt.getReg(caretLinePosition); if (reg != null) { final int[] anno_set = fl_table.getAnParent().window.getSettings().getSourceDisassemblySetting().get(); boolean scope_only = false; if (anno_set.length > 8) { // To accomodate older configurations that don't have scope... scope_only = (anno_set[8] != 0); } if (scope_only) { if (!regEquals(reg, previousSelectedReg)) { clearSelectedRegs(); Integer function = -1; for (Map.Entry entry : regsInFunction.entrySet()) { HashMap<String, ArrayList<Integer>> regMap = (HashMap<String, ArrayList<Integer>>) entry.getValue(); ArrayList<Integer> newList = regMap.get(regFullName(reg)); if (newList != null) { for (final int r : newList) { DisTextPane newDt = disPaneCreated.get(r); if (newDt != null) { newDt.updateRegSelection(reg); } } } function = (Integer) entry.getKey(); } previousSelectedReg = reg; previousSelectedFunction = function; } } else { Integer function = getFunctionBaseRowWhenCompare(row); if (function != null && (!regEquals(reg, previousSelectedReg) || !function.equals(previousSelectedFunction))) { clearSelectedRegs(); ArrayList<Integer> newList = regsInFunction.get(function).get(regFullName(reg)); if (newList != null) { for (final int r : newList) { DisTextPane newDt = disPaneCreated.get(r); if (newDt != null) { newDt.updateRegSelection(reg); } } } previousSelectedReg = reg; previousSelectedFunction = function; } } } else { clearSelectedRegs(); } } else { clearSelectedRegs(); } fl_table.repaint(); } protected boolean goToAddr(int row) { DisTextPane dt = disPaneCreated.get(row); if (dt != null) { String addr = dt.getAddr(caretLinePosition); if (addr == null && calleeInfo != null && calleeInfo.get(row) != null && calleeInfo.get(row).size() > 0 && (caretLinePosition >= dt.textMarker.opcodeBegin && caretLinePosition < dt.textMarker.opcodeEnd)) { for (final String key : dt.textMarker.addrPositions.keySet()) { addr = key; } } if (addr != null) { Integer targetRowObj = getAddrToRow(addr, row); if (targetRowObj != null) { int targetRow = targetRowObj.intValue(); // add new obj to history if it's different from current fl_table.getNavigationHistoryPool().getHistory().goToDisNew(row); fl_table.getNavigationHistoryPool().getHistory().enabled = false; fl_table.setSelectedRow(targetRow); fl_table.getNavigationHistoryPool().getHistory().enabled = true; fl_table.fireAnEvent(new AnEvent(fl_table, AnEvent.EVT_SELECT, targetRow, null)); // add new obj to history if it's different from current fl_table.getNavigationHistoryPool().getHistory().goToDisNew(targetRow); fl_table.getAnParent().updateToolBar(); return true; } } } return false; } protected void goToCallee(int row, MouseEvent e) { if (calleeInfo == null || calleeInfo.get(row) == null) { return; } DisTextPane dt = disPaneCreated.get(row); if (dt != null) { String addr = dt.getAddr(caretLinePosition); if (addr != null || (caretLinePosition >= dt.textMarker.opcodeBegin && caretLinePosition < dt.textMarker.opcodeEnd)) { if (calleeInfo.get(row).size() > 1) { // pop up context menu JPopupMenu popup = fl_table.getMenuListener().initPopup(e); if (popup != null) { popup.show(e.getComponent(), e.getX(), e.getY()); boolean pressDown = false; for (int i = 0; i < 3; i++) { // XXXX ugly assumption that the "show callee dis" is the 3rd item if (!popup.getComponent(i).isEnabled()) { continue; } popup.dispatchEvent( new KeyEvent(popup, KeyEvent.KEY_PRESSED, 0, 0, KeyEvent.VK_DOWN, '\0')); pressDown = true; } if (pressDown) { popup.dispatchEvent( new KeyEvent(popup, KeyEvent.KEY_PRESSED, 0, 0, KeyEvent.VK_RIGHT, '\0')); } } } else { long funcId = calleeInfo.get(row).get(0).id; // add new obj to history if it's different from current fl_table.getNavigationHistoryPool().getHistory().goToDisNew(row); // change selected object fl_table.getAnParent().window.getSelectedObject().setSelObjV2(funcId); fl_table.getAnParent().setComputed(false); fl_table.getAnParent().computeOnAWorkerThread(); fl_table.updateAnTable(AnTable.STR_ACTION_SHOW_CALLEE_DISASM); } } } } protected void goToSrcLine(int row) { DisTextPane dt = disPaneCreated.get(row); if (dt != null) { String ln = dt.getLineNo(caretLinePosition); if (ln != null) { int targetRow = getRowByLineNo(Integer.parseInt(ln.trim())); if (targetRow != -1) { // add new obj to history if it's different from current fl_table.getNavigationHistoryPool().getHistory().goToDisNew(row); fl_table.getNavigationHistoryPool().getHistory().enabled = false; fl_table.setSelectedRow(targetRow); fl_table.getNavigationHistoryPool().getHistory().enabled = true; fl_table.fireAnEvent(new AnEvent(fl_table, AnEvent.EVT_SELECT, targetRow, null)); // add new obj to history if it's different from current fl_table.getNavigationHistoryPool().getHistory().goToDisNew(targetRow); fl_table.getAnParent().updateToolBar(); } } } } protected DisTextMarker newTextMarker(int i) { DisTextMarker dm = null; if (tableData == null || fl_table == null || srcTypeData == null || fl_table.getNameCol() >= tableData.length || i >= tableData[fl_table.getNameCol()].length || i < 0) { return dm; } Object value = tableData[fl_table.getNameCol()][i]; int type = srcTypeData[i] < 0 ? (-srcTypeData[i]) : srcTypeData[i]; if (value instanceof String && (type == AT_DIS || type == AT_DIS_ONLY)) { dm = new DisTextMarker(i, ((String) value), false); } return dm; } public Integer getAddrToRow(String addr) { int base_row = fl_table.getSelectedRow(); return getAddrToRow(addr, base_row); } public Integer getAddrToRow(String addr, int base_row) { Integer row = addrToRow.get(addr); if (row != null || !reachedMemLimit) { return row; } else { // find row row = null; DisTextMarker dm = disRendered.get(base_row); if (dm == null) { dm = newTextMarker(base_row); } String base_addr = dm.getAddr(); BigInteger baseAddrNum = new BigInteger(base_addr, 16); BigInteger curAddrNum = new BigInteger(addr, 16); if (baseAddrNum.compareTo(curAddrNum) > 0) { for (int i = base_row; i > 0; i--) { dm = disRendered.get(i); if (dm == null) { dm = newTextMarker(i); } if (dm != null) { String cur_addr = dm.getAddr(); if (cur_addr.equalsIgnoreCase(addr)) { return i; } } } } else if (baseAddrNum.compareTo(curAddrNum) < 0) { for (int i = base_row; i < numRows; i++) { dm = disRendered.get(i); if (dm == null) { dm = newTextMarker(i); } if (dm != null) { String cur_addr = dm.getAddr(); if (cur_addr.equalsIgnoreCase(addr)) { return i; } } } } else { return base_row; } if (row == null) { if (baseAddrNum.compareTo(curAddrNum) < 0) { for (int i = base_row; i > 0; i--) { dm = disRendered.get(i); if (dm == null) { dm = newTextMarker(i); } if (dm != null) { String cur_addr = dm.getAddr(); if (cur_addr.equalsIgnoreCase(addr)) { return i; } } } } else if (baseAddrNum.compareTo(curAddrNum) > 0) { for (int i = base_row; i < numRows; i++) { dm = disRendered.get(i); if (dm == null) { dm = newTextMarker(i); } if (dm != null) { String cur_addr = dm.getAddr(); if (cur_addr.equalsIgnoreCase(addr)) { return i; } } } } } return row; } } public String getRowToAddr(int row) { int base_row = fl_table.getSelectedRow(); return getRowToAddr(row, base_row); } public String getRowToAddr(int row, int base_row) { String addr = rowToAddr.get(row); if (addr != null || !reachedMemLimit) { return addr; } else { // find addr addr = null; DisTextMarker dm = disRendered.get(base_row); if (dm == null) { dm = newTextMarker(base_row); } if (base_row > row) { for (int i = base_row; i > 0; i--) { dm = disRendered.get(i); if (dm == null) { dm = newTextMarker(i); } if (dm != null) { int cur_row = dm.getRow(); if (cur_row == row) { return dm.getAddr(); } } } } else if (base_row < row) { for (int i = base_row; i < numRows; i++) { dm = disRendered.get(i); if (dm == null) { dm = newTextMarker(i); } if (dm != null) { int cur_row = dm.getRow(); if (cur_row == row) { return dm.getAddr(); } } } } else { return dm == null ? null : dm.getAddr(); } return addr; } } } } ���������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/CallerCalleesView.java���������������������������������������������0000644�0001750�0001750�00000177002�14517772113�020135� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.AnDisplay.DSP_Callees; import static org.gprofng.mpmt.AnDisplay.DSP_CallerCalleeSelf; import static org.gprofng.mpmt.AnDisplay.DSP_Callers; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.util.gui.AnSplitPaneInternal; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; import java.util.Vector; import javax.accessibility.AccessibleContext; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; public final class CallerCalleesView extends FuncListDisp implements ExportSupport, AnChangeListener { private static final int CALLER_MIN_HEIGHT = 80; private static final int CALLEE_MIN_HEIGHT = 60; private AnTable caller, func_item, callee; private Object[][] caller_data = null; private Object[][] func_data = null; private Object[][] callee_data = null; private LocalProcessData caller_data_lpd; private LocalProcessData func_data_lpd; private LocalProcessData callee_data_lpd; private String acNameT1; private String acDescT1; private String acNameT2; private String acDescT2; private String acNameT3; private String acDescT3; private long[] ids_callers = null; private long[] ids_callees = null; private long[] ids_cstack = null; private String[] ids_names = null; private CC_CallStack cc_callstack = new CC_CallStack(); private CallStackToolbarHandler CS_ControlPanel; private boolean singleFunctionMode = false; // Interface strings final String mlistStr = "MET_CALL"; final String typeStrFunc = "FUNCTION"; final String subtypeStr = "0"; final String stab_callers = "CALLERS"; final String stab_callees = "CALLEES"; final String stab_self = "SELF"; // Constructor public CallerCalleesView() { super(AnWindow.getInstance(), AnDisplay.DSP_Callers, 0, AnVariable.HELP_TabsCallersCallees); setAccessibility(AnLocale.getString("Callers and callees of the selected function")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("CallerCalleesView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void requestFocus() { if (caller != null) { caller.requestFocus(); } } @Override public JPanel getToolbarPanel() { return null; } // Initialize GUI components @Override protected void initComponents() { final JPanel pcaller, pfunc_item, pcallee; JLabel label_callers, label_function, label_callees; JLabel label_callers_text, label_function_text, label_callees_text; final JSplitPane split_pane_1; final JSplitPane split_pane_2; Dimension msize; setLayout(new BorderLayout()); // Create table names and descriptions acNameT1 = AnLocale.getString("Callers Table"); acDescT1 = AnLocale.getString("Callers Table (shows functions that call selected function)"); acNameT2 = AnLocale.getString("Self Function Table"); acDescT2 = AnLocale.getString("Self Function Table (shows selected function)"); acNameT3 = AnLocale.getString("Callees Table"); acDescT3 = AnLocale.getString( "Callers Table (shows functions that are called from selected function)"); // Create lables label_callers = new JLabel(AnUtility.calr_icon); label_function = new JLabel(AnUtility.func_icon); // label_function = new JLabel(AnUtility.attr_icon); label_callees = new JLabel(AnUtility.cale_icon); label_callers_text = new JLabel("1"); label_function_text = new JLabel("2"); label_callees_text = new JLabel("3"); // Create tables caller = new AnTable( DSP_Callers, true, true, true, false, false, false, true, acNameT1, acDescT1, label_callers_text); table = caller; caller.setParent((AnDisplay) this); AccessibleContext context = caller.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Callers")); context.setAccessibleDescription(AnLocale.getString("Callers")); caller.addAnListener(new TableHandler()); if (singleFunctionMode == true) { func_item = new AnTable( DSP_CallerCalleeSelf, false, false, true, true, false, true, false, acNameT2, acDescT2, label_function_text); func_item.setParent((AnDisplay) this); func_item.addAnListener(new TableHandler()); context = func_item.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Self function")); context.setAccessibleDescription(AnLocale.getString("Self function")); func_item.setHeader(caller); } else { func_item = new AnTable( DSP_CallerCalleeSelf, false, false, true, false, false, false, false, acNameT2, acDescT2, label_function_text); func_item.setParent((AnDisplay) this); func_item.addAnListener(new TableHandler()); context = func_item.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Stack Fragment")); context.setAccessibleDescription(AnLocale.getString("Stack Fragment")); func_item.setHeader(caller); } callee = new AnTable( DSP_Callees, false, false, true, false, true, false, false, acNameT3, acDescT3, label_callees_text); callee.setParent((AnDisplay) this); context = callee.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Callees")); context.setAccessibleDescription(AnLocale.getString("Callees")); callee.setHeader(caller); callee.addAnListener(new TableHandler()); // Set header icons & tooltips pcaller = new JPanel(new BorderLayout()); label_callers.setToolTipText(AnLocale.getString("Callers") + " (Alt-1)"); label_callers_text.setText("1"); label_callers_text.setVisible(false); label_callers_text.setDisplayedMnemonic(KeyEvent.VK_1); context = label_callers.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Callers")); context.setAccessibleDescription(AnLocale.getString("Callers")); label_callers.setBorder(new EmptyBorder(40, AnVariable.sizeIcon, 0, AnVariable.sizeIcon)); pcaller.add(label_callers_text, BorderLayout.WEST); pcaller.add(label_callers, BorderLayout.WEST); pcaller.add(caller, BorderLayout.CENTER); pfunc_item = new JPanel(new BorderLayout()); JPanel pfunc_internal_panel = new JPanel(new BorderLayout()); // Create Call Stack Builder Control Panel CS_ControlPanel = new CallStackToolbarHandler(); JPanel pfunc_control_toolbar = CS_ControlPanel.initCallStackToolbarHandler(this); // new JToolBar(); JLabel jl = new JLabel(AnLocale.getString("Call Stack Builder")); jl.setVisible(false); pfunc_control_toolbar.add(jl); pfunc_internal_panel.add(pfunc_control_toolbar, BorderLayout.NORTH); pfunc_internal_panel.add(func_item, BorderLayout.CENTER); if (singleFunctionMode == true) { label_function.setToolTipText(AnLocale.getString("Selected Function") + " (Alt-2)"); } else { label_function.setToolTipText(AnLocale.getString("Stack Fragment") + " (Alt-2)"); } label_function_text.setText("2"); label_function_text.setVisible(false); label_function_text.setDisplayedMnemonic(KeyEvent.VK_2); context = label_function.getAccessibleContext(); if (singleFunctionMode == true) { context.setAccessibleName(AnLocale.getString("Selected Function")); context.setAccessibleDescription(AnLocale.getString("Selected Function")); } else { context.setAccessibleName(AnLocale.getString("Stack Fragment")); context.setAccessibleDescription(AnLocale.getString("Stack Fragment")); } label_function.setBorder(AnVariable.iconBorder); pfunc_item.add(label_function_text, BorderLayout.WEST); pfunc_item.add(label_function, BorderLayout.WEST); // NM pfunc_item.add(func_item, BorderLayout.CENTER); pfunc_item.add(pfunc_internal_panel, BorderLayout.CENTER); pcallee = new JPanel(new BorderLayout()); label_callees.setToolTipText(AnLocale.getString("Callees") + " (Alt-3)"); label_callees_text.setText("3"); label_callees_text.setVisible(false); label_callees_text.setDisplayedMnemonic(KeyEvent.VK_3); context = label_callees.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Callees")); context.setAccessibleDescription(AnLocale.getString("Callees")); label_callees.setBorder(AnVariable.iconBorder); pcallee.add(label_callees_text, BorderLayout.WEST); pcallee.add(label_callees, BorderLayout.WEST); pcallee.add(callee, BorderLayout.CENTER); // Set the split pane msize = pcaller.getMinimumSize(); msize.height = CALLER_MIN_HEIGHT; pcaller.setMinimumSize(msize); msize = pcallee.getMinimumSize(); msize.height = CALLEE_MIN_HEIGHT; pcallee.setMinimumSize(msize); pfunc_item.setMinimumSize(msize); split_pane_2 = new AnSplitPaneInternal(JSplitPane.VERTICAL_SPLIT, pfunc_item, pcallee); split_pane_2.setContinuousLayout(true); split_pane_2.setDividerLocation(AnVariable.WIN_HEIGHT / 2); pcaller.setBorder( BorderFactory.createMatteBorder(0, 0, 1, 0, AnEnvironment.SPLIT_PANE_BORDER_COLOR_INSIDE)); split_pane_1 = new AnSplitPaneInternal(JSplitPane.VERTICAL_SPLIT, pcaller, split_pane_2); split_pane_1.setContinuousLayout(true); split_pane_1.setDividerLocation(AnVariable.WIN_HEIGHT / 2); add(split_pane_1, BorderLayout.CENTER); } // Clear display @Override public void clear() { caller.removeAll(); func_item.removeAll(); callee.removeAll(); } // Clear selections public void clearSelections() { caller.clearSelection(); func_item.clearSelection(); callee.clearSelection(); } @Override public List<ExportFormat> getSupportedExportFormats() { List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.TEXT); // formats.add(ExportFormat.HTML); // formats.add(ExportFormat.CSV); formats.add(ExportFormat.JPG); return formats; } private Object[][] getCurrentTotalMax() { Object[][] total_max = new Object[2][]; total_max[0] = caller_data_lpd.getTotal(); total_max[1] = MaximumValues[1]; return total_max; } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String text = exportAsText(limit); return text; } private String exportAsText(Integer limit) { // Prepare text presentation of the table String sortedby = AnLocale.getString("sorted by metric:"); String eol = "\n"; String empty = ""; String space = " "; String textImage = null; String separator = empty; String No = AnLocale.getString("No "); String title1 = caller.getAccessibleContext().getAccessibleName(); String title2 = func_item.getAccessibleContext().getAccessibleName(); String title3 = callee.getAccessibleContext().getAccessibleName(); AnTable tbl = func_item; Object[][] total_max = getCurrentTotalMax(); textImage = tbl.printTableHeader(title2, sortedby, total_max); boolean[] show_percentage = tbl.getPercentageArray(); int[] maxh = tbl.getTableHeaderWidths(); if (null == MaximumValues) { return textImage; // empty report } for (int i = 0; i < maxh.length - 1; i++) { int j = 0; if (i + 2 == maxh.length) { j = 1; // Cosmetic } for (; j < maxh[i]; j++) { separator += "="; } } separator += space; // Cosmetic int printLimit = limit != null ? limit : 0; tbl = caller; textImage += separator; if (tbl.getRowCount() == 0) { textImage += No; } textImage += title1 + eol; boolean last_only = false; boolean selected_only = false; textImage += tbl.printTableContents( total_max, maxh, printLimit, show_percentage, last_only, selected_only); tbl = func_item; textImage += separator; textImage += title2 + eol; last_only = true; textImage += tbl.printTableContents( total_max, maxh, printLimit, show_percentage, last_only, selected_only); tbl = callee; textImage += separator; if (tbl.getRowCount() == 0) { textImage += No; } textImage += title3 + eol; last_only = false; textImage += tbl.printTableContents( total_max, maxh, printLimit, show_percentage, last_only, selected_only); return textImage; } /** * Sets column height for caller, stack fragment, and callee tables * * @param row_height */ private void setHeightsAndScroll(int row_height) { // This should be done on AWT thread: final int common_row_height = row_height; AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { // Set column height/width for caller/func/callee caller.setColumn(common_row_height); func_item.setColumn(common_row_height); callee.setColumn(common_row_height); if (singleFunctionMode == true) { caller.clearSelectedRow(); callee.clearSelectedRow(); } final int sc_pos = callee.getScroll(); caller.setScroll(sc_pos); func_item.setScroll(sc_pos); } }); } // Reset display @Override public void reset() { try { SwingUtilities.invokeAndWait( new Runnable() { @Override public void run() { caller.removeAllRows(); func_item.removeAllRows(); callee.removeAllRows(); } }); } catch (Exception exc) { System.out.println("CallDisp.reset() exception: " + exc); exc.printStackTrace(); } } // Get ID of selected function public long getID() { return window.getSelectedObject().getSelObjV2("FUNCTION"); } // Get current stack fragment public long[] getStack() { return cc_callstack.getIDs(); } // Compute & update function list table @Override public synchronized void doCompute() { final int /*new_ind,*/ sort_ind, sc_pos; int name_len, len, row_height, height; Object[] raw_data_with_ids; final int[] caller_stype, func_stype, callee_stype; MetricLabel[] caller_label, func_label, callee_label; final int[][] caller_width, func_width, callee_width; AnObject obj, max_obj; final long[] cstack; boolean select_self = false; AnUtility.checkIfOnAWTThread(false); // Not selected if (!selected) { return; } caller_label = func_label = callee_label = null; if (null == cc_callstack) { return; // initialization is not finished yet } // R1 Reset stack if necessary if (cc_callstack.needReset()) { cc_callstack.reset(); select_self = true; computed = false; } if (!computed) { // need re-compute sel_func = getFuncObj(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) // Required to initialize Functions list Object[] res = setFuncData(sel_func, type, subtype); // IPC String errstr = ((String[]) (res[1]))[0]; // Update table if (errstr == null) { showWarning(window.getMsg(AnUtility.WARNING_MSG)); table = caller; table.setViewport(); // Update stack /* * The caller-callee display will honor selections * made in other displays. */ cstack = cc_callstack.getIDs(); // Update callers list raw_data_with_ids = /* window. */ getTableData(mlistStr, stab_callers, typeStrFunc, subtypeStr, cstack); caller_data_lpd = new LocalProcessData(raw_data_with_ids); caller_data = caller_data_lpd.get_data(); ids_callers = caller_data_lpd.get_ids(); caller_stype = caller_data_lpd.get_types(); // Update Callers // Pass callers_total_max to support percentage calculation Object[] callers_total_max = caller_data_lpd.getLocalTotalMax(); // XXX Do we need a special case; no callers? caller_label = getSettings() .getMetricsSetting() .getLabel(caller_data, callers_total_max, type, caller); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(type); names = getNames(type, 0); sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(type); // Update function item raw_data_with_ids = /* window. */ getTableData(mlistStr, stab_self, typeStrFunc, subtypeStr, cstack); func_data_lpd = new LocalProcessData(raw_data_with_ids); func_data = func_data_lpd.get_data(); if (func_data.length <= name_col) { // NM Hack against drop experiments return; } if (cstack.length == 1) { ids_cstack = func_data_lpd.get_ids(); // NM fix API problem cc_callstack.setNames((String[]) func_data[name_col]); } else { // Now watch the hands :-) func_data = cc_callstack.recreateStackTable(raw_data_with_ids); } func_stype = func_data_lpd.get_types(); // Update callees list raw_data_with_ids = /* window. */ getTableData(mlistStr, stab_callees, typeStrFunc, subtypeStr, cstack); callee_data_lpd = new LocalProcessData(raw_data_with_ids); callee_data = callee_data_lpd.get_data(); ids_callees = callee_data_lpd.get_ids(); callee_stype = callee_data_lpd.get_types(); // Update Stack Fragment if (caller_data[0].length < 1) { if (callee_data[0].length > 0) { callers_total_max = callee_data_lpd.getLocalTotalMax(); } else { callers_total_max = func_data_lpd.getLocalTotalMax(); // if ((null == MaximumValues) || (null == MaximumValues[0][0])) { // callers_total_max = func_data_lpd.getLocalTotalMax(); // } else { // callers_total_max = new Object[2]; // ANOTHER HACK // callers_total_max[0] = MaximumValues[0]; // ANOTHER HACK // callers_total_max[1] = MaximumValues[1]; // ANOTHER HACK // } } } // Pass callers_total_max to support percentage calculation func_label = getSettings() .getMetricsSetting() .getLabel(func_data, callers_total_max, type, func_item); // Update Callees // Pass callers_total_max to support percentage calculation callee_label = getSettings() .getMetricsSetting() .getLabel(callee_data, callers_total_max, type, callee); { // Use SwingUtilities to update tables final MetricLabel[] label1 = caller_label; final MetricLabel[] label2 = func_label; final MetricLabel[] label3 = callee_label; AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { caller.setData(label1, caller_data, names, caller_stype, 0, name_col, sort_ind); func_item.setData(label2, func_data, names, func_stype, 0, name_col, sort_ind); callee.setData(label3, callee_data, names, callee_stype, 0, name_col, sort_ind); } }); } } else { window.getExperimentsView().appendLog(AnLocale.getString("Error: ") + errstr); table.showMessage(errstr); } } // Set the column width // XXX Should all this staff be done on AWT thread? if (caller_label != null) { // Find the 'name' object which has the maximum width max_obj = caller_label[name_col].getMaxAnObject(); name_len = caller.stringWidth(max_obj.toString()); obj = func_label[name_col].getMaxAnObject(); len = func_item.stringWidth(obj.toString()); if (name_len < len) { name_len = len; max_obj = obj; } obj = callee_label[name_col].getMaxAnObject(); len = callee.stringWidth(obj.toString()); if (name_len < len) { // name_len = len; // assignment is never used max_obj = obj; } caller_label[name_col].setMaxAnObject(max_obj); func_label[name_col].setMaxAnObject(max_obj); callee_label[name_col].setMaxAnObject(max_obj); // Find the maximum row height row_height = caller.getRowHeight(); height = func_item.getRowHeight(); if (row_height < height) { row_height = height; } height = callee.getRowHeight(); if (row_height < height) { row_height = height; } // Find the maximum width for each field caller_width = caller.getColumnWidth(); func_width = func_item.getColumnWidth(); callee_width = callee.getColumnWidth(); for (int i = 0; i < caller_width.length; i++) { for (int j = 0; j < 4; j++) { if (caller_width[i][j] < func_width[i][j]) { caller_width[i][j] = func_width[i][j]; } if (caller_width[i][j] < callee_width[i][j]) { caller_width[i][j] = callee_width[i][j]; } func_width[i][j] = callee_width[i][j] = caller_width[i][j]; } } // Set column height/width for caller/func/callee setHeightsAndScroll(row_height); // Use AWT thread } // Update caller table headers. Column width may have changed. caller.getTableModel().updateTableHeaders(); // Update selection if (select_self && (ids_cstack.length > 0)) { cc_callstack.setSelectedObject(ids_cstack[0]); cc_callstack.saveSelection(ids_cstack[0], func_item, 0); } cc_callstack.computeSelection(); // Update summary display window.getSelectionManager().updateSelection(); computed = true; } @Override protected boolean supportsFindText() { return true; } // Find @Override public int find(final String str, final boolean next, boolean caseSensitive) { int find_row; final AnTable next_table; if (str == null) { return -1; } table.clearSelection(); next_table = (table == caller) ? callee : caller; find_row = table.findAfter(str, next, caseSensitive); if (find_row == -1) { find_row = next_table.findBefore(str, next, caseSensitive); if (find_row == -1) { find_row = next_table.findAfter(str, next, caseSensitive); if (find_row == -1) { find_row = table.findBefore(str, next, caseSensitive); } else { table = next_table; } } else { table = next_table; } } if (find_row != -1) { table.setSelectedRow(find_row); } return find_row; } // Find name and select this raw public int findName(final String str, final boolean next, AnTable table, boolean caseSensitive) { int find_row = -1; AnTable next_table; if (str == null) { return -1; } next_table = table; if (null == table) { next_table = caller; } for (int i = 1; i <= 3; i++) { find_row = next_table.findAfter(str, next, caseSensitive); if (find_row == -1) { find_row = next_table.findBefore(str, next, caseSensitive); } if (find_row != -1) { clearSelections(); // caller.clearSelection(); // func_item.clearSelection(); // callee.clearSelection(); next_table.setSelectedRow(find_row); // NM table = next_table; //NM is it needed? break; } if (next_table == caller) { next_table = func_item; } else if (next_table == func_item) { next_table = callee; } else if (next_table == callee) { next_table = caller; } } return find_row; } // Sort @Override public void sort(final int index) { caller.sort(index); callee.sort(index); } // Check if "Back" action is available @Override public boolean isBackActionAvailable() { if (cc_callstack == null) { return false; } return cc_callstack.isBackActionAvailable(); } // Check if "Forward" action is available @Override public boolean isForwardActionAvailable() { if (cc_callstack == null) { return false; } return cc_callstack.isForwardActionAvailable(); } // Get function item data // private Object[] getFuncItem() { // return getFuncList(DSP_SELF, 0); // } // Get callers data list // private Object[] getCallerList() { // return getFuncList(DSP_CALLER, 0); // } // Get callees data list // private Object[] getCalleeList() { // return getFuncList(DSP_CALLEE, 0); // } // Get table data private Object[] getTableData( final String mlistStr, final String modeStr, final String typeStr, final String subtypeStr, final long[] cstack) { // long t = System.currentTimeMillis(); Object[] data = window.getTableDataV2(mlistStr, modeStr, typeStr, subtypeStr, cstack); // t = System.currentTimeMillis() - t; // System.out.println("DEBUG: CallerCalleesDisp.getTableData(): time="+t+" mls."); return data; } class LocalProcessData { final String AccessToMaximumValues = "AccessToMaximumValues"; private Object[][] LocalMaximumValues = null; // MaximumValues[0][col] = Total[col], MaximumValues[1][col] = Maximum[col] Object[][] total_max = null; private Object[] raw_data; private Object[][] data; private long[] ids; private int[] types; LocalProcessData(final Object[] raw_data_with_ids) { raw_data = raw_data_with_ids; final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(type); data = localProcessData(mlist, raw_data); ids = (long[]) raw_data[raw_data_with_ids.length - 1]; // types = (int[]) raw_data[raw_data_with_ids.length - 2]; types = null; // Is not needed ? total_max = AnObject.updateMaxValues(data, null); } public long[] get_ids() { return ids; } public int[] get_types() { return types; } public Object[][] get_data() { return data; } /* * Returns MaximumValues (Total and Max values), calculated by processData() */ public Object[] getTotalMax() { synchronized (AccessToMaximumValues) { return MaximumValues; } } /* * Returns local Maximum Values (Total and Max values), calculated by processData() */ public Object[] getLocalTotalMax() { synchronized (AccessToMaximumValues) { return LocalMaximumValues; } } /* * Returns Total values */ public Object[] getTotal() { Object[] total = null; Object[] raw_data_with_ids = getTableData(mlistStr, stab_callees, typeStrFunc, subtypeStr, null /*cstack*/); if (null == raw_data_with_ids) { return total; } final AnMetric[] mlist = getSettings().getMetricsSetting().getMetricListByDType(type); Object[][] processed_data = localProcessData(mlist, raw_data_with_ids); int len = processed_data.length; if (len > 0) { total = new Object[len]; for (int i = 0; i < len; i++) { total[i] = processed_data[i][0]; } } return total; } } // Listener for updating table private final class TableHandler implements AnListener { @Override public void valueChanged(final AnEvent event) { final AnTable src = (AnTable) event.getSource(); final int loc, from, to, column, width; boolean doubleClick = false; int index = event.getValue(); switch (event.getType()) { case AnEvent.EVT_SELECT: // Selecting changeSelection(src, index); break; case AnEvent.EVT_COPY_ALL: // Copy copyAll(); break; case AnEvent.EVT_RESET: // Reset cc_callstack.reset(); computed = false; computeOnAWorkerThread(); break; case AnEvent.EVT_SET: // Set (re-center) if (src == caller) { if ((index >= 0) && (ids_callers.length - 1 >= index)) { cc_callstack.replace(ids_callers, index); } } else if (src == callee) { if ((index >= 0) && (ids_callees.length - 1 >= index)) { cc_callstack.replace(ids_callees, index); } } else if (src == func_item) { if ((index >= 0) && (ids_cstack.length - 1 >= index)) { cc_callstack.replace(ids_cstack, index); } } computed = false; computeOnAWorkerThread(); break; case AnEvent.EVT_SETHEAD: // Set new head cc_callstack.setHead(index); computed = false; computeOnAWorkerThread(); break; case AnEvent.EVT_SETTAIL: // Set new tail cc_callstack.setTail(index); computed = false; computeOnAWorkerThread(); break; case AnEvent.EVT_COMPUTE: // Compute and Update // Default action for double click // double_click = true; //OM doubleClick = false; // NM if (src == caller) { cc_callstack.prepend(index); if (doubleClick) { if (ids_cstack.length == 2) { cc_callstack.replace(ids_cstack, 0); } } } else if (src == callee) { cc_callstack.append(index); if (doubleClick) { if (ids_cstack.length == 2) { cc_callstack.replace(ids_cstack, 1); } } } else if (src == func_item) { cc_callstack.remove(index); if (doubleClick) { if (ids_cstack.length == 2) { cc_callstack.replace(ids_cstack, 1); } } } computed = false; computeOnAWorkerThread(); break; case AnEvent.EVT_UPDATE: // Updating if (index >= 0) { if (src == caller) { cc_callstack.prepend(index); if (doubleClick) { // OM if (ids_cstack.length == 2) { // OM cc_callstack.replace(ids_cstack, 0); // OM } // OM } // OM } else if (src == callee) { cc_callstack.append(index); if (doubleClick) { // OM if (ids_cstack.length == 2) { // OM cc_callstack.replace(ids_cstack, 1); // OM } // OM } // OM } else if (src == func_item) { if ((index == 0) && (ids_cstack.length > 1)) { cc_callstack.remove(index); } if ((index > 0) && (ids_cstack.length - 1 == index)) { cc_callstack.remove(index); } if ((index > 0) && (ids_cstack.length - 1 > index)) { // R1 cc_callstack.replace(ids_cstack, index); // do nothing break; } } computed = false; computeOnAWorkerThread(); // } else { // Keep selected object (src == func_item) } // NM window.showSummary(); break; case AnEvent.EVT_SORT: // Sorting getSettings() .getMetricsSetting() .setSortMetricByDType(this, ((Integer) event.getAux()).intValue(), type); break; case AnEvent.EVT_SCROLL: // Scrolling if (src == callee) { loc = event.getValue(); caller.setScroll(loc); func_item.setScroll(loc); } break; case AnEvent.EVT_SWITCH: // Column switching from = event.getValue(); to = ((Integer) event.getAux()).intValue(); if (src == caller) { func_item.moveColumn(from, to); callee.moveColumn(from, to); } getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, type); break; case AnEvent.EVT_RESIZE: // Column resizing if (src == caller) { column = event.getValue(); width = ((Integer) event.getAux()).intValue(); func_item.setColumnWidth(column, width); callee.setColumnWidth(column, width); } break; case AnEvent.EVT_BACK: // Go back cc_callstack.gotoCallStackFrame(cc_callstack.StackHistoryIndex - 1); computed = false; computeOnAWorkerThread(); break; case AnEvent.EVT_FORWARD: // Go forward cc_callstack.gotoCallStackFrame(cc_callstack.StackHistoryIndex + 1); computed = false; computeOnAWorkerThread(); break; } } } // Listener for call stack toolbar actions private final class CallStackToolbarHandler implements ActionListener { private CallerCalleesView cd; private JPanel tb; public JButton btn_add = new JButton(); public JButton btn_remove = new JButton(); public JButton btn_set_head = new JButton(); public JButton btn_set_center = new JButton(); public JButton btn_set_tail = new JButton(); public JButton btn_back = new JButton(); public JButton btn_forward = new JButton(); public boolean btn_append_enabled = false; public JPanel initCallStackToolbarHandler(CallerCalleesView calldisp) { cd = calldisp; tb = new JPanel(); // btn_back = new JButton("Back"); btn_back.setMnemonic(AnLocale.getString('B', "CallerCalleesBack")); btn_back.setIcon(AnUtility.goBackwardIcon); // btn_back.setText(AnLocale.getString("Back", "GO_BACK_IN_CALLSTACK_HISTORY")); btn_back.setToolTipText(AnLocale.getString("Go back in callstack history")); btn_back.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { CS_Go_Back(evt); } }); tb.add(btn_back); // btn_forward = new JButton("Forward"); btn_forward.setMnemonic(AnLocale.getString('o', "CallerCalleesForward")); btn_forward.setIcon(AnUtility.goForwardIcon); // btn_forward.setText(AnLocale.getString("Forward", "GO_FORWARD_IN_CALLSTACK_HISTORY")); btn_forward.setToolTipText(AnLocale.getString("Go forward in callstack history")); btn_forward.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { CS_Go_Forward(evt); } }); tb.add(btn_forward); JLabel action_group = new JLabel(" "); tb.add(action_group); // btn_add = new JButton("Add"); btn_add.setMnemonic(AnLocale.getString('A', "CallerCalleesAdd")); btn_add.setText(AnLocale.getString("Add", "ADD_SELECTED_FUNCTION_TO_CALLSTACK")); btn_add.setToolTipText(AnLocale.getString("Add selected function to the callstack")); btn_add.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { CS_Add_Function(evt); } }); tb.add(btn_add); // btn_remove = new JButton("Remove"); btn_remove.setMnemonic(AnLocale.getString('R', "CallerCalleesRemove")); btn_remove.setText(AnLocale.getString("Remove", "REMOVE_SELECTED_FUNCTION_FROM_CALLSTACK")); btn_remove.setToolTipText(AnLocale.getString("Remove selected function from the callstack")); btn_remove.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { CS_Remove_Function(evt); } }); tb.add(btn_remove); JLabel set_group = new JLabel(" "); tb.add(set_group); // btn_set_head = new JButton("Set Head"); btn_set_head.setMnemonic(AnLocale.getString('e', "CallerCalleesSetHead")); btn_set_head.setText( AnLocale.getString("Set Head", "SET_SELECTED_FUNCTION_AS_HEAD_OF_CALLSTACK")); btn_set_head.setToolTipText( AnLocale.getString("Set selected function as head of the callstack")); btn_set_head.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { CS_Set_Head(evt); } }); tb.add(btn_set_head); // btn_set_center = new JButton("Set Center"); btn_set_center.setMnemonic(AnLocale.getString('s', "CallerCalleesCenter")); btn_set_center.setText( AnLocale.getString("Set Center", "SET_SELECTED_FUNCTION_AS_CALLSTACK")); btn_set_center.setToolTipText(AnLocale.getString("Set selected function as new callstack")); btn_set_center.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { CS_Set_Center(evt); } }); tb.add(btn_set_center); // btn_set_tail = new JButton("Set Tail"); btn_set_tail.setMnemonic(AnLocale.getString('l', "CallerCalleesTail")); btn_set_tail.setText( AnLocale.getString("Set Tail", "SET_SELECTED_FUNCTION_AS_TAIL_OF_CALLSTACK")); btn_set_tail.setToolTipText( AnLocale.getString("Set selected function as tail of the callstack")); btn_set_tail.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { CS_Set_Tail(evt); } }); tb.add(btn_set_tail); return tb; } // Action performed @Override public void actionPerformed(final ActionEvent event) { final String cmd = event.getActionCommand(); if (cmd.equals(AnLocale.getString("Add"))) { System.out.println("Add"); } } // Actions public void CS_Add_Function(final ActionEvent event) { if (btn_append_enabled) { int index = cd.callee.getSelectedRow(); // if (index < 0) return; // cd.cc_callstack.last_selected_table = callee; cd.cc_callstack.append(index); computed = false; computeOnAWorkerThread(); } else { int index = cd.caller.getSelectedRow(); // if (index < 0) return; // cd.cc_callstack.last_selected_table = caller; cd.cc_callstack.prepend(index); computed = false; computeOnAWorkerThread(); } } /* * Remove */ public void CS_Remove_Function(final ActionEvent event) { int index = cd.func_item.getSelectedRow(); // if (0 == index) { // cd.cc_callstack.last_selected_table = caller; // } else { // cd.cc_callstack.last_selected_table = callee; // } cd.cc_callstack.remove(index); computed = false; computeOnAWorkerThread(); } /* * Set Head */ public void CS_Set_Head(final ActionEvent event) { int index = cd.func_item.getSelectedRow(); // if (index <= 0) return; cd.cc_callstack.setHead(index); computed = false; computeOnAWorkerThread(); } /* * Set Center */ public void CS_Set_Center(final ActionEvent event) { cd.cc_callstack.setCenter(); computed = false; computeOnAWorkerThread(); } /* * Set Tail */ public void CS_Set_Tail(final ActionEvent event) { int index = cd.func_item.getSelectedRow(); cd.cc_callstack.setTail(index); computed = false; computeOnAWorkerThread(); } /* * Back */ public void CS_Go_Back(final ActionEvent event) { cd.cc_callstack.gotoCallStackFrame(cd.cc_callstack.StackHistoryIndex - 1); computed = false; computeOnAWorkerThread(); } /* * Forward */ public void CS_Go_Forward(final ActionEvent event) { cd.cc_callstack.gotoCallStackFrame(cd.cc_callstack.StackHistoryIndex + 1); computed = false; computeOnAWorkerThread(); } /* * Enable Buttons */ public void CS_Enable_Buttons(final AnTable table) { if (table == cd.caller) { btn_add.setEnabled(true); btn_append_enabled = false; btn_remove.setEnabled(false); btn_set_head.setEnabled(false); btn_set_center.setEnabled(true); btn_set_tail.setEnabled(false); btn_back.setEnabled(cd.cc_callstack.isBackActionAvailable()); btn_forward.setEnabled(cd.cc_callstack.isForwardActionAvailable()); } if (table == cd.func_item) { int rows = table.getRowCount(); int selrow = table.getSelectedRow(); btn_add.setEnabled(false); btn_append_enabled = false; btn_remove.setEnabled(false); if (rows > 1) { if ((selrow + 1 == rows) || (0 == selrow)) { btn_remove.setEnabled(true); } } if (selrow > 0) { btn_set_head.setEnabled(true); } else { btn_set_head.setEnabled(false); } btn_set_center.setEnabled(true); if ((selrow + 1 != rows) && (rows > 1)) { btn_set_tail.setEnabled(true); } else { btn_set_tail.setEnabled(false); } btn_back.setEnabled(cd.cc_callstack.isBackActionAvailable()); btn_forward.setEnabled(cd.cc_callstack.isForwardActionAvailable()); } if (table == cd.callee) { btn_add.setEnabled(true); btn_append_enabled = true; btn_remove.setEnabled(false); btn_set_head.setEnabled(false); btn_set_center.setEnabled(true); btn_set_tail.setEnabled(false); btn_back.setEnabled(cd.cc_callstack.isBackActionAvailable()); btn_forward.setEnabled(cd.cc_callstack.isForwardActionAvailable()); } } } // end of class /* * Change selection */ @Override public void changeSelection(AnTable src, int index) { long ID = -1; if (index >= 0) { clearSelections(); if (src == caller) { if (index < ids_callers.length) { ID = ids_callers[index]; } } else if (src == callee) { if (index < ids_callees.length) { ID = ids_callees[index]; } } else if (src == func_item) { if (index < ids_cstack.length) { ID = ids_cstack[index]; } } if (ID > 0) { src.setSelectedRow(index); // AWT // cc_callstack.setSelectedObject(ID); //NM Hack // cc_callstack.saveSelection(ID, src, index); //NM Hack // window.computeFuncData(); //NM Update Summary // window.showSummary(); // AWT final long id = ID; final int ix = index; final AnTable at = src; AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { cc_callstack.setSelectedObject(id); // NM Hack cc_callstack.saveSelection(id, at, ix); // NM Hack // window.computeFuncData(); // summary window.getSelectionManager().updateSelection(); AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { // window.showSummary(); // AWT CS_ControlPanel.CS_Enable_Buttons(at); // AWT } }); } }, "CallTree_thread"); } else { CS_ControlPanel.CS_Enable_Buttons(src); // AWT } } } // public CalledByCallsDisp getCallTab(final int ptype) { // FIXUP: REARCH // switch(ptype){ // case AnDisplay.DSP_SOURCE: // return call_tab_src; // case AnDisplay.DSP_DISASM: // return call_tab_dis; // case AnDisplay.DSP_FUNCTION: // return call_tab_func; // } // return null; // } // CallStack actions private final class CC_CallStack { long[] ids; String[] names; long selectionTime = 0; String lastFilter = null; long last_ID = -1; AnTable last_selected_table = null; int last_selected_row = -1; String API_V2_FUNCTION_Str = "FUNCTION"; Vector StackHistory = new Vector(0); int StackHistoryIndex = -1; private final class CC_CallStackFrame { long[] cstack; long selected_ID; AnTable selected_table; int selected_row; } public void append(int index) { // NM TODO: Replace ids_cstack with ids if (index >= ids_callees.length) { System.out.println("ERROR"); return; } long ID = ids_callees[index]; long[] new_cstack = new long[ids_cstack.length + 1]; for (int i = 0; i < ids_cstack.length; i++) { new_cstack[i] = ids_cstack[i]; } new_cstack[new_cstack.length - 1] = ID; ids_cstack = new_cstack; ids = new_cstack; String[] new_ids_names = new String[ids_names.length + 1]; for (int i = 0; i < ids_names.length; i++) { new_ids_names[i] = ids_names[i]; } new_ids_names[ids_names.length] = (String) callee_data[name_col][index]; ids_names = new_ids_names; names = new_ids_names; // Save selection saveSelection(ID, func_item, ids.length - 1); saveCallStackFrame(ids, last_ID, last_selected_table, last_selected_row); } public void prepend(int index) { // NM TODO: Replace ids_cstack with ids if (index >= ids_callers.length) { System.out.println("ERROR"); return; } long ID = ids_callers[index]; // last_ID = ID; long[] new_cstack = new long[ids_cstack.length + 1]; new_cstack[0] = ID; for (int i = 1; i < new_cstack.length; i++) { new_cstack[i] = ids_cstack[i - 1]; } ids_cstack = new_cstack; ids = new_cstack; // NM TODO: Replace ids_names with names String[] new_ids_names = new String[ids_names.length + 1]; for (int i = 0; i < ids_names.length; i++) { new_ids_names[i + 1] = ids_names[i]; } new_ids_names[0] = (String) caller_data[name_col][index]; ids_names = new_ids_names; names = new_ids_names; // Save selection saveSelection(ID, func_item, 0); saveCallStackFrame(ids, last_ID, last_selected_table, last_selected_row); } public void remove(int index) { if ((index == 0) && (ids.length > 1)) { // Remove top function long[] new_cstack = new long[ids.length - 1]; for (int i = 1; i < ids.length; i++) { new_cstack[i - 1] = ids[i]; } long ID = ids[0]; ids = new_cstack; ids_cstack = ids; // TEMPORARY String[] new_names = new String[names.length - 1]; for (int i = 1; i < names.length; i++) { new_names[i - 1] = names[i]; } names = new_names; ids_names = names; // TEMPORARY // Save selection saveSelection(ID, caller, -1); saveCallStackFrame(ids, last_ID, last_selected_table, last_selected_row); } if ((index > 0) && (ids.length - 1 == index)) { // Remove bottom function long[] new_cstack = new long[ids.length - 1]; for (int i = 0; i < new_cstack.length; i++) { new_cstack[i] = ids[i]; } long ID = ids[ids.length - 1]; ids = new_cstack; ids_cstack = ids; // TEMPORARY String[] new_names = new String[names.length - 1]; for (int i = 0; i < new_names.length; i++) { new_names[i] = names[i]; } names = new_names; ids_names = names; // TEMPORARY // Save selection saveSelection(ID, callee, -1); saveCallStackFrame(ids, last_ID, last_selected_table, last_selected_row); } } public void setHead(int index) { for (int i = 0; i < index; i++) { cc_callstack.remove(0); } long ID = ids[0]; // Save selection saveSelection(ID, func_item, 0); saveCallStackFrame(ids, last_ID, last_selected_table, last_selected_row); } public void setTail(int index) { for (int i = ids.length - 1; i > index; i--) { cc_callstack.remove(i); } long ID = ids[ids.length - 1]; // Save selection saveSelection(ID, func_item, ids.length - 1); saveCallStackFrame(ids, last_ID, last_selected_table, last_selected_row); } public void setCenter() { reset(); AnUtility.checkIPCOnWrongThread(false); getIDs(); AnUtility.checkIPCOnWrongThread(true); } public void replace(long[] stack, int index) { long ID = stack[index]; long[] new_cstack = new long[1]; new_cstack[0] = ID; ids = new_cstack; ids_cstack = ids; // TEMPORARY // Get name String fname = window.getObjNameV2(ID); String[] new_names = new String[1]; new_names[0] = fname; names = new_names; ids_names = names; // TEMPORARY // Save selection saveSelection(ID, func_item, 0); saveCallStackFrame(ids, last_ID, last_selected_table, last_selected_row); } public void reset() { ids = null; names = null; // StackHistoryIndex = -1; // StackHistory = new Vector(0); } public Object[][] recreateStackTable(Object[] raw_data) { LocalProcessData func_data_new_lpd = new LocalProcessData(raw_data); Object[][] func_data_new = func_data_new_lpd.get_data(); LocalProcessData func_data_from_dbe_lpd = new LocalProcessData(raw_data); Object[][] func_data_from_dbe = func_data_from_dbe_lpd.get_data(); AnAddress[] anAddress; AnDouble[] anDouble; AnInteger[] anInteger; AnLong[] anLong; String[] anString = new String[ids.length]; names = window.getObjNamesV2(ids); for (int i = 0; i < ids.length; i++) { anString[i] = names[i]; // Better to get names from DBE } // Set names func_data_new[name_col] = anString; // Set values for (int i = 0; i < func_data_new.length; i++) { if (func_data_new[i] instanceof String[]) { // Name func_data_new[i] = anString; } else if (func_data_new[i] instanceof AnDouble[]) { anDouble = new AnDouble[ids.length]; for (int k = 0; k < ids.length; k++) { anDouble[k] = new AnDouble(0.0); anDouble[k].showZero(false); } func_data_new[i] = anDouble; if (func_data_from_dbe[i].length > 0) { func_data_new[i][ids.length - 1] = func_data_from_dbe[i][0]; ((AnDouble) func_data_new[i][ids.length - 1]).showZero(true); // } else { // No data - show empty metrics } } else if (func_data_new[i] instanceof AnLong[]) { anLong = new AnLong[ids.length]; for (int k = 0; k < ids.length; k++) { anLong[k] = new AnLong(0); anLong[k].showZero(false); } func_data_new[i] = anLong; if (func_data_from_dbe[i].length > 0) { func_data_new[i][ids.length - 1] = func_data_from_dbe[i][0]; ((AnLong) func_data_new[i][ids.length - 1]).showZero(true); // } else { // No data - show empty metrics } } else if (func_data_new[i] instanceof AnInteger[]) { anInteger = new AnInteger[ids.length]; for (int k = 0; k < ids.length; k++) { anInteger[k] = new AnInteger(0); anInteger[k].showZero(false); } func_data_new[i] = anInteger; if (func_data_from_dbe[i].length > 0) { func_data_new[i][ids.length - 1] = func_data_from_dbe[i][0]; ((AnInteger) func_data_new[i][ids.length - 1]).showZero(true); // } else { // No data - show empty metrics } } else if (func_data_new[i] instanceof AnAddress[]) { anAddress = new AnAddress[ids.length]; for (int k = 0; k < ids.length; k++) { anAddress[k] = new AnAddress(0); anAddress[k].showZero(false); } func_data_new[i] = anAddress; if (func_data_from_dbe[i].length > 0) { func_data_new[i][ids.length - 1] = func_data_from_dbe[i][0]; ((AnAddress) func_data_new[i][ids.length - 1]).showZero(true); // } else { // No data - show empty metrics } } } return func_data_new; } private long[] getIDs() { if (ids == null) { // Get ID long ID = window.getSelectedObject().getSelObjV2(API_V2_FUNCTION_Str); // IPC long[] new_cstack = new long[1]; new_cstack[0] = ID; ids = new_cstack; ids_cstack = ids; // TEMPORARY // Get name String fname = window.getObjNameV2(ID); // IPC String[] new_names = new String[1]; new_names[0] = fname; names = new_names; ids_names = names; // TEMPORARY // Get Filter lastFilter = window.getFilterStr(); // Save selection saveSelection(ID, func_item, 0); saveCallStackFrame(ids, last_ID, last_selected_table, last_selected_row); } return ids; } public void setIDs(long[] stack) { // NM TODO: Remove ids_cstack ids = stack; ids_cstack = ids; // TEMPORARY } public String[] getNames() { if (names == null) { getIDs(); } return names; } public void setNames(String[] names) { // NM TODO: Remove ids_names this.names = names; ids_names = names; // TEMPORARY } public void saveSelection(long ID, AnTable table, int index) { last_ID = ID; last_selected_table = table; last_selected_row = index; } /* * Call Stack History implementation */ /* * Saves Call Stack frame in StackHistory vector. * StackHistoryIndex points to current frame in StackHistory. * @Parameters: * cstack * */ public void saveCallStackFrame(long[] cstack, long ID, AnTable table, int index) { CC_CallStackFrame frame = new CC_CallStackFrame(); frame.cstack = new long[cstack.length]; for (int i = 0; i < cstack.length; i++) { frame.cstack[i] = cstack[i]; } frame.selected_ID = ID; frame.selected_table = table; frame.selected_row = index; StackHistoryIndex++; if (StackHistoryIndex >= 0) { if (StackHistoryIndex + 1 < StackHistory.size()) { for (int i = StackHistory.size() - 1; i > StackHistoryIndex; i--) { StackHistory.removeElementAt(i); } } } else { StackHistoryIndex = 0; } StackHistory.setSize(StackHistoryIndex + 1); boolean alreadySaved = false; if (StackHistory.elementAt(StackHistoryIndex) != null) { // Check if this frame is already saved CC_CallStackFrame f = (CC_CallStackFrame) StackHistory.elementAt(StackHistoryIndex); if (f.cstack != null) { int i = f.cstack.length; int j = frame.cstack.length; if (i == j) { alreadySaved = true; for (i = 0; i < j; i++) { if (f.cstack[i] != frame.cstack[i]) { alreadySaved = false; break; } } } } } if (!alreadySaved) { StackHistory.setElementAt(frame, StackHistoryIndex); } else { StackHistoryIndex--; StackHistory.setSize(StackHistoryIndex + 1); // ? } } /* * Implements "Back" and "Forward" actions. * StackHistoryIndex points to current frame in StackHistory. * - action "Back" goes to ( StackHistoryIndex - 1 ) frame * - action "Forward" goes to ( StackHistoryIndex + 1 ) frame * @parameters: * index of frame in StackHistory */ public void gotoCallStackFrame(int index) { CC_CallStackFrame frame; if (index < 0) { return; } if (index >= StackHistory.size()) { return; } frame = (CC_CallStackFrame) StackHistory.elementAt(index); setIDs(frame.cstack); StackHistoryIndex = index; setSelectedObject(frame.selected_ID); // ? last_ID = frame.selected_ID; last_selected_table = frame.selected_table; last_selected_row = frame.selected_row; // window.computeFuncData(); // summary window.getSelectionManager().updateSelection(); } public boolean isBackActionAvailable() { if (StackHistoryIndex > 0) { return true; } return false; } public boolean isForwardActionAvailable() { if (StackHistoryIndex >= 0) { if (StackHistoryIndex + 1 < StackHistory.size()) { if (StackHistory.elementAt(StackHistoryIndex + 1) != null) { return true; } } } return false; } /* * Quick and durty hack to set selected object */ public void setSelectedObject(long ID) { window.getSelectedObject().setSelObjV2(ID); selectionTime = window.getSelectedObject().getSelObjectSelectionTime(); // last_ID = ID; last_selected_table = null; last_selected_row = -1; } /* * Quick and durty hack to show selected object */ public void computeSelection() { long ID = window.getSelectedObject().getSelObjV2(API_V2_FUNCTION_Str); if (ID == last_ID) { if (last_selected_table != null) { if (last_selected_row >= 0) { try { last_selected_table.setSelectedRow(last_selected_row); clearSelections(); last_selected_table.setSelectedRow(last_selected_row); CS_ControlPanel.CS_Enable_Buttons(last_selected_table); return; } catch (Exception e) { // sorry, not a lucky day last_selected_table = null; last_selected_row = -1; } } else { last_selected_row = updateSelection(last_selected_table); if (last_selected_row >= 0) { CS_ControlPanel.CS_Enable_Buttons(last_selected_table); return; } last_selected_table = null; } } } String fname = window.getObjNameV2(ID); findName(fname, true, null, true); // NM Hack, need FindID function } /* * Quick and durty hack to show selected object */ public int updateSelection(AnTable table) { long ID = window.getSelectedObject().getSelObjV2(API_V2_FUNCTION_Str); String fname = window.getObjNameV2(ID); findName(fname, true, table, true); int index = table.getSelectedRow(); return index; } /* * Quick and durty hack to check if reset is needed */ public boolean needReset() { String fs = window.getFilterStr(); if (fs != null) { if (!fs.equals(lastFilter)) { // Filter changed return true; } } if (selectionTime != window.getSelectedObject().getSelObjectSelectionTime()) { // Selected Object was changed in another tab return true; } return false; } } @Override public boolean exportLimitSupported() { return false; } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); list.add(window.getTimelineCallStackSubview()); list.add(window.getIoCallStackSubview()); return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/KeyboardShortcuts.java���������������������������������������������0000644�0001750�0001750�00000013244�14517772113�020263� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import javax.swing.KeyStroke; public class KeyboardShortcuts { // Focus shortcuts public static final KeyStroke viewsFocusShortCut = KeyStroke.getKeyStroke(KeyEvent.VK_0, InputEvent.CTRL_DOWN_MASK); public static final KeyStroke mainViewFocusShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_1, InputEvent.CTRL_DOWN_MASK); public static final KeyStroke subviewArea2CallerFocusShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_2, InputEvent.CTRL_DOWN_MASK); public static final KeyStroke subviewArea2CalleeFocusShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_3, InputEvent.CTRL_DOWN_MASK); public static final KeyStroke subviewArea1FocusShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_4, InputEvent.CTRL_DOWN_MASK); public static final KeyStroke subviewArea3FocusShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_5, InputEvent.CTRL_DOWN_MASK); public static final KeyStroke statusAreaShortCut = KeyStroke.getKeyStroke(KeyEvent.VK_6, InputEvent.CTRL_DOWN_MASK); // Action shortcuts public static final KeyStroke helpActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0); public static final KeyStroke contextMenuActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F10, InputEvent.SHIFT_DOWN_MASK); // Menu shortcuts public static final KeyStroke profileApplicationActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_P, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke profileRunningProcessActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_R, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke profileKernelActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_K, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke openExperimentActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke compareExperimentsActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke aggregateExperimentsActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke showErrorsWarningsActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke connectActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_H, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke exportActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke viewsSettingsActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke metricsSettingsShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_M, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke libraryVisibilityActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_L, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke functionColorsActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke settingsActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke exportSettingsActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke importSettingsActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_I, InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK); // Next/Previous View shortcuts public static final KeyStroke nextViewActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F7, 0); public static final KeyStroke previousViewActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F7, InputEvent.SHIFT_DOWN_MASK); // Functions/Source/Disassembler/Source Disassembler views public static final KeyStroke forwardActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F3, 0); public static final KeyStroke backwardActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F3, InputEvent.SHIFT_DOWN_MASK); // Source/Disassembler/Source Disassembler views public static final KeyStroke sourceNextHotLineActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F4, 0); public static final KeyStroke sourcePreviousHotLineActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F4, InputEvent.SHIFT_DOWN_MASK); public static final KeyStroke sourceNextNonZeroLineActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0); public static final KeyStroke sourcePreviousNonZeroLineActionShortcut = KeyStroke.getKeyStroke(KeyEvent.VK_F5, InputEvent.SHIFT_DOWN_MASK); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/LibraryVisibilityPanel.java����������������������������������������0000644�0001750�0001750�00000137371�14517772113�021250� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.picklist.StringPickList; import org.gprofng.mpmt.picklist.StringPickListElement; import org.gprofng.mpmt.settings.LibraryVisibilitySetting; import org.gprofng.mpmt.util.gui.AnCheckBox; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.gui.AnUtility.AnRadioButton; import java.awt.Color; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.JTextField; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; public class LibraryVisibilityPanel extends JPanel implements AnChangeListener { private static final int maxEntries = 1000; private static final int fill1 = 80; private static int fill2 = 0; private enum SortState { NONE, UP, DOWN }; private SortState nameSortState = SortState.DOWN; private SortState pathSortState = SortState.NONE; private LibraryVisibilityDialog dialog; private JLabel pleaseWaitLabel = new JLabel(AnLocale.getString("Please wait...")); private List<GUIEntry> entryListOriginal; private List<GUIEntry> entryListSortedFiltered; private int noEntriesViewed = 0; private boolean initialized = false; private boolean anyJava; private AnCheckBox functionsCheckBox; private AnCheckBox apiCheckBox; private AnCheckBox CheckBox; public LibraryVisibilityPanel(LibraryVisibilityDialog dialog) { this.dialog = dialog; initComponents(); AnUtility.setTextAndAccessibleContext( infoLabel, AnLocale.getString( "Specify the visibility level of shared libraries and classes in data views.")); scrollPane.getVerticalScrollBar().setUnitIncrement(10); scrollPane.setBorder( BorderFactory.createMatteBorder(0, 0, 1, 0, AnEnvironment.SCROLLBAR_BORDER_COLOR)); nativeRadioButton.setText(AnLocale.getString("Native")); nativeRadioButton.setToolTipText(AnLocale.getString("Select native libraries")); nativeRadioButton.setMnemonic(AnLocale.getString('N', "MN_LIBRARYVISIBILITY_Native_PANEL")); AnUtility.setAccessibleContext( nativeRadioButton.getAccessibleContext(), nativeRadioButton.getText()); javaRadioButton.setText(AnLocale.getString("Java")); javaRadioButton.setToolTipText(AnLocale.getString("Select Java classes")); javaRadioButton.setMnemonic(AnLocale.getString('J', "MN_LIBRARYVISIBILITY_Java_PANEL")); AnUtility.setAccessibleContext( javaRadioButton.getAccessibleContext(), javaRadioButton.getText()); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(nativeRadioButton); buttonGroup.add(javaRadioButton); String includeTT = AnLocale.getString("Include entries that contain any of these text strings"); includeLabel.setText(AnLocale.getString("Include:")); includeLabel.setToolTipText(includeTT); includeLabel.setDisplayedMnemonic(AnLocale.getString('I', "HideFunctionsIncludeLabelMnemonic")); includeLabel.setLabelFor(includeComboBox); includeComboBox.setToolTipText(includeTT); String excludeTT = AnLocale.getString("Exclude entries that contain any of these text strings"); excludeLabel.setToolTipText(excludeTT); excludeLabel.setText(AnLocale.getString("Exclude:")); excludeLabel.setDisplayedMnemonic(AnLocale.getString('X', "HideFunctionsExcludeLabelMnemonic")); excludeLabel.setLabelFor(excludeComboBox); excludeComboBox.setToolTipText(excludeTT); filterPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); AnUtility.setTextAndAccessibleContext(filterLabel, " " + AnLocale.getString("Filters")); filterLabel.setLabelFor(includeComboBox); filterLabel.setOpaque(true); // filterLabel.setDisplayedMnemonic(AnLocale.getString('F', "HideFilterMnemonics")); refreshButton.setText(AnLocale.getString("Refresh")); refreshButton.setMnemonic(AnLocale.getString('R', "HideFunctionsRefreshButton")); refreshButton.setToolTipText(AnLocale.getString("Apply filters")); listLabelPanel.setOpaque(false); AnUtility.setTextAndAccessibleContext(listLabel, AnLocale.getString("List")); // listLabel.setDisplayedMnemonic(AnLocale.getString('L', "HideFunctionsListMnemonics")); functionsCheckBox = new AnCheckBox(); functionsCheckBox.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { functionsCheckBoxActionPerformed(evt); } }); GridBagConstraints gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; outerListPanel.add(functionsCheckBox, gridBagConstraints); apiCheckBox = new AnCheckBox(); apiCheckBox.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { apiCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; outerListPanel.add(apiCheckBox, gridBagConstraints); CheckBox = new AnCheckBox(); CheckBox.addActionListener( new java.awt.event.ActionListener() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { libraryCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 3; outerListPanel.add(CheckBox, gridBagConstraints); listLabel.setLabelFor(functionsCheckBox); functionsLabel.setText(AnLocale.getString("Functions")); String showTT = AnLocale.getString("Show all library and class functions"); functionsLabel.setToolTipText(showTT); functionsLabel.setDisplayedMnemonic(AnLocale.getString('F', "MN_LibraryVisibility_Functions")); functionsLabel.setLabelFor(functionsCheckBox); functionsCheckBox.setToolTipText(showTT); libraryLabel.setText(AnLocale.getString("Library")); libraryLabel.setLabelFor(CheckBox); String hideTT = AnLocale.getString("Show only library or class name (Aggregate by library or class)"); libraryLabel.setToolTipText(hideTT); libraryLabel.setDisplayedMnemonic(AnLocale.getString('L', "MN_LibraryVisibility_Library")); CheckBox.setToolTipText(hideTT); apiLabel.setText(AnLocale.getString("API")); apiLabel.setLabelFor(apiCheckBox); apiLabel.setDisplayedMnemonic(AnLocale.getString('A', "MN_LibraryVisibility_API")); String apiTT = AnLocale.getString("Show only API entry points"); apiLabel.setToolTipText(apiTT); apiCheckBox.setToolTipText(apiTT); AnUtility.setTextAndAccessibleContext(nameButton, AnLocale.getString("Name")); nameButton.setMnemonic(AnLocale.getString('M', "HideFunctionsNameButton")); AnUtility.setTextAndAccessibleContext(pathButton, AnLocale.getString("Path")); pathButton.setMnemonic(AnLocale.getString('P', "HideFunctionsPathButton")); defaultsButton.setText(AnLocale.getString("Defaults")); defaultsButton.setMnemonic(AnLocale.getString('D', "HideFunctionsDefaultsButton")); defaultsButton.setToolTipText(AnLocale.getString("Reset selections to defaults")); outerListPanel.setBorder(BorderFactory.createLineBorder(AnEnvironment.BAR_BORDER_COLOR, 1)); includeComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); excludeComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); Dimension dim1 = new java.awt.Dimension(fill1, 0); filler1.setMinimumSize(dim1); filler1.setPreferredSize(dim1); filler1.setMaximumSize(dim1); filler2.setMinimumSize(dim1); filler2.setPreferredSize(dim1); filler2.setMaximumSize(dim1); filler3.setMinimumSize(dim1); filler3.setPreferredSize(dim1); filler3.setMaximumSize(dim1); Dimension dim2 = new java.awt.Dimension(fill2, 0); filler4.setMinimumSize(dim2); filler4.setPreferredSize(dim2); filler4.setMaximumSize(dim2); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); listPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); buttonPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); nameButton.setBorder(null); nameButton.setBorderPainted(false); nameButton.setBackground(Color.red); nameButton.setOpaque(false); pathButton.setBorder(null); pathButton.setBorderPainted(false); pathButton.setBackground(Color.red); pathButton.setOpaque(false); // Accept ENTER in combobox Action enterAction = new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { String typedInclude = ((JTextField) includeComboBox.getEditor().getEditorComponent()).getText(); includeComboBox.setSelectedItem(typedInclude); String typedExclude = ((JTextField) excludeComboBox.getEditor().getEditorComponent()).getText(); excludeComboBox.setSelectedItem(typedExclude); applyFiltersAndUpdateGUI(); } }; ((JTextField) includeComboBox.getEditor().getEditorComponent()) .getInputMap() .put(KeyStroke.getKeyStroke("ENTER"), "enter"); ((JTextField) includeComboBox.getEditor().getEditorComponent()) .getActionMap() .put("enter", enterAction); ((JTextField) excludeComboBox.getEditor().getEditorComponent()) .getInputMap() .put(KeyStroke.getKeyStroke("ENTER"), "enter"); ((JTextField) excludeComboBox.getEditor().getEditorComponent()) .getActionMap() .put("enter", enterAction); setPreferredSize(new Dimension(1000, 600)); dialog.getOKButton().setEnabled(false); maxLabel.setForeground(Color.red); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("StatisticsView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: initialized = false; break; case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case FILTER_CHANGING: case FILTER_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: case SETTING_CHANGED: break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } protected void debug() { System.out.println("HideFunctionsPanel: " + getClass().getName()); } private void updateSortState() { if (nameSortState == SortState.UP) { nameButton.setIcon(AnUtility.smallArrowDownIcon); } else if (nameSortState == SortState.DOWN) { nameButton.setIcon(AnUtility.smallArrowUpIcon); } else { nameButton.setIcon(null); } if (pathSortState == SortState.UP) { pathButton.setIcon(AnUtility.smallArrowUpIcon); } else if (pathSortState == SortState.DOWN) { pathButton.setIcon(AnUtility.smallArrowDownIcon); } else { pathButton.setIcon(null); } } class GUIEntry implements Comparable<GUIEntry>, ActionListener { private LibraryVisibilitySetting.Entry entry; public JRadioButton showRadioButton; public JRadioButton hideRadioButton; public JRadioButton apiRadioButton; public GUIEntry(LibraryVisibilitySetting.Entry entry) { this.entry = entry; showRadioButton = new AnRadioButton(); AnUtility.setAccessibleContext( showRadioButton.getAccessibleContext(), AnLocale.getString("Functions")); showRadioButton.setOpaque(false); showRadioButton.setActionCommand("SHOW"); showRadioButton.addActionListener(this); hideRadioButton = new AnRadioButton(); AnUtility.setAccessibleContext( hideRadioButton.getAccessibleContext(), AnLocale.getString("API")); hideRadioButton.setActionCommand("HIDE"); hideRadioButton.addActionListener(this); hideRadioButton.setOpaque(false); apiRadioButton = new AnRadioButton(); AnUtility.setAccessibleContext( apiRadioButton.getAccessibleContext(), AnLocale.getString("Library")); apiRadioButton.setActionCommand("API"); apiRadioButton.addActionListener(this); apiRadioButton.setOpaque(false); ButtonGroup buttonGroup = new ButtonGroup(); buttonGroup.add(hideRadioButton); buttonGroup.add(showRadioButton); buttonGroup.add(apiRadioButton); if (entry.getState() == 0) { showRadioButton.setSelected(true); } else if (entry.getState() == 1) { hideRadioButton.setSelected(true); } else if (entry.getState() == 2) { apiRadioButton.setSelected(true); } } /** * @return the name */ public String getName() { return entry.getName(); } /** * @return the path */ public String getPath() { return entry.getPath(); } /** * @return the state */ public int getState() { return entry.getState(); } /** * @return the index */ public int getIndex() { return entry.getIndex(); } /** * @return the name */ public boolean isJava() { return entry.isJava(); } @Override public int compareTo(GUIEntry o) { if (nameSortState == SortState.UP) { return getName().compareTo(o.getName()); } else if (nameSortState == SortState.DOWN) { return o.getName().compareTo(getName()); } else if (pathSortState == SortState.UP) { return getPath().compareTo(o.getPath()); } else if (pathSortState == SortState.DOWN) { return o.getPath().compareTo(getPath()); } else { // Sort by index if (getIndex() < o.getIndex()) { return -1; } else if (getIndex() > o.getIndex()) { return 1; } else { return 0; } } } /** * @param state the state to set */ public void setState(int state) { entry.setState(state); if (state == 0) { showRadioButton.setSelected(true); } else if (state == 1) { hideRadioButton.setSelected(true); } else if (state == 2) { apiRadioButton.setSelected(true); } } @Override public void actionPerformed(ActionEvent e) { String ac = e.getActionCommand(); if (ac.equals("SHOW")) { setState(0); } else if (ac.equals("HIDE")) { setState(1); } else if (ac.equals("API")) { setState(2); } updateCheckBoxStates(); } } private void updateCheckBoxStates() { functionsCheckBox.setSelected(false); CheckBox.setSelected(false); apiCheckBox.setSelected(false); if (entryListSortedFiltered.size() > 0) { boolean allTheSame = true; int state = entryListSortedFiltered.get(0).getState(); for (GUIEntry entry : entryListSortedFiltered) { if (entry.getState() != state) { allTheSame = false; break; } } if (allTheSame) { if (state == 0) { functionsCheckBox.setSelected(true); } else if (state == 1) { CheckBox.setSelected(true); } else if (state == 2) { apiCheckBox.setSelected(true); } } } } public void reset() { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { resetInternal(); } }); } private void resetInternal() { if (!initialized) { listPanel.removeAll(); listPanel.add(pleaseWaitLabel); includeComboBox.setSelectedItem(UserPref.getInstance().getLibraryVisibilityIncludeFilter()); initilize(); } else { includeComboBox.setSelectedItem(UserPref.getInstance().getLibraryVisibilityIncludeFilter()); List<LibraryVisibilitySetting.Entry> list = AnWindow.getInstance().getSettings().getLibraryVisibilitySetting().get(); for (int i = 0; i < list.size(); i++) { LibraryVisibilitySetting.Entry entry = list.get(i); GUIEntry guiEntry = entryListOriginal.get(i); guiEntry.setState(entry.getState()); if (guiEntry.getState() == 0) { guiEntry.showRadioButton.setSelected(true); } else if (guiEntry.getState() == 1) { guiEntry.hideRadioButton.setSelected(true); } else if (guiEntry.getState() == 2) { guiEntry.apiRadioButton.setSelected(true); } } updateCheckBoxStates(); } } public void save() { List<LibraryVisibilitySetting.Entry> list = new ArrayList<LibraryVisibilitySetting.Entry>(); for (GUIEntry guiEntry : entryListOriginal) { list.add(guiEntry.entry.copy()); } AnWindow.getInstance().getSettings().getLibraryVisibilitySetting().set(this, list); } // For persistance public void initStates( boolean java, StringPickList hideFuncsIncludePickList, String currentIncludeFilter, StringPickList hideFuncsExcludePickList, String currentExcludeFilter) { AnUtility.checkIfOnAWTThread(true); initialized = false; if (java) { javaRadioButton.setSelected(true); } else { nativeRadioButton.setSelected(true); } updateFilterComboBoxes( hideFuncsIncludePickList, currentIncludeFilter, hideFuncsExcludePickList, currentExcludeFilter); } private void enableControls(boolean val) { dialog.getOKButton().setEnabled(val); includeComboBox.setEnabled(val); excludeComboBox.setEnabled(val); refreshButton.setEnabled(val); defaultsButton.setEnabled(val); nativeRadioButton.setEnabled(val); javaRadioButton.setEnabled(val && anyJava); } private void initilize() { AnUtility.checkIfOnAWTThread(true); initialized = true; enableControls(false); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { anyJava = false; entryListOriginal = new ArrayList<GUIEntry>(); entryListSortedFiltered = new ArrayList<GUIEntry>(); List<LibraryVisibilitySetting.Entry> list = AnWindow.getInstance().getSettings().getLibraryVisibilitySetting().get(); for (LibraryVisibilitySetting.Entry entry : list) { GUIEntry guiEntry = new GUIEntry(entry.copy()); entryListOriginal.add(guiEntry); entryListSortedFiltered.add(guiEntry); if (entry.isJava()) { anyJava = true; } } if (!anyJava) { nativeRadioButton.setSelected(true); } javaRadioButton.setEnabled(anyJava); applyFiltersAndUpdateGUI(); enableControls(true); } }); } }, "LibraryVisibility"); } private void updateList() { AnUtility.checkIfOnAWTThread(true); enableControls(false); dialog.busyCursor(true); updateSortState(); Collections.sort(entryListSortedFiltered); listPanel.removeAll(); noEntriesViewed = 0; maxLabel.setText(""); maxListLabel.setText(""); for (GUIEntry entry : entryListSortedFiltered) { addEntry(noEntriesViewed++, entry); if (noEntriesViewed >= maxEntries) { addMaxEntry(noEntriesViewed); break; } } addLastEntry(noEntriesViewed); listPanel.validate(); listPanel.repaint(); dialog.busyCursor(false); enableControls(true); // if (noEntriesViewed != entryListOriginal.size()) { String labelText = String.format( AnLocale.getString("List (%d/%d)"), noEntriesViewed, entryListOriginal.size()); listLabel.setText(labelText); // } else { // listLabel.setText(AnLocale.getString("List:")); // } AnUtility.setTextAndAccessibleContext( listedLabel, AnLocale.getString("Number of entries viewed: ") + noEntriesViewed + "/" + entryListOriginal.size()); } private void addEntry(int no, GUIEntry entry) { GridBagConstraints gridBagConstraints = new GridBagConstraints(); if (entry.getState() == 0) { entry.showRadioButton.setSelected(true); } else if (entry.getState() == 1) { entry.hideRadioButton.setSelected(true); } else if (entry.getState() == 2) { entry.apiRadioButton.setSelected(true); } gridBagConstraints.gridx = 0; gridBagConstraints.gridy = no; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, fill1 / 2 - 10, 0, 0); listPanel.add(entry.showRadioButton, gridBagConstraints); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = no; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, fill1 / 2 + 19, 0, 0); listPanel.add(entry.apiRadioButton, gridBagConstraints); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = no; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, fill1 / 2 + 19, 0, 0); listPanel.add(entry.hideRadioButton, gridBagConstraints); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = no; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 45, 0, 0); JLabel label = new JLabel(entry.getName()); label.setToolTipText(entry.getName()); listPanel.add(label, gridBagConstraints); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = no; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.insets = new Insets(0, 12, 0, 0); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; label = new JLabel(entry.getPath()); label.setToolTipText(entry.getPath()); listPanel.add(label, gridBagConstraints); } private void addMaxEntry(int no) { String text = String.format( AnLocale.getString( "Maximum number (%d) of viewed entries reached. Use the filters to reduce the" + " number of entries"), maxEntries); // Add entry in list GridBagConstraints gridBagConstraints = new GridBagConstraints(); JLabel maxEntryLabel = new JLabel(); AnUtility.setTextAndAccessibleContext(maxEntryLabel, text); maxEntryLabel.setForeground(Color.red); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = no + 1; gridBagConstraints.gridwidth = GridBagConstraints.REMAINDER; gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new Insets(8, 12, 8, 0); listPanel.add(maxEntryLabel, gridBagConstraints); // Set the max list label AnUtility.setTextAndAccessibleContext(maxListLabel, " - " + text); maxListLabel.setForeground(Color.red); } private void addLastEntry(int no) { JLabel label = new JLabel(); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = no; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weighty = 1.0; listPanel.add(label, gridBagConstraints); } private void updateFilterComboBoxes(String includeFilterString, String excludeFilterString) { String includeSelected = (String) includeComboBox.getSelectedItem(); UserPref.getInstance().getLibraryVisibilityIncludePickList().addElement(includeFilterString); String excludeSelected = (String) excludeComboBox.getSelectedItem(); UserPref.getInstance().getLibraryVisibilityExcludePickList().addElement(excludeFilterString); updateFilterComboBoxes( UserPref.getInstance().getLibraryVisibilityIncludePickList(), includeSelected, UserPref.getInstance().getLibraryVisibilityExcludePickList(), excludeSelected); } private void updateFilterComboBoxes( StringPickList includePicklist, String currentIncludeFilter, StringPickList excludePicklist, String currentExcludeFilter) { includeComboBox.removeAllItems(); includeComboBox.addItem(""); for (StringPickListElement elem : includePicklist.getStringElements()) { if (elem.getString().length() > 0) { includeComboBox.addItem(elem.getString()); } } if (currentIncludeFilter != null) { includeComboBox.setSelectedItem(currentIncludeFilter); } excludeComboBox.removeAllItems(); excludeComboBox.addItem(""); for (StringPickListElement elem : excludePicklist.getStringElements()) { if (elem.getString().length() > 0) { excludeComboBox.addItem(elem.getString()); } } if (currentExcludeFilter != null) { excludeComboBox.setSelectedItem(currentExcludeFilter); } } private void formatColumns() { int maxNameWidth = 0; for (GUIEntry entry : entryListSortedFiltered) { JLabel label = new JLabel(entry.getName()); int w = label.getPreferredSize().width; if (maxNameWidth < w) { maxNameWidth = w; } } fill2 = maxNameWidth + 28; // Dimension dim2 = new java.awt.Dimension(fill2, 0); filler4.setMinimumSize(dim2); filler4.setPreferredSize(dim2); filler4.setMaximumSize(dim2); } private void applyFiltersAndUpdateGUI() { String includeFilterString = (String) includeComboBox.getSelectedItem(); String excludeFilterString = (String) excludeComboBox.getSelectedItem(); if (includeFilterString == null) { includeFilterString = ""; } if (excludeFilterString == null) { excludeFilterString = ""; } entryListSortedFiltered = filterEntries(entryListOriginal, javaRadioButton.isSelected()); entryListSortedFiltered = filterEntries(entryListSortedFiltered, includeFilterString, false); entryListSortedFiltered = filterEntries(entryListSortedFiltered, excludeFilterString, true); includeComboBox.addItem(includeFilterString); excludeComboBox.addItem(excludeFilterString); formatColumns(); updateList(); updateCheckBoxStates(); updateFilterComboBoxes(includeFilterString, excludeFilterString); UserPref.getInstance().setLibraryVisibilityIncludeFilter(includeFilterString); UserPref.getInstance().setCurrentLibraryVisibilityExcludeFilter(excludeFilterString); } public boolean isJava() { return javaRadioButton.isSelected(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; infoLabel = new javax.swing.JLabel(); filterPanel = new javax.swing.JPanel(); filterLabel = new javax.swing.JLabel(); radioButtonPanel = new javax.swing.JPanel(); nativeRadioButton = new javax.swing.JRadioButton(); javaRadioButton = new javax.swing.JRadioButton(); includeLabel = new javax.swing.JLabel(); includeComboBox = new javax.swing.JComboBox(); excludeLabel = new javax.swing.JLabel(); excludeComboBox = new javax.swing.JComboBox(); refreshButton = new javax.swing.JButton(); listLabelPanel = new javax.swing.JPanel(); listLabel = new javax.swing.JLabel(); maxListLabel = new javax.swing.JLabel(); outerListPanel = new javax.swing.JPanel(); filler1 = new javax.swing.Box.Filler( new java.awt.Dimension(60, 0), new java.awt.Dimension(60, 0), new java.awt.Dimension(60, 0)); filler2 = new javax.swing.Box.Filler( new java.awt.Dimension(60, 0), new java.awt.Dimension(60, 0), new java.awt.Dimension(60, 0)); filler3 = new javax.swing.Box.Filler( new java.awt.Dimension(60, 0), new java.awt.Dimension(60, 0), new java.awt.Dimension(60, 0)); filler4 = new javax.swing.Box.Filler( new java.awt.Dimension(120, 0), new java.awt.Dimension(120, 0), new java.awt.Dimension(120, 0)); functionsLabel = new javax.swing.JLabel(); apiLabel = new javax.swing.JLabel(); libraryLabel = new javax.swing.JLabel(); nameButton = new javax.swing.JButton(); pathButton = new javax.swing.JButton(); scrollPane = new javax.swing.JScrollPane(); listPanel = new javax.swing.JPanel(); buttonPanel = new javax.swing.JPanel(); maxLabel = new javax.swing.JLabel(); defaultsButton = new javax.swing.JButton(); listedLabel = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); infoLabel.setText("info..."); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(infoLabel, gridBagConstraints); filterPanel.setLayout(new java.awt.GridBagLayout()); filterLabel.setText("Filter:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.ipady = 6; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; filterPanel.add(filterLabel, gridBagConstraints); radioButtonPanel.setOpaque(false); radioButtonPanel.setLayout(new java.awt.GridBagLayout()); nativeRadioButton.setText("Native"); nativeRadioButton.setOpaque(false); nativeRadioButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { nativeRadioButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; radioButtonPanel.add(nativeRadioButton, gridBagConstraints); javaRadioButton.setText("Java"); javaRadioButton.setOpaque(false); javaRadioButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { javaRadioButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; radioButtonPanel.add(javaRadioButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); filterPanel.add(radioButtonPanel, gridBagConstraints); includeLabel.setText("Include"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); filterPanel.add(includeLabel, gridBagConstraints); includeComboBox.setEditable(true); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); filterPanel.add(includeComboBox, gridBagConstraints); excludeLabel.setText("and exclude"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 8, 4, 0); filterPanel.add(excludeLabel, gridBagConstraints); excludeComboBox.setEditable(true); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 4, 4, 0); filterPanel.add(excludeComboBox, gridBagConstraints); refreshButton.setText("Refresh"); refreshButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { refreshButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 8, 4, 0); filterPanel.add(refreshButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(14, 0, 0, 0); add(filterPanel, gridBagConstraints); listLabelPanel.setLayout(new java.awt.GridBagLayout()); listLabel.setText("List:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; listLabelPanel.add(listLabel, gridBagConstraints); maxListLabel.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; listLabelPanel.add(maxListLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(listLabelPanel, gridBagConstraints); outerListPanel.setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; outerListPanel.add(filler1, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; outerListPanel.add(filler2, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 1; outerListPanel.add(filler3, gridBagConstraints); filler4.setAutoscrolls(true); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 1; outerListPanel.add(filler4, gridBagConstraints); functionsLabel.setText("Functions"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); outerListPanel.add(functionsLabel, gridBagConstraints); apiLabel.setText("API"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); outerListPanel.add(apiLabel, gridBagConstraints); libraryLabel.setText("Library"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 2; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); outerListPanel.add(libraryLabel, gridBagConstraints); nameButton.setText("Name"); nameButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { nameButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 3; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 14, 0, 0); outerListPanel.add(nameButton, gridBagConstraints); pathButton.setText("Path"); pathButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { pathButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 4; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; outerListPanel.add(pathButton, gridBagConstraints); scrollPane.setBorder(null); listPanel.setLayout(new java.awt.GridBagLayout()); scrollPane.setViewportView(listPanel); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.gridwidth = 5; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); outerListPanel.add(scrollPane, gridBagConstraints); buttonPanel.setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(4, 12, 0, 12); buttonPanel.add(maxLabel, gridBagConstraints); defaultsButton.setText("Defaults"); defaultsButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { defaultsButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 12, 4, 0); buttonPanel.add(defaultsButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 1; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 12); buttonPanel.add(listedLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; outerListPanel.add(buttonPanel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(outerListPanel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void nameButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_nameButtonActionPerformed // TODO add your handling code here: if (nameSortState == SortState.NONE) { nameSortState = SortState.UP; } else if (nameSortState == SortState.UP) { nameSortState = SortState.DOWN; } else { nameSortState = SortState.UP; } pathSortState = SortState.NONE; updateList(); } // GEN-LAST:event_nameButtonActionPerformed private void pathButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_pathButtonActionPerformed // TODO add your handling code here: if (pathSortState == SortState.NONE) { pathSortState = SortState.UP; } else if (pathSortState == SortState.UP) { pathSortState = SortState.DOWN; } else { pathSortState = SortState.UP; } nameSortState = SortState.NONE; updateList(); } // GEN-LAST:event_pathButtonActionPerformed private void refreshButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_refreshButtonActionPerformed applyFiltersAndUpdateGUI(); } // GEN-LAST:event_refreshButtonActionPerformed private List<GUIEntry> filterEntries(List<GUIEntry> origList, boolean java) { List<GUIEntry> list = new ArrayList<GUIEntry>(); for (GUIEntry guiEntry : origList) { if (guiEntry.isJava() == java) { list.add(guiEntry); } } return list; } private List<GUIEntry> filterEntries( List<GUIEntry> origList, String rawIncludeFilterString, boolean exclude) { String[] substrings = rawIncludeFilterString.split(" "); // multiword match //FIXUP bypass escaped spaces? // String[] substrings = {raw_includeFilterString}; // exact text match List<String> clauses = new ArrayList(); for (int ii = 0; ii < substrings.length; ii++) { if (substrings[ii].isEmpty()) { continue; // strip out empty clauses caused by consecutive spaces } clauses.add(substrings[ii]); } final List<GUIEntry> newList; if (clauses.isEmpty()) { newList = new ArrayList(origList); } else { newList = new ArrayList(); for (GUIEntry entry : origList) { boolean pass = false; for (String clause : clauses) { if (entry.getName().contains(clause) || entry.getPath().contains(clause)) { pass = true; break; } } if (exclude) { if (!pass) { newList.add(entry); } } else { if (pass) { newList.add(entry); } } } } return newList; } private void functionsCheckBoxActionPerformed(java.awt.event.ActionEvent evt) { for (GUIEntry entry : entryListSortedFiltered) { entry.setState(0); } updateCheckBoxStates(); } private void libraryCheckBoxActionPerformed(java.awt.event.ActionEvent evt) { for (GUIEntry entry : entryListSortedFiltered) { entry.setState(1); } updateCheckBoxStates(); } private void apiCheckBoxActionPerformed(java.awt.event.ActionEvent evt) { for (GUIEntry entry : entryListSortedFiltered) { entry.setState(2); } updateCheckBoxStates(); } private void defaultsButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_defaultsButtonActionPerformed for (GUIEntry entry : entryListSortedFiltered) { entry.setState(0); } updateCheckBoxStates(); } // GEN-LAST:event_defaultsButtonActionPerformed private void nativeRadioButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_nativeRadioButtonActionPerformed applyFiltersAndUpdateGUI(); } // GEN-LAST:event_nativeRadioButtonActionPerformed private void javaRadioButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_javaRadioButtonActionPerformed applyFiltersAndUpdateGUI(); } // GEN-LAST:event_javaRadioButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel apiLabel; private javax.swing.JPanel buttonPanel; private javax.swing.JButton defaultsButton; private javax.swing.JComboBox excludeComboBox; private javax.swing.JLabel excludeLabel; private javax.swing.Box.Filler filler1; private javax.swing.Box.Filler filler2; private javax.swing.Box.Filler filler3; private javax.swing.Box.Filler filler4; private javax.swing.JLabel filterLabel; private javax.swing.JPanel filterPanel; private javax.swing.JLabel functionsLabel; private javax.swing.JComboBox includeComboBox; private javax.swing.JLabel includeLabel; private javax.swing.JLabel infoLabel; private javax.swing.JRadioButton javaRadioButton; private javax.swing.JLabel libraryLabel; private javax.swing.JLabel listLabel; private javax.swing.JPanel listLabelPanel; private javax.swing.JPanel listPanel; private javax.swing.JLabel listedLabel; private javax.swing.JLabel maxLabel; private javax.swing.JLabel maxListLabel; private javax.swing.JButton nameButton; private javax.swing.JRadioButton nativeRadioButton; private javax.swing.JPanel outerListPanel; private javax.swing.JButton pathButton; private javax.swing.JPanel radioButtonPanel; private javax.swing.JButton refreshButton; private javax.swing.JScrollPane scrollPane; // End of variables declaration//GEN-END:variables } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/CalledByCallsDisp.java���������������������������������������������0000644�0001750�0001750�00000062064�14517772113�020066� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.metrics.MetricLabel; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.util.gui.AnSplitPane; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.accessibility.AccessibleContext; import javax.swing.BorderFactory; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JSplitPane; import javax.swing.ListSelectionModel; public class CalledByCallsDisp extends FuncListDisp { private static final int CALLER_MIN_HEIGHT = 120; private static final int CALLEE_MIN_HEIGHT = 60; private AnTable caller, func_item, callee; private Object[][] caller_data, callee_data; private Object[][] caller_sort_data, callee_sort_data; private LocalProcessData caller_data_lpd; private LocalProcessData callee_data_lpd; private String acNameT1; private String acDescT1; private String acNameT3; private String acDescT3; private long[] ids_callers = null; private long[] ids_callees = null; private long[] ids_cstack = null; private String[] ids_names = null; // private CC_CallStack cc_callstack; private int sort_ind; JLabel calledByCallsLabel; String[] names_caller, names_callee; // private Object[][] MaximumValues = null; protected long sel_func; // Constructor public CalledByCallsDisp( final AnWindow awindow, final int type, final String help_id, final int ptype) { super(awindow, type, 0, help_id); caller_data = callee_data = null; parent_type = ptype; sel_func = 0; } private Object[] getTableData( final String mlistStr, final String modeStr, final String typeStr, final String subtypeStr, final long[] cstack) { // long t = System.currentTimeMillis(); Object[] data = window.getTableDataV2(mlistStr, modeStr, typeStr, subtypeStr, cstack); // t = System.currentTimeMillis() - t; // System.out.println("DEBUG: CallerCalleesDisp.getTableData(): time="+t+" mls."); return data; } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { StringBuilder buf = new StringBuilder(); buf.append(calledByCallsLabel.getText()); buf.append(" "); buf.append(names_caller[1]); buf.append("\n"); buf.append(caller.printTableContents(null, 0)); buf.append(calledByCallsLabel.getText()); buf.append(" "); buf.append(names_callee[1]); buf.append("\n"); buf.append(callee.printTableContents(null, 0)); return buf.toString(); } public AnTable getCallerTable() { return caller; } public AnTable getCalleeTable() { return callee; } class LocalProcessData { final String AccessToMaximumValues = "AccessToMaximumValues"; // Process the raw data from mixed Primary/Object to pure Object array. // Creates or updates MaximumValues. public Object[][] localProcessData(final Object[] raw_data) { int i; // Default values for MaximumValues AnAddress aa = new AnAddress(0); AnDouble ad = new AnDouble(0.0); AnInteger ai = new AnInteger(0); AnLong al = new AnLong(0); AnString as = new AnString(""); final int nc = raw_data.length - 1; final Object[][] data = new Object[nc][]; synchronized (AccessToMaximumValues) { MaximumValues = new Object[2][nc]; for (i = 0; i < nc; i++) { if (raw_data[i] instanceof double[]) { data[i] = AnDouble.toArray((double[]) raw_data[i]); MaximumValues[1][i] = ad; } else if (raw_data[i] instanceof int[]) { data[i] = AnInteger.toArray((int[]) raw_data[i]); MaximumValues[1][i] = ai; } else if (raw_data[i] instanceof long[]) { if ((((long[]) raw_data[i]).length == 0) || !AnAddress.isAddress(((long[]) raw_data[i])[0])) { data[i] = AnLong.toArray((long[]) raw_data[i]); MaximumValues[1][i] = al; } else { data[i] = AnAddress.toArray((long[]) raw_data[i]); MaximumValues[1][i] = aa; } } else { data[i] = (Object[]) raw_data[i]; MaximumValues[1][i] = as; } this.updateTotalMax(data[i], i); } for (i = 0; i < nc; i++) { // make sure there are no null elements in MaximumValues[1] if (MaximumValues[0][i] == null) { MaximumValues[0][i] = ad; } if (MaximumValues[1][i] == null) { MaximumValues[1][i] = ad; } } } return data; } /* * Updates MaximumValues (Total and Max values) * Note: Total is not used, so only Maximum is updated. */ void updateTotalMax(Object[] table_column, int index) { synchronized (AccessToMaximumValues) { double d0 = 0; for (int i = 0; i < table_column.length; i++) { if (MaximumValues[0][index] != null) { d0 = ((AnDouble) (MaximumValues[0][index])).doubleValue(); } if ((table_column[i] instanceof AnDouble)) { double d = ((AnDouble) table_column[i]).doubleValue(); d = d + d0; MaximumValues[0][index] = new AnDouble(d); } if ((table_column[i] instanceof AnInteger)) { double d = ((AnInteger) table_column[i]).doubleValue(); d = d + d0; MaximumValues[0][index] = new AnDouble(d); } if ((table_column[i] instanceof AnLong)) { double d = ((AnLong) table_column[i]).doubleValue(); d = d + d0; MaximumValues[0][index] = new AnDouble(d); } if (MaximumValues[1][index] == null) { MaximumValues[1][index] = table_column[i]; continue; } int j = MaximumValues[1][index].toString().length(); int k = table_column[i].toString().length(); if (j < k) { MaximumValues[1][index] = table_column[i]; } } } } /* * Returns MaximumValues (Total and Max values), calculated by processData() */ public Object[] getTotalMax() { synchronized (AccessToMaximumValues) { return MaximumValues; } } } // Initialize GUI components @Override protected void initComponents() { final JPanel pcaller; final JPanel pcallee; final JSplitPane splitPane1; Dimension msize; setLayout(new BorderLayout()); // Create table names and descriptions acNameT1 = AnLocale.getString("Callers Table"); acDescT1 = AnLocale.getString("Callers Table (shows functions that call selected function)"); acNameT3 = AnLocale.getString("Callees Table"); acDescT3 = AnLocale.getString( "Callers Table (shows functions that are called from selected function)"); // Create lables calledByCallsLabel = new JLabel(); Font monoSpacedFont = new Font("Monospaced", Font.BOLD, calledByCallsLabel.getFont().getSize()); calledByCallsLabel.setFont(monoSpacedFont); AnUtility.setAccessibleContext( calledByCallsLabel.getAccessibleContext(), AnLocale.getString("Selected function")); // Create tables caller = new AnTable( DSP_MiniCaller, true, false, true, false, true, false, false, acNameT1, acDescT1, null); // HERE table = caller; caller.setParent((AnDisplay) this); AccessibleContext context = caller.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Callers")); context.setAccessibleDescription(AnLocale.getString("Callers")); caller.addAnListener(new TabTableHandler()); caller.getTable().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); callee = new AnTable( DSP_MiniCallee, true, false, true, false, true, false, false, acNameT3, acDescT3, null); // HERE callee.setParent((AnDisplay) this); context = callee.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Callees")); context.setAccessibleDescription(AnLocale.getString("Callees")); callee.setHeader(caller); callee.addAnListener(new TabTableHandler()); callee.getTable().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); // Set header icons & tooltips pcaller = new JPanel(new BorderLayout()); pcaller.setBorder( BorderFactory.createMatteBorder(1, 0, 0, 1, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); pcaller.add(caller, BorderLayout.CENTER); pcallee = new JPanel(new BorderLayout()); pcallee.setBorder( BorderFactory.createMatteBorder(1, 1, 0, 0, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); pcallee.add(callee, BorderLayout.CENTER); // Set the split pane msize = pcaller.getMinimumSize(); msize.height = CALLER_MIN_HEIGHT; pcaller.setMinimumSize(msize); msize = pcallee.getMinimumSize(); msize.height = CALLEE_MIN_HEIGHT; pcallee.setMinimumSize(msize); msize.height = 100; msize.width = 50; splitPane1 = new AnSplitPane(JSplitPane.HORIZONTAL_SPLIT, pcaller, pcallee); splitPane1.setContinuousLayout(true); splitPane1.setResizeWeight(0.5); JPanel topPanel = new JPanel(); topPanel.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.weightx = 1.0; gridBagConstraints.anchor = GridBagConstraints.CENTER; gridBagConstraints.insets = new Insets(3, 0, 2, 0); topPanel.add(calledByCallsLabel, gridBagConstraints); add(topPanel, BorderLayout.NORTH); add(splitPane1, BorderLayout.CENTER); this.setPreferredSize(msize); } // Compute & update function list table @Override public synchronized void doCompute() { AnUtility.checkIfOnAWTThread(false); final int sc_pos; int name_len, len, row_height, height, i, j; Object[] raw_data; Object[] raw_data_with_ids; final int[] caller_stype, callee_stype; MetricLabel[] caller_label, callee_label; MetricLabel[] caller_sort_label, callee_sort_label; final int[][] caller_width, callee_width; AnObject obj, max_obj; final String mlistStr = "MET_CALL"; final String typeStrCaller; switch (parent_type) { case AnDisplay.DSP_Source: case AnDisplay.DSP_Lines: typeStrCaller = "LINE"; break; case AnDisplay.DSP_Disassembly: case AnDisplay.DSP_PCs: typeStrCaller = "INSTR"; break; default: typeStrCaller = "FUNCTION"; break; } final String typeStr = "FUNCTION"; final String subtypeStr; switch (parent_type) { case AnDisplay.DSP_Lines: case AnDisplay.DSP_PCs: subtypeStr = "1"; break; default: subtypeStr = "0"; break; } final String stab_callers = "CALLERS"; final String stab_callees = "CALLEES"; final String stab_self = "SELF"; final long[] cstack; // Not selected if (!selected) { return; } caller_label = callee_label = null; long func_obj = window.getSelectedObject().getSelObj(DSP_Functions, 0); if (sel_func == 0 || sel_func != func_obj) { computed = false; sel_func = func_obj; } if (!computed) { // need re-compute // sel_func = getFuncObj(); // Required to initialize Functions list // setFuncData(sel_func, type, subtype); table = caller; table.setViewport(); // Update stack /* * The caller-callee display will honor selections * made in other displays. */ long ID = window.getSelectedObject().getSelObjV2("FUNCTION"); long[] new_cstack = new long[1]; new_cstack[0] = ID; cstack = new_cstack; ids_cstack = cstack; // TEMPORARY // Get name String fname = window.getObjNameV2(ID); String[] new_names = new String[1]; new_names[0] = fname; ids_names = new_names; // TEMPORARY // Update callers list raw_data_with_ids = /* window. */ getTableData(mlistStr, stab_callers, typeStrCaller, subtypeStr, cstack); raw_data = new Object[raw_data_with_ids.length]; for (i = 0; i < raw_data.length; i++) { raw_data[i] = raw_data_with_ids[i]; } raw_data[raw_data.length - 1] = null; ids_callers = (long[]) raw_data_with_ids[raw_data_with_ids.length - 1]; caller_data_lpd = new LocalProcessData(); caller_data = caller_data_lpd.localProcessData(raw_data); caller_stype = (int[]) raw_data[raw_data.length - 1]; caller_label = getSettings() .getMetricsSetting() .getLabel( caller_data, caller_data_lpd.getTotalMax(/*DSP_CALLER, subtype*/ ), type, caller); name_col = getSettings().getMetricsSetting().getNameColumnIndexByDType(getMetricMType()); names = getNames(type, 0); sort_ind = getSortCol(); if (sort_ind == name_col) { sort_ind = (name_col == 0) ? 1 : 0; } if (sort_ind >= caller_data.length) { sort_ind = 0; } if (caller_data.length > 1) { caller_sort_data = new Object[2][]; caller_sort_label = new MetricLabel[2]; caller_sort_data[0] = caller_data[sort_ind]; caller_sort_label[0] = caller_label[sort_ind]; caller_sort_data[1] = caller_data[name_col]; caller_sort_label[1] = caller_label[name_col]; } else { caller_sort_data = caller_data; caller_sort_label = caller_label; } // Update callees list raw_data_with_ids = /* window. */ getTableData(mlistStr, stab_callees, typeStr, subtypeStr, cstack); raw_data = new Object[raw_data_with_ids.length]; for (i = 0; i < raw_data.length; i++) { raw_data[i] = raw_data_with_ids[i]; } raw_data[raw_data.length - 1] = null; ids_callees = (long[]) raw_data_with_ids[raw_data_with_ids.length - 1]; callee_data_lpd = new LocalProcessData(); callee_data = callee_data_lpd.localProcessData(raw_data); callee_stype = (int[]) raw_data[raw_data.length - 1]; /* TEMPORARY changes to support percentage calculation */ // Have to do it here, because Total was not calculated earlier callee_label = getSettings() .getMetricsSetting() .getLabel( callee_data, callee_data_lpd.getTotalMax(/*DSP_CALLEE, subtype*/ ), type, callee); if (callee_data.length > 1) { callee_sort_data = new Object[2][]; callee_sort_label = new MetricLabel[2]; callee_sort_data[0] = callee_data[sort_ind]; callee_sort_label[0] = callee_label[sort_ind]; callee_sort_data[1] = callee_data[name_col]; callee_sort_label[1] = callee_label[name_col]; } else { callee_sort_data = callee_data; callee_sort_label = callee_label; } // Update function name String[] funcNames = ids_names; String funcName = AnLocale.getString("Selected function"); if (funcNames != null && funcNames.length > 0) { funcName = (String) funcNames[0]; } // int index = funcName.indexOf('('); // if (index > 0) { // funcName = funcName.substring(0, index); // } calledByCallsLabel.setText(funcName); names_caller = new String[names.length]; names_callee = new String[names.length]; if (names.length > 1) { names_caller[0] = funcName; names_callee[0] = funcName; names_caller[1] = AnLocale.getString("is called by"); names_callee[1] = AnLocale.getString("calls"); } int sort_col = getSortCol(); if (sort_col == name_col) { sort_col = 1; } else { sort_col = 0; } // if (SwingUtilities.isEventDispatchThread()) { // caller.setData(caller_sort_label, caller_sort_data, names_caller, // caller_stype, // 0, (caller_data.length > 1) ? 1 : name_col, sort_col); // callee.setData(callee_sort_label, callee_sort_data, names_callee, // callee_stype, // 0, (callee_data.length > 1) ? 1 : name_col, sort_col); // caller.repaint(); // callee.repaint(); // } else { { // Use SwingUtilities to update tables final MetricLabel[] label1 = caller_sort_label; final MetricLabel[] label3 = callee_sort_label; // try { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { int sort_col = getSortCol(); if (sort_col == name_col) { sort_col = 1; } else { sort_col = 0; } getCallerTable() .setData( label1, caller_sort_data, names_caller, caller_stype, 0, (caller_data.length > 1) ? 1 : name_col, sort_col); getCalleeTable() .setData( label3, callee_sort_data, names_callee, callee_stype, 0, (callee_data.length > 1) ? 1 : name_col, sort_col); getCallerTable().repaint(); getCalleeTable().repaint(); } }); // } catch (Exception exc) { // System.out.println("CallDisp.recompute() exception: " + exc); // exc.printStackTrace(); // } } } // Set the column width if (caller_label != null) { // Find the 'name' object which has the maximum width max_obj = caller_label[name_col].getMaxAnObject(); name_len = caller.stringWidth(max_obj.toString()); obj = callee_label[name_col].getMaxAnObject(); len = callee.stringWidth(obj.toString()); if (name_len < len) { // name_len = len; // assignment is never used max_obj = obj; } caller_label[name_col].setMaxAnObject(max_obj); callee_label[name_col].setMaxAnObject(max_obj); // Find the maximum row height row_height = caller.getRowHeight(); height = callee.getRowHeight(); if (row_height < height) { row_height = height; } // Find the maximum width for each field caller_width = caller.getColumnWidth(); callee_width = callee.getColumnWidth(); for (i = 0; i < caller_width.length; i++) { for (j = 0; j < 4; j++) { if (caller_width[i][j] < callee_width[i][j]) { caller_width[i][j] = callee_width[i][j]; } } } // Set column height/width for caller/func/callee caller.setColumn(row_height); callee.setColumn(row_height); caller.clearSelectedRow(); callee.clearSelectedRow(); sc_pos = callee.getScroll(); caller.setScroll(sc_pos); } computed = true; } private int getSortCol() { int ret = -1; int func_sort_ind = getSettings().getMetricsSetting().getSortColumnByDType(AnDisplay.DSP_Functions); AnMetric[] func_mlist = getSettings().getMetricsSetting().getMetricListByMType(MetricsSetting.MET_NORMAL); AnMetric[] cc_mlist = getSettings().getMetricsSetting().getMetricListByMType(MetricsSetting.MET_CALL); for (int ind = 0; ind < cc_mlist.length; ind++) { if (cc_mlist[ind].getUserName().equals(func_mlist[func_sort_ind].getUserName())) { ret = ind; break; } } if (ret == -1) { ret = getSettings().getMetricsSetting().getSortColumnByDType(type); } return ret; } // Is current selected tab? public void setSelected(final boolean set) { selected = set; } // Listener for updating table private final class TabTableHandler implements AnListener { @Override public void valueChanged(final AnEvent event) { final AnTable src = (AnTable) event.getSource(); final int loc, from, to, column, width; boolean double_click = false; int index = event.getValue(); switch (event.getType()) { case AnEvent.EVT_SELECT: // Selecting // changeSelection(src, index); break; case AnEvent.EVT_COMPUTE: // Compute and Update changeSelection(src, index); break; case AnEvent.EVT_SORT: // Sorting getSettings() .getMetricsSetting() .setSortMetricByDType(this, getSortCol(), getMetricMType()); break; case AnEvent.EVT_COPY_ALL: // Copy all lines copyAll(); break; case AnEvent.EVT_COPY_SEL: // Copy selected lines copySelected(); break; case AnEvent.EVT_SCROLL: // Scrolling if (src == getCalleeTable()) { loc = event.getValue(); getCallerTable().setScroll(loc); func_item.setScroll(loc); } break; case AnEvent.EVT_SWITCH: // Column switching from = event.getValue(); to = ((Integer) event.getAux()).intValue(); getSettings().getMetricsSetting().setMetricOrderByDType(this, from, to, getMetricMType()); break; case AnEvent.EVT_RESIZE: // Column resizing if (src == getCallerTable()) { column = event.getValue(); width = ((Integer) event.getAux()).intValue(); func_item.setColumnWidth(column, width); getCalleeTable().setColumnWidth(column, width); } break; } } } @Override public void changeSelection(AnTable src, int index) { long ID = -1; if (index >= 0) { // clearSelections(); if (src == caller) { if (index < ids_callers.length) { ID = ids_callers[index]; } } else if (src == callee) { if (index < ids_callees.length) { ID = ids_callees[index]; } } if (ID > 0) { src.setSelectedRow(index); // AWT // cc_callstack.setSelectedObject(ID); //NM Hack // cc_callstack.saveSelection(ID, src, index); //NM Hack // window.computeFuncData(); //NM Update Summary // window.showSummary(); // AWT final long id = ID; final int ix = index; final AnTable at = src; AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { if (at == getCallerTable() && (parent_type == AnDisplay.DSP_Source || parent_type == AnDisplay.DSP_Disassembly)) { window.getSelectedObject().setSelObjWithEvent(id, DSP_MiniCaller, 0); } else { window.getSelectedObject().setSelObjV2WithEvent(id); } // //window.computeFuncData(); //NM Update Summary // switch (parent_type) { // case AnDisplay.DSP_SOURCE: // window.computeSrcData(); // break; // case AnDisplay.DSP_DISASM: // window.computeDisData(); // break; // case AnDisplay.DSP_FUNCTION: // window.computeFuncData(); // break; // default: // break; // } } }, "CallTree_thread"); } } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/DataObjectsView.java�����������������������������������������������0000644�0001750�0001750�00000007353�14517772113�017626� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import javax.swing.JPanel; public final class DataObjectsView extends FuncListDisp implements AnChangeListener { public DataObjectsView() { super(AnWindow.getInstance(), AnDisplay.DSP_DataObjects, 0, AnVariable.HELP_TabsDataObjects); setAccessibility(AnLocale.getString("Data Objects")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("DataObjectsView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public JPanel getToolbarPanel() { return null; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�015326� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/CheckBoxList.java�������������������������������������������0000644�0001750�0001750�00000005502�14517772113�020417� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.remote; import java.awt.Component; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.JList; import javax.swing.ListCellRenderer; import javax.swing.ListSelectionModel; public class CheckBoxList extends JList<JCheckBox> { private DefaultListModel<JCheckBox> model; public CheckBoxList() { model = new DefaultListModel<JCheckBox>(); setModel(model); setSelectionMode(ListSelectionModel.SINGLE_SELECTION); setCellRenderer(new CellRenderer()); addKeyListener( new KeyAdapter() { @Override public void keyTyped(KeyEvent evt) { super.keyTyped(evt); if (evt.getKeyChar() == ' ') { JCheckBox checkBox = getSelectedValue(); if (checkBox != null) { checkBox.setSelected(!checkBox.isSelected()); repaint(100); } } } }); addMouseListener( new MouseAdapter() { @Override public void mousePressed(MouseEvent evt) { if (evt.getX() < 20) { int row = locationToIndex(evt.getPoint()); JCheckBox checkBox = model.getElementAt(row); if (checkBox != null) { checkBox.setSelected(!checkBox.isSelected()); repaint(100); } } } }); } private class CellRenderer implements ListCellRenderer<JCheckBox> { @Override public Component getListCellRendererComponent( JList<? extends JCheckBox> list, JCheckBox checkBox, int index, boolean isSelected, boolean cellHasFocus) { if (isSelected) { checkBox.setBackground(getSelectionBackground()); checkBox.setForeground(getSelectionForeground()); } else { checkBox.setBackground(getBackground()); checkBox.setForeground(getForeground()); } return checkBox; } } public void addElement(JCheckBox checkBox) { model.addElement(checkBox); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/ConnectionPanel.java����������������������������������������0000644�0001750�0001750�00000034560�14517772113�021162� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.remote; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.util.gui.AnDialog2; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Font; import java.util.List; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JPasswordField; import javax.swing.JProgressBar; import javax.swing.JTextArea; import javax.swing.JTextField; public class ConnectionPanel extends JPanel { private final ConnectionDialog connectionDialog; /** Creates new form ConnectionPanel */ public ConnectionPanel(ConnectionDialog connectionDialog) { this.connectionDialog = connectionDialog; initComponents(); setOpaque(false); AnUtility.setAccessibleContext( messageTextArea.getAccessibleContext(), AnLocale.getString("Information Area")); messageTextArea.setBackground(AnEnvironment.DEFAULT_TEXT_PANE_RO_BACKGROUND); hostNameComboBox.setPrototypeDisplayValue("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"); hostNameComboBox.setFont(hostNameComboBox.getFont().deriveFont(Font.PLAIN)); hostNameLabel.setText(AnLocale.getString("Host Name:")); hostNameLabel.setToolTipText(AnLocale.getString("Name of the remote system")); hostNameLabel.setDisplayedMnemonic(AnLocale.getString('o', "RemoteDialogHostNameLabelMN")); hostNameLabel.setLabelFor(hostNameComboBox); authenticationLabel.setText(AnLocale.getString("Authentication:")); authenticationLabel.setToolTipText(AnLocale.getString("Autentication methods")); authenticationManageButton.setText(AnLocale.getString("Manage")); authenticationManageButton.setToolTipText(AnLocale.getString("Manage authentication methods")); authenticationManageButton.setMnemonic(AnLocale.getString('M', "AuthenticationManageButton")); userNameLabel.setText(AnLocale.getString("User Name:")); userNameLabel.setToolTipText( AnLocale.getString("User name of the account to log in to the remote system")); userNameLabel.setDisplayedMnemonic(AnLocale.getString('u', "RemoteDialogUserNameLabelMN")); userNameLabel.setLabelFor(userNameTextField); passWordLabel.setText(AnLocale.getString("Password:")); passWordLabel.setToolTipText( AnLocale.getString("Password for the account to log in to the remote system")); passWordLabel.setDisplayedMnemonic(AnLocale.getString('p', "RemoteDialogPasswordLabelMN")); passWordLabel.setLabelFor(passwordField); solstudioPathLabel.setText(AnLocale.getString("Installation Path:")); solstudioPathLabel.setToolTipText( AnLocale.getString( "Full path to the gprofng installation accessible on the remote system")); solstudioPathLabel.setDisplayedMnemonic(AnLocale.getString('I', "RemoteDialogPathLabelMN")); solstudioPathLabel.setLabelFor(solstudioPathTextField); connectionStatusLabel.setText(AnLocale.getString("Connection Status:")); connectionStatusLabel.setToolTipText(AnLocale.getString("Status of connection")); connectionStatusValueLabel.setFont(connectionStatusValueLabel.getFont().deriveFont(Font.PLAIN)); AnUtility.setAccessibleContext( authenticationTextField.getAccessibleContext(), AnLocale.getString("Authentications")); AnUtility.setAccessibleContext( connectionStatusValueLabel.getAccessibleContext(), AnLocale.getString("Status of connection")); AnUtility.setAccessibleContext( connectionProgressBar.getAccessibleContext(), AnLocale.getString("Progress")); // For now userNameTextField.setText(""); passwordField.setText(""); } public void setLoginFieldsEnabled(boolean remote) { if (!remote) { // local host solstudioPathLabel.setEnabled(false); solstudioPathTextField.setEnabled(false); } else { solstudioPathLabel.setEnabled(true); solstudioPathTextField.setEnabled(true); } } public JProgressBar getConnectionProgressBar() { return connectionProgressBar; } public JTextArea getMessageTextArea() { return messageTextArea; } public JLabel getConnectionStatusValueLabel() { return connectionStatusValueLabel; } public JComboBox getHostNameComboBox() { return hostNameComboBox; } public JPasswordField getPasswordField() { return passwordField; } public JTextField getSolstudioPathTextField() { return solstudioPathTextField; } public JTextField getAuthenticationTextField() { return authenticationTextField; } public JButton getAuthenticationManageButton() { return authenticationManageButton; } public JTextField getUserNameTextField() { return userNameTextField; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; hostNameLabel = new javax.swing.JLabel(); hostNameComboBox = new javax.swing.JComboBox(); authenticationLabel = new javax.swing.JLabel(); authenticationTextField = new javax.swing.JTextField(); authenticationManageButton = new javax.swing.JButton(); userNameLabel = new javax.swing.JLabel(); userNameTextField = new javax.swing.JTextField(); passWordLabel = new javax.swing.JLabel(); passwordField = new javax.swing.JPasswordField(); solstudioPathLabel = new javax.swing.JLabel(); solstudioPathTextField = new javax.swing.JTextField(); connectionStatusLabel = new javax.swing.JLabel(); connectionStatusValueLabel = new javax.swing.JLabel(); messageTextScrollPane = new javax.swing.JScrollPane(); messageTextArea = new javax.swing.JTextArea(); connectionProgressBar = new javax.swing.JProgressBar(); setLayout(new java.awt.GridBagLayout()); hostNameLabel.setText("Host name:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); add(hostNameLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 4, 0, 0); add(hostNameComboBox, gridBagConstraints); authenticationLabel.setText("Authentication:"); authenticationLabel.setToolTipText(""); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); add(authenticationLabel, gridBagConstraints); authenticationTextField.setEditable(false); authenticationTextField.setColumns(40); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.RELATIVE; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 4, 0, 0); add(authenticationTextField, gridBagConstraints); authenticationManageButton.setText("Manage"); authenticationManageButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { authenticationManageButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 4, 0, 0); add(authenticationManageButton, gridBagConstraints); userNameLabel.setText("User name:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(userNameLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(8, 4, 0, 0); add(userNameTextField, gridBagConstraints); passWordLabel.setText("Password:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(passWordLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.insets = new java.awt.Insets(8, 4, 0, 0); add(passwordField, gridBagConstraints); solstudioPathLabel.setText("Remote SolStudio Path:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(solstudioPathLabel, gridBagConstraints); solstudioPathTextField.setColumns(40); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.RELATIVE; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(8, 4, 0, 0); add(solstudioPathTextField, gridBagConstraints); connectionStatusLabel.setText("Connection Status:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(8, 0, 0, 0); add(connectionStatusLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(8, 8, 0, 0); add(connectionStatusValueLabel, gridBagConstraints); messageTextArea.setEditable(false); messageTextArea.setLineWrap(true); messageTextArea.setRows(6); messageTextArea.setWrapStyleWord(true); messageTextScrollPane.setViewportView(messageTextArea); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); add(messageTextScrollPane, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.PAGE_END; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(connectionProgressBar, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void authenticationManageButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_authenticationManageButtonActionPerformed AnDialog2 dialog = new AnDialog2(connectionDialog, this, AnLocale.getString("Manage Authentications")); AuthenticationPanel authenticationsPanel = new AuthenticationPanel(dialog, connectionDialog.getAuthenticationsCopy()); dialog.setCustomPanel(authenticationsPanel); dialog.setHelpTag(AnVariable.HELP_ConnectAuthentication); dialog.setVisible(true); if (dialog.getStatus() == AnDialog2.Status.OK) { // Not Cancel List<Authentication> authentications = authenticationsPanel.getAuthentications(); connectionDialog.setAuthentications(authentications); } } // GEN-LAST:event_authenticationManageButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel authenticationLabel; private javax.swing.JButton authenticationManageButton; private javax.swing.JTextField authenticationTextField; private javax.swing.JProgressBar connectionProgressBar; private javax.swing.JLabel connectionStatusLabel; private javax.swing.JLabel connectionStatusValueLabel; private javax.swing.JComboBox hostNameComboBox; private javax.swing.JLabel hostNameLabel; private javax.swing.JTextArea messageTextArea; private javax.swing.JScrollPane messageTextScrollPane; private javax.swing.JLabel passWordLabel; private javax.swing.JPasswordField passwordField; private javax.swing.JLabel solstudioPathLabel; private javax.swing.JTextField solstudioPathTextField; private javax.swing.JLabel userNameLabel; private javax.swing.JTextField userNameTextField; // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/AuthenticationPanel.form������������������������������������0000644�0001750�0001750�00000017043�14517772113�022061� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,4,120,0,0,2,78"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JTextArea" name="infoTextArea"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="lineWrap" type="boolean" value="true"/> <Property name="wrapStyleWord" type="boolean" value="true"/> <Property name="opaque" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="19" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="prefAutenticationsLabel"> <Properties> <Property name="text" type="java.lang.String" value="Preferred Authentications:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="10" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="23" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="authenticationsPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="11" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Container> <Container class="javax.swing.JPanel" name="buttonPanel"> <Properties> <Property name="opaque" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="6" insetsBottom="0" insetsRight="0" anchor="19" weightX="0.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JButton" name="upButton"> <Properties> <Property name="text" type="java.lang.String" value="Up"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="upButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="11" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="downButton"> <Properties> <Property name="text" type="java.lang.String" value="Down"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="downButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="11" weightX="0.0" weightY="1.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> <Component class="javax.swing.JLabel" name="errorLabel"> <Properties> <Property name="foreground" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> <Color blue="0" green="0" red="ff" type="rgb"/> </Property> <Property name="text" type="java.lang.String" value="Error dsadsa dsadsaldsa dsadsa "/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="25" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/AuthenticationPanel.java������������������������������������0000644�0001750�0001750�00000025642�14517772113�022043� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.remote; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.util.gui.AnDialog2; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Dimension; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.util.List; import javax.swing.BorderFactory; import javax.swing.DefaultListModel; import javax.swing.JCheckBox; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; public class AuthenticationPanel extends javax.swing.JPanel { private AnDialog2 dialog; private List<Authentication> data; private CheckBoxList checkBoxList; public AuthenticationPanel(AnDialog2 dialog, List<Authentication> authentications) { this.dialog = dialog; this.data = authentications; initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); infoTextArea.setText( AnLocale.getString( "Select the preferred authentication methods and their order. At least one method must" + " be selected.")); AnUtility.setAccessibleContext(infoTextArea.getAccessibleContext(), AnLocale.getString("Info")); AnUtility.setTextAndAccessibleContext(upButton, AnLocale.getString("Up")); upButton.setMnemonic(AnLocale.getString('U', "AuthenticationPanel.UpButton")); AnUtility.setTextAndAccessibleContext(downButton, AnLocale.getString("Down")); downButton.setMnemonic(AnLocale.getString('D', "AuthenticationPanel.DownButton")); AnUtility.setTextAndAccessibleContext( prefAutenticationsLabel, AnLocale.getString("Preferred Authentication Methods:")); prefAutenticationsLabel.setDisplayedMnemonic( AnLocale.getString('P', "AuthenticationPanel.AutenticationsLabel")); checkBoxList = new CheckBoxList(); for (Authentication auth : authentications) { final Authentication authentication = auth; final JCheckBox checkBox = new JCheckBox(auth.getType().getName()); checkBox.setSelected(auth.isOn()); checkBoxList.addElement(checkBox); checkBox.addItemListener( new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { authentication.setOn(checkBox.isSelected()); updateStates(); } }); } prefAutenticationsLabel.setLabelFor(checkBoxList); checkBoxList.setSelectedIndex(0); updateStates(); authenticationsPanel.add(checkBoxList); authenticationsPanel.setBorder( BorderFactory.createLineBorder(AnEnvironment.STATUS_PANEL_BORDER_COLOR)); setPreferredSize(new Dimension(400, 200)); checkBoxList .getSelectionModel() .addListSelectionListener( new ListSelectionListener() { @Override public void valueChanged(ListSelectionEvent e) { updateStates(); } }); } private void setErrorText(String text) { errorLabel.setText(text); } private void updateStates() { upButton.setEnabled(false); downButton.setEnabled(false); setErrorText(""); dialog.getOKButton().setEnabled(true); if (data != null && data.size() > 0) { if (checkBoxList.getSelectedIndex() > 0) { upButton.setEnabled(true); } if (checkBoxList.getSelectedIndex() < data.size() - 1) { downButton.setEnabled(true); } } boolean atLeastOneSelected = false; for (Authentication auth : data) { if (auth.isOn()) { atLeastOneSelected = true; break; } } if (!atLeastOneSelected) { setErrorText(AnLocale.getString("At least one authentication method needs to be selected.")); dialog.getOKButton().setEnabled(false); } } private void updateSelection(int selectedIndex) { if (selectedIndex >= 0 && selectedIndex <= data.size()) { checkBoxList.setSelectedIndex(selectedIndex); checkBoxList.ensureIndexIsVisible(selectedIndex); } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; infoTextArea = new javax.swing.JTextArea(); prefAutenticationsLabel = new javax.swing.JLabel(); authenticationsPanel = new javax.swing.JPanel(); buttonPanel = new javax.swing.JPanel(); upButton = new javax.swing.JButton(); downButton = new javax.swing.JButton(); errorLabel = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); infoTextArea.setEditable(false); infoTextArea.setLineWrap(true); infoTextArea.setWrapStyleWord(true); infoTextArea.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.PAGE_START; gridBagConstraints.weightx = 1.0; add(infoTextArea, gridBagConstraints); prefAutenticationsLabel.setText("Preferred Authentications:"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(10, 0, 0, 0); add(prefAutenticationsLabel, gridBagConstraints); authenticationsPanel.setLayout(new java.awt.BorderLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); add(authenticationsPanel, gridBagConstraints); buttonPanel.setOpaque(false); buttonPanel.setLayout(new java.awt.GridBagLayout()); upButton.setText("Up"); upButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { upButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; buttonPanel.add(upButton, gridBagConstraints); downButton.setText("Down"); downButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { downButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); buttonPanel.add(downButton, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.PAGE_START; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(2, 6, 0, 0); add(buttonPanel, gridBagConstraints); errorLabel.setForeground(new java.awt.Color(255, 0, 0)); errorLabel.setText("Error dsadsa dsadsaldsa dsadsa "); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LAST_LINE_START; add(errorLabel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void upButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_upButtonActionPerformed int selectedIndex = checkBoxList.getSelectedIndex(); if (selectedIndex > 0) { // Update data Authentication auth = data.get(selectedIndex); data.remove(selectedIndex); data.add(selectedIndex - 1, auth); // Update GUI JCheckBox checkBox = checkBoxList.getModel().getElementAt(selectedIndex); ((DefaultListModel) checkBoxList.getModel()).remove(selectedIndex); ((DefaultListModel) checkBoxList.getModel()).add(selectedIndex - 1, checkBox); updateSelection(selectedIndex - 1); } } // GEN-LAST:event_upButtonActionPerformed private void downButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_downButtonActionPerformed int selectedIndex = checkBoxList.getSelectedIndex(); if (selectedIndex < data.size()) { // Update data Authentication auth = data.get(selectedIndex); data.remove(selectedIndex); data.add(selectedIndex + 1, auth); // Update GUI JCheckBox checkBox = checkBoxList.getModel().getElementAt(selectedIndex); ((DefaultListModel) checkBoxList.getModel()).remove(selectedIndex); ((DefaultListModel) checkBoxList.getModel()).add(selectedIndex + 1, checkBox); updateSelection(selectedIndex + 1); } } // GEN-LAST:event_downButtonActionPerformed protected List<Authentication> getAuthentications() { return data; } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel authenticationsPanel; private javax.swing.JPanel buttonPanel; private javax.swing.JButton downButton; private javax.swing.JLabel errorLabel; private javax.swing.JTextArea infoTextArea; private javax.swing.JLabel prefAutenticationsLabel; private javax.swing.JButton upButton; // End of variables declaration//GEN-END:variables } ����������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/CloseExperimentPanel.java�����������������������������������0000644�0001750�0001750�00000006136�14517772113�022167� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.remote; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import javax.swing.JPanel; import javax.swing.border.MatteBorder; public class CloseExperimentPanel extends JPanel { public CloseExperimentPanel() { initComponents(); // setOpaque(false); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); setBorder(new MatteBorder(12, 12, 12, 12, (Color) null)); AnUtility.setTextAndAccessibleContext( label1, AnLocale.getString( "gprofng GUI cannot connect to a remote host when there are open" + " experiments.")); AnUtility.setTextAndAccessibleContext( label2, AnLocale.getString("Close the experiment(s) before continuing?")); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; label1 = new javax.swing.JLabel(); label2 = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); label1.setText("jLabel1"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; add(label1, gridBagConstraints); label2.setText("jLabel2"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); add(label2, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel label1; private javax.swing.JLabel label2; // End of variables declaration//GEN-END:variables } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/Authentication.java�����������������������������������������0000644�0001750�0001750�00000011503�14517772113�021052� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.remote; import org.gprofng.mpmt.persistence.UserPref; import java.util.ArrayList; import java.util.List; public class Authentication { public enum Type { PASSWORD("Password", "password"), PUBLIC_KEY("Public key", "publickey"), KEYBOARD_INTERACTIVE("Keyboard-interactive", "keyboard-interactive"); private String name; private String keyName; private Type(String name, String keyName) { this.name = name; this.keyName = keyName; } public String getName() { return name; } public String getKeyName() { return keyName; } protected static Type fromString(String s) { for (Type type : Type.values()) { if (type.toString().equals(s)) { return type; } } return null; } }; private Type type; private boolean on; public Authentication(Type type, boolean on) { this.on = on; this.type = type; } public Authentication copy() { return new Authentication(type, on); } public Type getType() { return type; } public boolean isOn() { return on; } public void setOn(boolean on) { this.on = on; } /** * @return the default set of authentication methods */ public static List<Authentication> getDefaultAuthentications() { List<Authentication> def = new ArrayList<Authentication>(); def.add(new Authentication(Authentication.Type.PUBLIC_KEY, true)); def.add(new Authentication(Authentication.Type.PASSWORD, true)); // def.add(new Authentication(Authentication.Type.KEYBOARD_INTERACTIVE, false)); // Don't // offer KEYBOARD_INTERACTIVE for now.... return def; } /* * @return "Public key, Password" * Used in dialog. Uses 'user names' and shows only those that are on */ public static String toString(List<Authentication> authentications) { StringBuilder buf = new StringBuilder(); boolean first = true; for (Authentication auth : authentications) { if (auth.isOn()) { if (first) { first = false; } else { buf.append(", "); } buf.append(auth.getType().getName()); } } return buf.toString(); } /** * @param authentications * @return "PUBLIC_KEY=true,PASSWORD=true,KEYBOARD_INTERACTIVE=false" Used in persistence */ public static String toXMLString(List<Authentication> authentications) { StringBuilder buf = new StringBuilder(); boolean first = true; for (Authentication auth : authentications) { if (first) { first = false; } else { buf.append(","); } buf.append(auth.getType() + "=" + auth.isOn()); } return buf.toString(); } /** * @param xmlString * @return Parses output from toXMLString(): * "PUBLIC_KEY=true,PASSWORD=true,KEYBOARD_INTERACTIVE=false" Used in persistence. */ public static List<Authentication> fromXMLString(String xmlString) { String[] auths = xmlString.split(","); List<Authentication> list = new ArrayList<Authentication>(); for (String auth : auths) { String[] s = auth.split("="); Authentication.Type type = Type.fromString(s[0]); if (type == Authentication.Type .KEYBOARD_INTERACTIVE) { // Don't offer KEYBOARD_INTERACTIVE for now.... continue; } if (s.length != 2) { // Abort return null; } boolean on = s[1].equals("true"); if (type != null) { list.add(new Authentication(type, on)); } else { // Abort, just return the default list... list = UserPref.getDefaultAuthentications(); } } return list; } /** * @param authentications * @return "publickey,password", only the keys for methods selected. Used when connecting. */ public static String toKeyString(List<Authentication> authentications) { StringBuilder buf = new StringBuilder(); boolean first = true; for (Authentication auth : authentications) { if (!auth.isOn()) { continue; } if (first) { first = false; } else { buf.append(","); } buf.append(auth.getType().getKeyName()); } return buf.toString(); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/CloseExperimentPanel.form�����������������������������������0000644�0001750�0001750�00000006450�14517772113�022210� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-71"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="label1"> <Properties> <Property name="text" type="java.lang.String" value="jLabel1"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="label2"> <Properties> <Property name="text" type="java.lang.String" value="jLabel2"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/ConnectionManager.java��������������������������������������0000644�0001750�0001750�00000035203�14517772113�021470� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.remote; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCLogger; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.util.gui.AnUtility; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JDialog; import javax.swing.JOptionPane; /** * ConnectionManager thread creates and manages ConnectionChecker thread, which sends * "checkConnection" IPC calls. * * <p>Sets interface variables doCheck and defaultTimeOut. * * <p>Uses interface variables connectionStatus and connectionCheckerState. */ public class ConnectionManager extends Thread { int CC_defaultTimeOut = 2000; // 2 seconds int CM_defaultTimeOut = 10000; // 10 seconds int CONNECTION_UNKNOWN = 0; int CONNECTION_OK = 1; int CONNECTION_LOST = 2; int CONNECTION_CHECK = 3; volatile int connectionStatus = CONNECTION_UNKNOWN; int CM_NO_CHECK = 0; int CM_CHECK = 1; volatile int connectionManagerStatus = CM_CHECK; ConnectionChecker cc = null; Boolean doCheck = false; String threadName = "Connection Manager"; JDialog CM_warn_dialog = null; /** Default ConnectionManager constructor. */ public ConnectionManager() { this.setName(threadName); } /** Main method. */ public void run() { AnWindow anWindow = AnWindow.getInstance(); String err_cc_msg = "ERROR: Cannot create ConnectionChecker"; String warn_msg = AnLocale.getString("Lost connection to remote host "); String warn_title = AnLocale.getString("Warning: Connection is lost"); String conf_msg = AnLocale.getString("Are you sure you want to exit gprofng GUI"); String conf_title = AnLocale.getString("Exit gprofng GUI?"); // System.err.println("ConnectionManager started"); // DEBUG try { String str = AnUtility.getenv("SP_ANALYZER_HEARTBEAT_DISABLE"); if (str != null) { // System.err.println("analyzer: SP_ANALYZER_HEARTBEAT_DISABLE is set"); DEBUG IPCLogger.logTrace("\n" + "analyzer: SP_ANALYZER_HEARTBEAT_DISABLE is set"); connectionManagerStatus = CM_NO_CHECK; } str = AnUtility.getenv("SP_ANALYZER_HEARTBEAT_MSEC"); if (str != null) { // set timeout value // System.err.println("analyzer: SP_ANALYZER_HEARTBEAT_MSEC=" + str); DEBUG IPCLogger.logTrace("\n" + "analyzer: SP_ANALYZER_HEARTBEAT_MSEC=" + str); Integer tm = new Integer(str); setTimeOut(tm.intValue()); } long ts_start_checking = 0; while (CC_defaultTimeOut > 0) { if ((connectionManagerStatus != CM_NO_CHECK) && (Analyzer.getInstance().isRemote())) { if (null != cc) { if (cc.connectionCheckerState == cc.CHECKER_FINISHED) { // System.err.println("ConnectionChecker finished"); // DEBUG cc.join(); // System.err.println("ConnectionChecker joined"); // DEBUG cc = new ConnectionChecker(); if (null == cc) { Logger.getLogger(ConnectionManager.class.getName()) .log(Level.SEVERE, null, err_cc_msg); // System.err.println(err_cc_msg); // DEBUG return; } cc.start(); // System.err.println("ConnectionChecker started"); // DEBUG } } else { cc = new ConnectionChecker(); if (null == cc) { Logger.getLogger(ConnectionManager.class.getName()) .log(Level.SEVERE, null, err_cc_msg); // System.err.println(err_cc_msg); // DEBUG return; } cc.start(); // System.err.println("ConnectionChecker started"); // DEBUG } if (connectionStatus == CONNECTION_LOST) { if (cc.connectionCheckerState == cc.CHECKER_FINISHED) { // System.err.println("ConnectionChecker finished"); // DEBUG cc.join(); // System.err.println("ConnectionChecker joined"); // DEBUG cc = null; } // Show error dialog String sWait = AnLocale.getString("Wait"); String sExit = AnLocale.getString("Exit"); String host = Analyzer.getInstance().getRemoteHost(); int at = host.indexOf("@"); if (at >= 0) { host = host.substring(at + 1); } Object[] options = {sWait, sExit}; JOptionPane pane = new JOptionPane( warn_msg + host, JOptionPane.WARNING_MESSAGE, JOptionPane.DEFAULT_OPTION, null, options, options[0]); // Use CM_warn_dialog to allow ConnectionChecker thread to close it CM_warn_dialog = pane.createDialog(anWindow.getFrame(), warn_title); CM_warn_dialog.setVisible(true); Object selectedValue = pane.getValue(); CM_warn_dialog = null; // Sync with ConnectionChecker // There are 2 choices: "Wait" and "Exit" // System.err.println("selectedValue:" + selectedValue); // DEBUG int choice = 0; // Cancel means Wait if (selectedValue instanceof Integer) { choice = ((Integer) selectedValue).intValue(); if (choice != 1) choice = 0; // Wait } if (selectedValue instanceof String) { if (sExit.equals(selectedValue)) choice = 1; // Exit } // Exit - stop ConnectionChecker and exit if (sExit.equals(options[choice])) { // Show confirmation dialog selectedValue = JOptionPane.showConfirmDialog( anWindow.getFrame(), conf_msg, conf_title, JOptionPane.YES_NO_OPTION); // System.err.println("selectedValue:" + selectedValue); // DEBUG if (selectedValue instanceof Integer) { choice = ((Integer) selectedValue).intValue(); } if (choice == 0) { // YES stopChecking(); if (null != cc) { cc.interrupt(); cc.join(CC_defaultTimeOut * 2); // System.err.println("ConnectionChecker joined."); // DEBUG cc = null; } // System.err.println("Exiting..."); // DEBUG AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { AnWindow.getInstance().exitAction(); } }); return; } } // Restore connectionStatus to CONNECTION_CHECK connectionStatus = CONNECTION_CHECK; // Wait if (null == cc) { cc = new ConnectionChecker(); if (null == cc) { Logger.getLogger(ConnectionManager.class.getName()) .log(Level.SEVERE, null, err_cc_msg); // System.err.println(err_cc_msg); // DEBUG return; } cc.start(); } // Wait for next timeout ts_start_checking = System.currentTimeMillis(); // System.err.println("Waiting..."); // DEBUG startChecking(); } if (connectionStatus == CONNECTION_CHECK) { if (ts_start_checking != 0) { long ts = System.currentTimeMillis(); long dts = ts - ts_start_checking; if (dts > CM_defaultTimeOut) { connectionStatus = CONNECTION_LOST; continue; } } else { ts_start_checking = System.currentTimeMillis(); } } if (connectionStatus == CONNECTION_OK) { ts_start_checking = 0; } } try { sleep(CC_defaultTimeOut / 4); // Check more often } catch (InterruptedException ex) { // Logger.getLogger(ConnectionManager.class.getName()).log(Level.SEVERE, null, ex); } } if (null != cc) { // System.err.println("ConnectionChecker interrupted"); // DEBUG cc.interrupt(); cc.join(CC_defaultTimeOut * 2); cc = null; // System.err.println("ConnectionChecker joined"); // DEBUG } } catch (InterruptedException ex) { Logger.getLogger(ConnectionManager.class.getName()).log(Level.SEVERE, null, ex); } // System.err.println("ConnectionManager finished"); // DEBUG } /** * Sets default timeout value. Minimum: 100 milliseconds * * @param timeout * @return defaultTimeOut */ public int setTimeOut(int timeout) { if (timeout < 100) { timeout = 100; // not less than 100 milliseconds } CC_defaultTimeOut = timeout; return CC_defaultTimeOut; } /** * Gets default timeout value * * @return defaultTimeOut */ public int getTimeOut() { return CC_defaultTimeOut; } /** Sets "Start Checking" flag. */ public void startChecking() { // System.err.println("startChecking"); // DEBUG doCheck = true; } /** Sets "Stop Checking" flag. */ public void stopChecking() { // System.err.println("stopChecking"); // DEBUG doCheck = false; } /** * Thread ConnectionChecker sends "checkConnection" IPC calls. Uses interface variables doCheck * and defaultTimeOut. Sets interface variables connectionStatus and connectionCheckerState. */ private class ConnectionChecker extends Thread { int CHECKER_NOT_IN_IPC = 0; // Not in IPC call int CHECKER_IN_IPC = 1; // In IPC call int CHECKER_FINISHED = 2; volatile int connectionCheckerState = CHECKER_NOT_IN_IPC; String threadName = "Connection Checker"; /** Default ConnectionChecker constructor. */ public ConnectionChecker() { this.setName(threadName); } /** * Check Connection * * @return res */ private int checkConnection() { int res = 0; long ts0, ts1; long n = 1; AnWindow anWindow = AnWindow.getInstance(); while (CC_defaultTimeOut > 0) { ts0 = System.currentTimeMillis(); ts1 = ts0 + CC_defaultTimeOut; try { sleep(CC_defaultTimeOut); } catch (InterruptedException ex) { // Logger.getLogger(ConnectionManager.class.getName()).log(Level.SEVERE, null, ex); } if (doCheck != true) { continue; // Do not check connection } // Ping remote host - this thread can hang here String s = "Check:" + n; // System.err.println("ConnectionChecker sent ping: " + s + " ts=" + ts1); // DEBUG connectionStatus = CONNECTION_CHECK; connectionCheckerState = CHECKER_IN_IPC; String r = null; int ver = 2; if (1 == ver) { // use Sync IPC r = anWindow.checkConnection(s); // Sync IPC call } else { // use Async IPC // IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.NON_DBE); // ipcHandle.append("checkConnection"); // ipcHandle.append(s); // ipcHandle.append(0); // IPCResult ipcResult = ipcHandle.sendRequest(); // r = ipcResult.getString(); // blocking // Temporary use Handshake request - it is really async r = s; // fake reply IPCHandle ipcHandle = IPCHandle.newHandshakeIPCHandle(); IPCResult ipcResult = ipcHandle.sendRequest(); // no body IPCResult.CC cc = ipcResult.getCC(); // blocking } connectionCheckerState = CHECKER_NOT_IN_IPC; if (!s.equals(r)) { // System.err.println("ConnectionChecker got wrong reply: " + r + " instead of " + s); // // DEBUG res = 1; break; } n++; // Debugging code to simulate lost connection // int debug = 1; // if (debug > 0) { // File f = new File("/tmp/nm_remote_analyzer_check_100"); // DEBUG // if (f.exists()) { // f.delete(); // setTimeOut(100); // } // f = new File("/tmp/nm_remote_analyzer_check_2000"); // DEBUG // if (f.exists()) { // f.delete(); // setTimeOut(2000); // } // f = new File("/tmp/nm_remote_analyzer_stop_checking"); // DEBUG // if (f.exists()) { // f.delete(); // res = 2; // break; // } // f = new File("/tmp/nm_remote_analyzer_hang_checking"); // DEBUG // if (f.exists()) { // //f.delete(); // connectionStatus = CONNECTION_CHECK; // continue; // } // } connectionStatus = CONNECTION_OK; // Close warning dialog if necessary - HACK and NO SYNC final JDialog d = CM_warn_dialog; if (d != null) { // System.err.println("Closing dialog..."); // DEBUG AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { d.dispose(); } }); } } return res; } /** Main method Calls checkConnection() */ public void run() { int res = checkConnection(); if (res != 0) { connectionStatus = CONNECTION_LOST; } connectionCheckerState = CHECKER_FINISHED; // finished } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/CloseExperimentDialog.java����������������������������������0000644�0001750�0001750�00000002301�14517772113�022315� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.remote; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.util.gui.AnDialog2; import java.awt.Frame; public class CloseExperimentDialog extends AnDialog2 { public CloseExperimentDialog(Frame owner) { super(owner, owner, AnLocale.getString("Connect to Remote Host")); CloseExperimentPanel panel = new CloseExperimentPanel(); setCustomPanel(panel); getOKButton().setText(AnLocale.getString("Close")); getOKButton().setToolTipText(AnLocale.getString("Close experiment(s) before continuing")); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/ConnectionPanel.form����������������������������������������0000644�0001750�0001750�00000030350�14517772113�021175� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="hostNameLabel"> <Properties> <Property name="text" type="java.lang.String" value="Host name:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="hostNameComboBox"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="authenticationLabel"> <Properties> <Property name="text" type="java.lang.String" value="Authentication:"/> <Property name="toolTipText" type="java.lang.String" value=""/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="authenticationTextField"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="columns" type="int" value="40"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="-1" gridWidth="-1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="authenticationManageButton"> <Properties> <Property name="text" type="java.lang.String" value="Manage"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="authenticationManageButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="userNameLabel"> <Properties> <Property name="text" type="java.lang.String" value="User name:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="userNameTextField"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="-1" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="passWordLabel"> <Properties> <Property name="text" type="java.lang.String" value="Password:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JPasswordField" name="passwordField"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="-1" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="solstudioPathLabel"> <Properties> <Property name="text" type="java.lang.String" value="Remote SolStudio Path:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JTextField" name="solstudioPathTextField"> <Properties> <Property name="columns" type="int" value="40"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="-1" gridWidth="-1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="connectionStatusLabel"> <Properties> <Property name="text" type="java.lang.String" value="Connection Status:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="connectionStatusValueLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="8" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JScrollPane" name="messageTextScrollPane"> <AuxValues> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="-1" gridWidth="0" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <SubComponents> <Component class="javax.swing.JTextArea" name="messageTextArea"> <Properties> <Property name="editable" type="boolean" value="false"/> <Property name="lineWrap" type="boolean" value="true"/> <Property name="rows" type="int" value="6"/> <Property name="wrapStyleWord" type="boolean" value="true"/> </Properties> </Component> </SubComponents> </Container> <Component class="javax.swing.JProgressBar" name="connectionProgressBar"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="-1" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="20" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/remote/ConnectionDialog.java���������������������������������������0000644�0001750�0001750�00000050131�14517772113�021312� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.remote; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnDialog; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.persistence.UserPref.ConnectionProperties; import org.gprofng.mpmt.picklist.StringPickListElement; import org.gprofng.mpmt.statuspanel.StatusLabelValueHandle; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Frame; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JPasswordField; import javax.swing.JProgressBar; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; public final class ConnectionDialog extends AnDialog implements ItemListener { public static final String help_id = AnVariable.HELP_ConnectRemoteHost; private static String startDir = null; private JComboBox hostNameComboBox; private JTextField file; private JPasswordField passwordField; private JTextField usernameTextField; private JTextField solstudioPathTextField; private JTextField authenticationTextField; private JButton authenticationManageButton; private JLabel statusValueLabel; private JTextArea messageTextArea; private AnWindow m_window; private JProgressBar progressBar = null; public boolean cancelRequest = false; private final StatusLabelValueHandle connectedStatusHandle; private Thread threadConnector = null; private JButton was_ok, was_apply, was_close; private static final String connecting = AnLocale.getString("connecting..."); private static final String connected = AnLocale.getString("connected"); protected static final String notConnected = AnLocale.getString("not connected"); private static final String disconnected = AnLocale.getString("connection failed"); private static final String local_host = "localhost"; private ConnectionPanel connectionPanel; private String defaultSolstudioPath = null; private DocumentListener comboboxDocumentListener = null; private List<Authentication> authentications = null; // Constructor public ConnectionDialog( final AnWindow window, final Frame frame, StatusLabelValueHandle connectedStatusHandle) { super( window, frame, AnLocale.getString("Connect to Remote Host"), false, null, null, help_id, false); this.connectedStatusHandle = connectedStatusHandle; m_window = window; // active_id = window.getWindowID(); initComponents(); updateStatus(); } // Initialize GUI components private void initComponents() { getContentPane().setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); connectionPanel = new ConnectionPanel(this); hostNameComboBox = connectionPanel.getHostNameComboBox(); // hostNameComboBox.addItem(local_host); String os_name = Analyzer.getInstance().os_name; String lh = local_host; if (null != os_name) { if ((!os_name.equals("SunOS")) && (!os_name.equals("Linux"))) { lh = ""; } } hostNameComboBox.addItem(lh); for (StringPickListElement hostElement : UserPref.getInstance().getHostNamePicklist().getStringElements()) { hostNameComboBox.addItem(hostElement.getString()); } hostNameComboBox.setSelectedIndex(0); hostNameComboBox.setEditable(true); ((JTextField) hostNameComboBox.getEditor().getEditorComponent()) .getDocument() .addDocumentListener(comboboxDocumentListener = new ComboBoxDocumentListener()); usernameTextField = connectionPanel.getUserNameTextField(); passwordField = connectionPanel.getPasswordField(); solstudioPathTextField = connectionPanel.getSolstudioPathTextField(); authenticationTextField = connectionPanel.getAuthenticationTextField(); authenticationManageButton = connectionPanel.getAuthenticationManageButton(); statusValueLabel = connectionPanel.getConnectionStatusValueLabel(); statusValueLabel.setForeground(Color.BLACK); messageTextArea = connectionPanel.getMessageTextArea(); String status = notConnected; Analyzer an = Analyzer.getInstance(); if (an.IPC_started) { if (an.remoteConnection == null) { status = an.localHost; } else { status = an.remoteHost; } } statusValueLabel.setText(status); progressBar = connectionPanel.getConnectionProgressBar(); // progressBar.setVisible(false); // pack(); // Change buttons JButton[] buttons = getDefaultButtons(); if (buttons.length > 2) { was_ok = buttons[0]; was_ok.setText(AnLocale.getString("Connect")); // was_ok.setMnemonic(AnLocale.getString('n', // "RemoteConnectDialogConnectButtonMN")); was_ok.setEnabled(true); close_on_enter = false; was_apply = buttons[1]; was_apply.setText(AnLocale.getString("Cancel")); was_apply.setEnabled(false); was_close = buttons[2]; was_close.setEnabled(true); was_close.setMnemonic(AnLocale.getString('l', "RemoteConnectDialogCloseButtonMN")); } setAccessory(connectionPanel); } protected List<Authentication> getAuthenticationsCopy() { List<Authentication> copy = new ArrayList<Authentication>(); for (Authentication auth : authentications) { Authentication authCopy = auth.copy(); copy.add(authCopy); } return copy; } protected void setAuthentications(List<Authentication> authentications) { this.authentications = authentications; passwordField.setEnabled(false); passwordField.setText(""); if (authentications != null) { authenticationTextField.setText(Authentication.toString(authentications)); authenticationManageButton.setEnabled(true); for (Authentication auth : authentications) { if (auth.isOn() && auth.getType() == Authentication.Type.PASSWORD) { passwordField.setEnabled(true); break; } } } else { authenticationTextField.setText(""); authenticationManageButton.setEnabled(false); passwordField.setEnabled(false); } } class ComboBoxDocumentListener implements DocumentListener { // @Override @Override public void changedUpdate(DocumentEvent e) { updateStatus(); } // @Override @Override public void insertUpdate(DocumentEvent e) { updateStatus(); } // @Override @Override public void removeUpdate(DocumentEvent e) { updateStatus(); } } private String getDefaultSolStudioPath() { if (defaultSolstudioPath == null) { String er_print = Analyzer.getInstance().er_print; int index = er_print.lastIndexOf("bin"); if (index > 0) { defaultSolstudioPath = er_print.substring(0, index - 1); } } return defaultSolstudioPath; } private void updateStatus() { AnUtility.checkIfOnAWTThread(true); String hostName = ((JTextField) hostNameComboBox.getEditor().getEditorComponent()).getText(); ConnectionProperties connectionProperties = UserPref.getInstance().getConnectionPropertiesMap().get(hostName); String empty = ""; if (connectionProperties != null) { String path = connectionProperties.getPath(); if (path != null && path.length() > 0) { solstudioPathTextField.setText(path); } else { solstudioPathTextField.setText(empty); } String userName = connectionProperties.getUserName(); if (userName != null && userName.length() > 0) { usernameTextField.setText(userName); } else { usernameTextField.setText(empty); } if (hostName.equals(local_host) || hostName.length() == 0) { setAuthentications(null); } else { setAuthentications(connectionProperties.getAuthentications()); } } else { String lastPath = solstudioPathTextField.getText(); if (hostName.equals(local_host) || hostName.length() == 0) { solstudioPathTextField.setText( getDefaultSolStudioPath()); // Default path (same as local path) setAuthentications(null); } else { if (getDefaultSolStudioPath().equals(lastPath)) { solstudioPathTextField.setText(empty); } setAuthentications(UserPref.getDefaultAuthentications()); } } if (hostName.equals(local_host)) { connectionPanel.setLoginFieldsEnabled(false); } else { connectionPanel.setLoginFieldsEnabled(true); } } // Set visible public void setVisible(final boolean set, final int active_id) { super.setVisible(set); } /* * Listener to switch between file/printer */ @Override public void itemStateChanged(final ItemEvent event) { // final Object source = event.getItemSelectable(); } /* * Connect to remote host */ public String connectToRemoteHost(ConnectionProperties connectionProperties, int timeout) { // if (connectionProperties != null) { // System.out.println("User Name: " + connectionProperties.getUserName()); // System.out.println("Path: " + connectionProperties.getPath()); // String authenticationMethodKeys = // Authentication.toKeyString(connectionProperties.getAuthentications()); // System.out.println("Authentication Keys: " + authenticationMethodKeys); // } try { if (!isVisible()) { setVisible(true); // progressBar.setIndeterminate(true); } String host = hostNameComboBox.getSelectedItem().toString(); if (host != null) { host = host.trim(); } if ((host == null) || (host.length() < 1)) { return (AnLocale.getString("Error: Remote Host Name is not specified.")); } String un = usernameTextField.getText(); if (un != null) { un = un.trim(); } char[] p = passwordField.getPassword(); if (p.length <= 0) { p = null; } String path = solstudioPathTextField.getText(); if (path != null) { path = path.trim(); } if ((path == null) || (path.length() < 1)) { return (AnLocale.getString("Error: Installation Path is not specified.")); } if (!path.endsWith("gp-display-text")) { if (path.endsWith("bin") || path.endsWith("bin/")) { path = path + "/gp-display-text"; } else { path = path + "/bin/gp-display-text"; } } String s = m_window.getAnalyzer().createNewIPC(this, host, un, p, path, connectionProperties); // usernameTextField.setText(""); passwordField.setText(""); if (s != null) { return (s); } } catch (Exception e) { return ("Exception during connectiing."); // Cancel } return null; // Successfully connected } /** * Action performed * * @param event */ @Override public void actionPerformed(final ActionEvent event) { final String str_file; String cmd = event.getActionCommand(); if (cmd.equals(AnLocale.getString("Browse..."))) { if ((str_file = getFile()) != null) { file.setText(str_file); } return; } if (cmd.equals(AnLocale.getString("OK")) || cmd.equals(AnLocale.getString("Connect"))) { String hostName = hostNameComboBox.getSelectedItem().toString(); hostName = hostName.trim().toLowerCase(); final ConnectionProperties connectionProperties; // if (hostName.equals(local_host)) { Map<String, ConnectionProperties> map = UserPref.getInstance().getConnectionPropertiesMap(); connectionProperties = new ConnectionProperties( solstudioPathTextField.getText(), usernameTextField.getText(), authentications); map.put(hostName, connectionProperties); UserPref.getInstance().getHostNamePicklist().addElement(hostName); if (comboboxDocumentListener != null) { ((JTextField) hostNameComboBox.getEditor().getEditorComponent()) .getDocument() .removeDocumentListener(comboboxDocumentListener); } hostNameComboBox.removeAllItems(); hostNameComboBox.addItem(local_host); for (StringPickListElement hostElement : UserPref.getInstance().getHostNamePicklist().getStringElements()) { hostNameComboBox.addItem(hostElement.getString()); } hostNameComboBox.setSelectedItem(hostName); if (comboboxDocumentListener != null) { ((JTextField) hostNameComboBox.getEditor().getEditorComponent()) .getDocument() .addDocumentListener(comboboxDocumentListener); } // } else { // connectionProperties = null; // } connectionStarted(); // Connect to remote host Thread worker = new Thread(/*m_window.getAnalyzer().tgroup, */ "Connection_thread") { final int timeout = 3; @Override public void run() { /* synchronized (AnVariable.worker_lock) */ { threadConnector = this; cancelRequest = false; String res = connectToRemoteHost(connectionProperties, timeout); if (true == cancelRequest) { cancelRequest = false; res += ". Connection canceled"; } connectionFinished(res); } } }; worker.start(); } if (cmd.equals(AnLocale.getString("Apply")) || cmd.equals(AnLocale.getString("Cancel"))) { // TEMPORARY: Cancel if (connectedStatusHandle .get() .equals(connecting) /* statusValueLabel.getText().equals(connecting) */) { cancelRequest = true; // m_window.getAnalyzer().IPC_session = m_window.getAnalyzer().old_IPC_session; // m_window.getAnalyzer().IPC_started = m_window.getAnalyzer().old_IPC_status; // fld_status.setText(disconnected); // progressBar.setIndeterminate(false); if (threadConnector != null) { try { threadConnector.interrupt(); connectionFinished("Connection canceled"); } catch (Exception e) { // thread may already had gone } } } else { setVisible(false); } } } /** * Gets host name * * @return String host name */ // public String getHost() { // String host = fld_host.getSelectedItem().toString(); // return host; // } /** Sets buttons and fields states as they should be during connecting */ private void connectionStarted() { Analyzer.getInstance().connectingToRemoteHost = true; // progressBar.setVisible(true); connectedStatusHandle.update(connecting); progressBar.setIndeterminate(true); was_ok.setEnabled(false); was_apply.setEnabled(true); hostNameComboBox.setEditable(false); passwordField.setEditable(false); usernameTextField.setEditable(false); solstudioPathTextField.setEditable(false); // fld_status.setFont() // bold statusValueLabel.setForeground(Color.black); statusValueLabel.setText(connecting); messageTextArea.setText(AnLocale.getString("Connecting...")); // pack(); } /** Sets buttons and fields states as they should be after connecting */ private void connectionFinished(String result) { // progressBar.setMaximum(10); progressBar.setValue(0); progressBar.setIndeterminate(false); // progressBar.setVisible(false); was_ok.setEnabled(true); was_apply.setEnabled(false); hostNameComboBox.setEditable(true); passwordField.setEditable(true); usernameTextField.setEditable(true); solstudioPathTextField.setEditable(true); if (result == null) { String hostName = hostNameComboBox.getSelectedItem().toString(); // if (hostName.equals(local_host)) { // connectedStatusHandle.update(hostName, StatusLabelValueHandle.Mode.DEFAULT); // statusValueLabel.setForeground(Color.BLACK); // statusValueLabel.setText(local_host); // statusValueLabel.setToolTipText(local_host); // } else { connectedStatusHandle.update( AnUtility.getShortString(hostName, 30), StatusLabelValueHandle.Mode.SET); statusValueLabel.setForeground(new Color(44, 121, 6)); result = connected + " to " + hostName; statusValueLabel.setText(result); statusValueLabel.setToolTipText(result); // } setVisible(false); messageTextArea.setText(""); } else { connectedStatusHandle.update( AnLocale.getString("connection failed"), StatusLabelValueHandle.Mode.ERROR); statusValueLabel.setForeground(Color.red); // statusValueLabel.setText(disconnected); statusValueLabel.setText(result); statusValueLabel.setToolTipText(result); // setVisible(true); // Show error messageTextArea.append("\n"); messageTextArea.append(AnLocale.getString("Connection failed: ")); String s = Analyzer.getInstance().explainConnectionProblem(result, usernameTextField.getText()); messageTextArea.append(AnLocale.getString(s)); // Check if this is CR 22373059: // Is it MacOS? // Do we use java 7? // If "yes" and "yes" show a message and restart remote analyzer client with another java } Analyzer.getInstance().connectingToRemoteHost = false; AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { AnWindow.getInstance().enableSessionActions(false, false); } }); // pack(); } /** * Updates Connection Status * * @param status */ public void updateConnectionStatus(String status) { statusValueLabel.setForeground(Color.black); statusValueLabel.setText(status); messageTextArea.append("\n"); messageTextArea.append(AnLocale.getString(status)); } /** Set file name by interpreting ~ */ private static String getFullPath(final String fname) { String fullpath = null; if (fname != null) { if (fname.startsWith("~/")) { fullpath = fname.replaceFirst("~/", Analyzer.home_dir + "/"); } else if (fname.startsWith("~")) { fullpath = fname.replaceFirst("~", "/home/"); } else { fullpath = fname; } } return fullpath; } /** Get file name from the file chooser */ private String getFile() { final JFileChooser filechooser; final File prn_file; final String path; if (startDir == null) { startDir = Analyzer.getInstance().getWorkingDirectory(); } filechooser = new JFileChooser(startDir); filechooser.setFileHidingEnabled(false); filechooser.setDialogTitle(AnLocale.getString("SolStudio Location")); filechooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); if ((filechooser.showDialog(dialog, AnLocale.getString("Set")) == JFileChooser.APPROVE_OPTION) && ((prn_file = filechooser.getSelectedFile()) != null)) { path = prn_file.getAbsolutePath(); } else { path = null; } startDir = filechooser.getCurrentDirectory().getAbsolutePath(); return path; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/IExtTreeModel.java�������������������������������������������������0000644�0001750�0001750�00000001666�14517772113�017263� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import javax.swing.tree.TreeModel; /** * @author nd159473 */ public interface IExtTreeModel extends TreeModel { public IExtTreeModel getTreeModel(IDispToModel disp); public void setRoot(Object root); public Object createNewRootFrom(Object from); } ��������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/DualSourceView.java������������������������������������������������0000644�0001750�0001750�00000023476�14517772113�017515� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import static org.gprofng.mpmt.event.AnChangeEvent.Type.SETTING_CHANGED; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.util.gui.AnSplitPaneInternal; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dimension; import java.util.ArrayList; import java.util.List; import javax.swing.BoxLayout; import javax.swing.JPanel; import javax.swing.JSplitPane; public final class DualSourceView extends AnDisplay implements ExportSupport, AnChangeListener { private FuncListDisp upperSourcePanel; private FuncListDisp lowerSourcePanel; private JSplitPane splitPane; private int focusedPart; DualSourceView() { super(AnWindow.getInstance(), AnDisplay.DSP_DualSource, AnVariable.HELP_TabsRaceDualSrc); focusedPart = 0; setAccessibility(AnLocale.getString("Dual Sources")); AnEventManager.getInstance().addListener(this); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("DualSourceView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; clear(); clearHistory(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.FORMAT || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override protected boolean supportsFindText() { return true; } // Find @Override public int find(final String str, final boolean next, boolean caseSensitive) { int value = -1; if (focusedPart == 1) { value = upperSourcePanel.find(str, next, caseSensitive); } else if (focusedPart == 2) { value = lowerSourcePanel.find(str, next, caseSensitive); } return value; } public void focusInHalf(int ahalf) { focusedPart = ahalf; } protected void initComponents() { setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); upperSourcePanel = new SourceDisp( window, AnDisplay.DSP_Source, 1, null, AnDisplay.DSP_DualSource); // AnVariable.HELP_TabsSource); lowerSourcePanel = new SourceDisp( window, AnDisplay.DSP_Source, 2, null, AnDisplay.DSP_DualSource); // AnVariable.HELP_TabsSource); lowerSourcePanel.table.setWrapMetricNames(false); // make the both parts to be 0ed Dimension minDim = new Dimension(0, 0); upperSourcePanel.setMinimumSize(minDim); lowerSourcePanel.setMinimumSize(minDim); splitPane = new AnSplitPaneInternal(JSplitPane.VERTICAL_SPLIT, upperSourcePanel, lowerSourcePanel); // the both parts are equals splitPane.setResizeWeight(0.5); // put the split bar in the middle splitPane.setDividerLocation(0.5); add(splitPane); } @Override public void doCompute() { long sel_obj; final long sel_func = 0; AnUtility.checkIfOnAWTThread(false); // Not selected if (!selected) { return; } if (focusedPart == 0) { splitPane.setDividerLocation(0.5); focusedPart = 1; } boolean selObjWasChanged = false; boolean wasPreviousSel = window.getSelectedObject().wasASelDone(); int savedSelType = window.getSelectedObject().getSelType(); int savedSelSubType = window.getSelectedObject().getSelSubType(); long savedSelInd = window.getSelectedObject().getSelIndex(); if (wasRaceAccessUpdated(2)) { if ((getSelPC(2) != 0) && (sel_obj = window.getSelectedObject().getObject(getSelPC(2), sel_func)) != 0L) { lowerSourcePanel.setSelected(true); window.getSelectedObject().setSelObj(sel_obj, DSP_Races /*type*/, subtype); selObjWasChanged = true; lowerSourcePanel.doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) } } if (wasRaceAccessUpdated(1)) { if ((getSelPC(1) != 0) && (sel_obj = window.getSelectedObject().getObject(getSelPC(1), sel_func)) != 0L) { upperSourcePanel.setSelected(true); window.getSelectedObject().setSelObj(sel_obj, DSP_Races /*type*/, subtype); selObjWasChanged = true; upperSourcePanel.doCompute(); // inside doCompute, on worker thread and synchronized // (AnVariable.mainFlowLock) } } if (wasPreviousSel && selObjWasChanged) { window.getSelectedObject().setSelObj(savedSelInd, savedSelType, savedSelSubType); } computed = true; } private boolean wasRaceAccessUpdated_1 = false; private boolean wasRaceAccessUpdated_2 = false; private long pc_1; private long pc_2; public boolean wasRaceAccessUpdated(int aHalf) { boolean retValue = false; if (aHalf == 1) { retValue = wasRaceAccessUpdated_1; wasRaceAccessUpdated_1 = false; } else if (aHalf == 2) { retValue = wasRaceAccessUpdated_2; wasRaceAccessUpdated_2 = false; } return retValue; } public void setWasRaceAccessUpdated(int id, boolean value) { if (id == 1) { wasRaceAccessUpdated_1 = value; } else { wasRaceAccessUpdated_2 = value; } } public void setSelPC(int id, long value) { if (id == 1) { pc_1 = value; } else { pc_2 = value; } } public long getSelPC(int id) { if (id == 1) { return pc_1; } else { return pc_2; } } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { String upperText = upperSourcePanel.exportAsText(limit, format, delimiter); String lowerText = lowerSourcePanel.exportAsText(limit, format, delimiter); return upperText + lowerText; } @Override public java.util.List<ExportFormat> getSupportedExportFormats() { java.util.List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.TEXT); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return false; } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } private static JPanel toolbarPanel = null; // Fixup: pass it to SourceDisp instead of being static!!!! public static JPanel getToolbarPanelInternal() { if (toolbarPanel == null) { toolbarPanel = new JPanel(); toolbarPanel.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); toolbarPanel.setLayout(new BorderLayout()); } return toolbarPanel; } @Override public JPanel getToolbarPanel() { return getToolbarPanelInternal(); } // Update view specific tool bar public void updateToolBar() { if (focusedPart == 1 && upperSourcePanel != null) { upperSourcePanel.updateToolBar(); } else if (focusedPart == 2 && lowerSourcePanel != null) { lowerSourcePanel.updateToolBar(); } } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/����������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�015701� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/TurnerLabelPanel.java�������������������������������������0000644�0001750�0001750�00000006076�14517772113�021656� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.mpmt.util.gui.AnUtility; public class TurnerLabelPanel extends javax.swing.JPanel { /** Creates new form TurnerLabellPanel */ public TurnerLabelPanel(String label1Text, String label2Text) { initComponents(); setOpaque(false); label1.setFont(Overview.defaultBoldFont); label2.setFont(Overview.defaultPlainFont); label1.setText(label1Text); AnUtility.setAccessibleContext(label1.getAccessibleContext(), label1.getText()); AnUtility.setAccessibleContext(label2.getAccessibleContext(), " "); AnUtility.setAccessibleContext(hyphenLabel.getAccessibleContext(), " "); if (label2Text != null) { label2.setText(label2Text); } else { hyphenLabel.setVisible(false); } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; label1 = new javax.swing.JLabel(); hyphenLabel = new javax.swing.JLabel(); label2 = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; add(label1, gridBagConstraints); hyphenLabel.setText(":"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 6); add(hyphenLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.weightx = 1.0; add(label2, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel hyphenLabel; private javax.swing.JLabel label1; private javax.swing.JLabel label2; // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/Overview.java���������������������������������������������0000644�0001750�0001750�00000002336�14517772113�020260� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import java.awt.Color; import java.awt.Font; import javax.swing.JLabel; public class Overview { protected static final Color STATUS_BACKGROUND = Color.WHITE; // new Color(223,238,215); public static final Color METRICS_BACKGROUND = Color.WHITE; // new Color(241,237,186); protected static final Color VIEWS_BACKGROUND = Color.WHITE; // new Color(225,230,237); public static final Font defaultBoldFont = new JLabel().getFont().deriveFont(Font.BOLD); public static final Font defaultPlainFont = defaultBoldFont.deriveFont(Font.PLAIN); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/CheckBoxBarPanel.form�������������������������������������0000644�0001750�0001750�00000003742�14517772113�021571� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Form> ������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/BarPanel.form���������������������������������������������0000644�0001750�0001750�00000003742�14517772113�020162� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Form> ������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/OverviewPanel.form����������������������������������������0000644�0001750�0001750�00000017175�14517772113�021271� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,-4,0,0,2,-78"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Container class="javax.swing.JPanel" name="innerPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="statusLabel"> <Properties> <Property name="text" type="java.lang.String" value="Experiment(s)"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="12" insetsBottom="0" insetsRight="12" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="statusPanel"> <Properties> <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> <Color blue="ff" green="ff" red="ff" type="rgb"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="12" insetsBottom="0" insetsRight="12" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Container> <Component class="javax.swing.JLabel" name="metricsLabel"> <Properties> <Property name="text" type="java.lang.String" value="Metrics"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="12" insetsBottom="0" insetsRight="12" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="metricsPanel"> <Properties> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"> <LineBorder/> </Border> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="12" insetsBottom="0" insetsRight="12" anchor="23" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Container> <Component class="javax.swing.JLabel" name="viewsLabel"> <Properties> <Property name="text" type="java.lang.String" value="Shown Metrics"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="4" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="12" insetsLeft="12" insetsBottom="0" insetsRight="12" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="viewsPanel"> <Properties> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="org.netbeans.modules.form.compat2.border.LineBorderInfo"> <LineBorder/> </Border> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="5" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="12" insetsBottom="0" insetsRight="12" anchor="23" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Container> </SubComponents> </Container> </SubComponents> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/OverviewPanel.java����������������������������������������0000644�0001750�0001750�00000076066�14517772113�021253� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.analyzer.AnLog; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.ipc.IPCContext; import org.gprofng.mpmt.ipc.IPCHandle; import org.gprofng.mpmt.ipc.IPCResult; import org.gprofng.mpmt.metrics.IPCMetricsAPI; import org.gprofng.mpmt.metrics.MetricAttr; import org.gprofng.mpmt.metrics.MetricNode; import org.gprofng.mpmt.metrics.MetricValue; import org.gprofng.mpmt.metrics.MetricsGUI; import org.gprofng.mpmt.metrics.SelectableMetricNode; import org.gprofng.mpmt.metrics.ValueMetricNode; import org.gprofng.mpmt.settings.MetricAttributes; import org.gprofng.mpmt.settings.MetricState; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnSplitPane; import org.gprofng.mpmt.util.gui.AnSplitPaneFixedRightSize; import org.gprofng.mpmt.util.gui.AnUtility; import org.gprofng.mpmt.util.gui.ToolTipPopup; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.util.ArrayList; import java.util.List; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextPane; import javax.swing.ScrollPaneConstants; import javax.swing.border.LineBorder; import javax.swing.border.MatteBorder; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class OverviewPanel extends javax.swing.JPanel { private static OverviewPanel instance = null; protected static final Color borderColor = AnEnvironment.SPLIT_PANE_BORDER_COLOR; private final AnWindow window; private OverviewView overviewDisp; private OuterPanel statusOuterPanel = null; private TurnerPanel statusTurnerPanel = null; private JLabel statusTopLabel = null; private JTextPane statusBottomTextPane = null; private JScrollPane statusBottomScrollPane = null; private ProgressBarPanel metricsProgressBarPanel; private OuterPanel metricsOuterPanel = null; private JPanel metricsOuterPanel2 = null; // private ProgressBarPanel viewsProgressBarPanel; // private JPanel viewsTurnerPanel = null; // private OuterPanel viewsOuterPanel = null; // private MetricNode metricsRootNode = null; private ToolTipPopup previewToolTipPopup = null; private boolean previewToolTipPopupNew = true; private JPanel outerScrollPanePanel; private AnSplitPane splitPane; private JPanel previewPanel; /** Creates new form WelcomePanel */ public OverviewPanel(final AnWindow window, OverviewView overviewDisp) { instance = this; this.window = window; this.overviewDisp = overviewDisp; initComponents(); statusLabel.setText(AnLocale.getString("Experiment(s)")); statusLabel.setDisplayedMnemonic(AnLocale.getString('E', "MN_Overview_Experiments")); AnUtility.setAccessibleContext(statusLabel.getAccessibleContext(), statusLabel.getText()); metricsLabel.setText(AnLocale.getString("Metrics")); // metricsLabel.setDisplayedMnemonic(AnLocale.getString('s', "MN_Overview_Metrics")); AnUtility.setAccessibleContext(metricsLabel.getAccessibleContext(), metricsLabel.getText()); viewsLabel.setText(AnLocale.getString("Shown Metrics")); AnUtility.setAccessibleContext(viewsLabel.getAccessibleContext(), viewsLabel.getText()); statusLabel.setFont(statusLabel.getFont().deriveFont(Font.BOLD)); metricsLabel.setFont(metricsLabel.getFont().deriveFont(Font.BOLD)); innerPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); metricsPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); viewsPanel.setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); setBackground(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); // Status statusTopLabel = new JLabel(); AnUtility.setAccessibleContext( statusTopLabel.getAccessibleContext(), AnLocale.getString("Status")); statusTopLabel.setOpaque(false); statusBottomTextPane = new JTextPane(); statusBottomTextPane.setBackground(Color.WHITE); statusBottomTextPane.setEditable(false); statusBottomScrollPane = new AnJScrollPane(); statusBottomScrollPane.setHorizontalScrollBarPolicy( ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); statusBottomScrollPane.setVerticalScrollBarPolicy( ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED); statusBottomScrollPane.setPreferredSize(new Dimension(100, 80)); statusBottomScrollPane.setViewportView(statusBottomTextPane); statusBottomScrollPane.setBorder(null); statusTurnerPanel = new TurnerPanel( statusTopLabel, statusBottomScrollPane, 4, true, false, Overview.STATUS_BACKGROUND); statusLabel.setLabelFor(statusTurnerPanel.getTurnerButton()); statusOuterPanel = new OuterPanel(); statusOuterPanel.add(statusTurnerPanel, BorderLayout.CENTER); statusPanel.add(statusOuterPanel); statusPanel.setBorder(new LineBorder(borderColor)); statusTurnerPanel.addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { Dimension dim = statusPanel.getPreferredSize(); // System.out.println("statusPanel: " + dim); statusPanel.setMinimumSize(dim); innerPanel.validate(); innerPanel.repaint(); } }); // Metrics metricsOuterPanel = new OuterPanel(); metricsProgressBarPanel = new ProgressBarPanel(); metricsOuterPanel.add(metricsProgressBarPanel, BorderLayout.WEST); metricsPanel.add(metricsOuterPanel, BorderLayout.CENTER); metricsPanel.setBorder(new LineBorder(borderColor)); // Views // viewsOuterPanel = new OuterPanel(); // viewsProgressBarPanel = new ProgressBarPanel(); // viewsOuterPanel.add(viewsProgressBarPanel, BorderLayout.WEST); // viewsPanel.add(viewsOuterPanel, BorderLayout.CENTER); // viewsPanel.setBorder(new LineBorder(borderColor)); // // FIXUP: make Views tables invisible for now viewsLabel.setVisible(false); viewsPanel.setVisible(false); } @Override public void requestFocus() { statusTurnerPanel .getTurnerButton() .requestFocus(); // To change body of generated methods, choose Tools | Templates. } private void constructMetricsPanel() { CheckBoxBarPanel.resetCheckBoxBarPanelList(); if (metricsOuterPanel2 != null) { metricsOuterPanel.remove(metricsOuterPanel2); } metricsOuterPanel2 = new JPanel(); metricsOuterPanel2.setBackground(Color.WHITE); metricsOuterPanel2.setLayout(new BorderLayout()); JPanel metricsOuterPanel2a = new JPanel(); metricsOuterPanel2a.setBackground(Color.WHITE); metricsOuterPanel2a.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); int gridy = 0; String infoTxt = AnLocale.getString( "Select the metrics to display in the data views, then click a data view in the" + " navigation panel on the left."); JLabel infoLabel = new JLabel(infoTxt); AnUtility.setAccessibleContext(infoLabel.getAccessibleContext(), infoLabel.getText()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = gridy++; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(0, 4, 0, 4); metricsOuterPanel2a.add(infoLabel, gridBagConstraints); MetricsGUI metricsGUI = new MetricsGUI( window.getSettings().getMetricsSetting().getMetricStates().getMetricsRootNode(), window); if (MetricsGUI.SHOW_ATTRIBUTES_IN_OVERVIEW) { JPanel buttonPanel = metricsGUI.createButtonPanel(); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridy = gridy++; gridBagConstraints.insets = new Insets(12, 4, 0, 4); gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; metricsOuterPanel2a.add(buttonPanel, gridBagConstraints); } JPanel metricsBarPanel = metricsGUI.createAvailableMetricsPanel(); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.insets = new Insets(12, 4, 0, 4); gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.gridy = gridy++; metricsOuterPanel2a.add(metricsBarPanel, gridBagConstraints); JScrollPane availableMetrcisScrollPane = new AnJScrollPane(); availableMetrcisScrollPane.getVerticalScrollBar().setUnitIncrement(16); availableMetrcisScrollPane.getHorizontalScrollBar().setUnitIncrement(16); availableMetrcisScrollPane.setBorder(null); availableMetrcisScrollPane.setViewportView(metricsOuterPanel2a); outerScrollPanePanel = new JPanel(); outerScrollPanePanel.setBackground(Color.WHITE); outerScrollPanePanel.setLayout(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(0, 0, 4, 0); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; outerScrollPanePanel.add(availableMetrcisScrollPane, gridBagConstraints); previewPanel = constructPreviewPanel(); previewPanel.setBorder(new MatteBorder(1, 0, 0, 0, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); int fontSize = previewPanel.getFont().getSize(); int previewPanelSize = 60 + 4 * fontSize; splitPane = new AnSplitPaneFixedRightSize( AnSplitPane.VERTICAL_SPLIT, outerScrollPanePanel, previewPanel, previewPanelSize, previewPanelSize); splitPane.setDividerSize(1); splitPane.setOneTouchExpandable(false); metricsOuterPanel2.add(splitPane, BorderLayout.CENTER); // metricsOuterPanel2.add(previewPanel, BorderLayout.SOUTH); metricsOuterPanel.add(metricsOuterPanel2, BorderLayout.CENTER); } private JPanel constructPreviewPanel() { // overviewDisp.getMiniFuncListDisp().computeOnWorkerThread(); JPanel miniFuncListPanel = new JPanel(); miniFuncListPanel.setOpaque(false); miniFuncListPanel.setBorder(new MatteBorder(1, 1, 1, 0, AnEnvironment.SPLIT_PANE_BORDER_COLOR)); miniFuncListPanel.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.anchor = GridBagConstraints.NORTHWEST; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; miniFuncListPanel.add(overviewDisp.getMiniFuncListDisp(), gridBagConstraints); JPanel previewPanel = new JPanel(); previewPanel.setBackground(Color.WHITE); previewPanel.setLayout(new GridBagLayout()); JLabel titleLabel = new JLabel(AnLocale.getString("Metrics Preview")); AnUtility.setAccessibleContext(titleLabel.getAccessibleContext(), titleLabel.getText()); titleLabel.setToolTipText(AnLocale.getString("Preview of Functions and other views")); titleLabel.setFont(titleLabel.getFont().deriveFont(Font.BOLD)); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.anchor = GridBagConstraints.WEST; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(4, 4, 0, 4); previewPanel.add(titleLabel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.insets = new Insets(0, 4, 0, 4); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; previewPanel.add(miniFuncListPanel, gridBagConstraints); JPanel ttPanel = new JPanel(new GridBagLayout()); gridBagConstraints = new GridBagConstraints(); ttPanel.setOpaque(false); JLabel ttLabel1 = new JLabel(AnLocale.getString("Metrics Preview")); AnUtility.setAccessibleContext(ttLabel1.getAccessibleContext(), ttLabel1.getText()); // ttLabel1.setForeground(AnEnvironment.TOOLTIP_POPUP_FOREGROUND_COLOR); ttLabel1.setForeground(Color.BLACK); ttLabel1.setFont(ttLabel1.getFont().deriveFont(Font.BOLD)); gridBagConstraints.gridx = 0; ttPanel.add(ttLabel1, gridBagConstraints); JLabel ttLabel2 = new JLabel(AnLocale.getString(" changed")); AnUtility.setAccessibleContext(ttLabel2.getAccessibleContext(), ttLabel2.getText()); ttLabel2.setForeground(AnEnvironment.TOOLTIP_POPUP_FOREGROUND_COLOR); gridBagConstraints.gridx = 1; ttPanel.add(ttLabel2, gridBagConstraints); previewToolTipPopup = new ToolTipPopup(miniFuncListPanel, ttPanel, ToolTipPopup.Location.NORTH, true); previewToolTipPopupNew = true; return previewPanel; } public void previewChanged() { if (previewToolTipPopupNew) { previewToolTipPopupNew = false; } else if (previewToolTipPopup != null) { previewToolTipPopup.show(0, 3000); } } /* * Called from presentation with updates to attributes */ protected void updateMetricTree(List<MetricState> metricStateList) { for (MetricState metricSetting : metricStateList) { if (metricSetting.getAnMetric().isNameMetric()) { continue; } String metricName = metricSetting.getAnMetric().getComd(); boolean selected = metricSetting.getSelection().isSelected(); MetricAttributes metricAttributes = metricSetting.getSelection().getAttributes(); if (window.getSettings().getMetricsSetting().getMetricStates().getMetricsRootNode() == null) { AnLog.log("Error: updateMetricTree: " + " metricsRootNode == null"); return; } List<MetricNode> nodes = window .getSettings() .getMetricsSetting() .getMetricStates() .getMetricsRootNode() .findByName(metricName); if (nodes.isEmpty()) { AnLog.log("Error: updateMetricTree: " + metricName + " not found under metricsRootNode"); return; } for (MetricNode node : nodes) { if (node != null && node instanceof SelectableMetricNode) { // Update data SelectableMetricNode selectableMetricNode = (SelectableMetricNode) node; boolean isHidden = !selected; selectableMetricNode .getExclusive() .setSelected( new MetricAttr( isHidden, metricAttributes.isETime(), metricAttributes.isEValue(), metricAttributes.isEPercent())); selectableMetricNode .getInclusive() .setSelected( new MetricAttr( isHidden, metricAttributes.isITime(), metricAttributes.isIValue(), metricAttributes.isIPercent())); if (!selectableMetricNode.hasSelections()) { // should un-select metric in overview // FIXUP } // Update GUI selectableMetricNode.fireChange(); } } } } // private TurnerPanel dummyViewsPanel() { // GridBagConstraintsnew JLabel gridBagConstraints; // // JComponent viewsTopComponent; // JPanel viewsBottomComponent; // // TurnerPanel view1TurnerPanel; // JComponent view1TopComponent; // JComponent view1BottomComponent; // TurnerPanel view2TurnerPanel; // JComponent view2TopComponent; // JComponent view2BottomComponent; // // view1TopComponent = new JLabel("Functions"); // view1TopComponent.setOpaque(false); // view1BottomComponent = new JLabel(); // view1TurnerPanel = new TurnerPanel(view1TopComponent, view1BottomComponent, false, true, // Overview.VIEWS_BACKGROUND); // // // view2TopComponent = new JLabel("Lines"); // view2TopComponent.setOpaque(false); // view2BottomComponent = new JLabel(); // view2TurnerPanel = new TurnerPanel(view2TopComponent, view2BottomComponent, false, true, // Overview.VIEWS_BACKGROUND); // // // viewsTopComponent = new TopButtonPanel("Selected Views", "All Views...", new // ActionListener() { //// @Override // @Override // public void actionPerformed(ActionEvent e) { // window.getSettings().showDialog(7); // } // }); // viewsTopComponent.setOpaque(false); // viewsBottomComponent = new JPanel(); // viewsBottomComponent.setOpaque(false); // viewsBottomComponent.setLayout(new GridBagLayout()); // gridBagConstraints = new GridBagConstraints(); // gridBagConstraints.gridx = 0; // gridBagConstraints.gridy = 0; // gridBagConstraints.weightx = 1; // gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; // viewsBottomComponent.add(view1TurnerPanel, gridBagConstraints); // gridBagConstraints.gridx = 0; // gridBagConstraints.gridy = 1; // gridBagConstraints.weightx = 1; // gridBagConstraints.insets = new java.awt.Insets(4, 0, 6, 0); // gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; // viewsBottomComponent.add(view2TurnerPanel, gridBagConstraints); // // TurnerPanel turnerPanel = new TurnerPanel(viewsTopComponent, viewsBottomComponent, true, // true, Overview.VIEWS_BACKGROUND); // return turnerPanel; // } private void initExperimentInfo(String[][] groups) { if (groups == null || groups.length == 0 || groups[0] == null) { return; } StringBuilder buf = new StringBuilder(); int got = 0; outer: for (int i = 0; i < groups.length; i++) { for (int j = 0; j < groups[i].length; j++) { if (groups[i][j] != null) { if (got > 0) { buf.append(", "); } if (got >= 2) { buf.append("..."); break outer; } buf.append(AnUtility.basename(groups[i][j])); got++; } } } String labelText = buf.toString(); statusTopLabel.setText(labelText); statusBottomTextPane.setText(AnLocale.getString("Calculating...")); statusOuterPanel.setMinimumSize( statusOuterPanel.getPreferredSize()); // <=== ugly, but what else to do? } /** * Ready to load new experiments * * @param expList experiments list */ protected void initLoadingExperiments(final String[][] groups, final boolean newExperiment) { // this.groups = groups; AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { // if (newExperiment) { // metricsRootNode = null; // } // Status initExperimentInfo(groups); innerPanel.remove(metricsPanel); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 12); innerPanel.add(metricsPanel, gridBagConstraints); // Metrics if (metricsOuterPanel2 != null) { metricsOuterPanel.remove(metricsOuterPanel2); metricsOuterPanel2 = null; } metricsProgressBarPanel.setVisible(true); // Views // if (viewsTurnerPanel != null) { // viewsOuterPanel.remove(viewsTurnerPanel); // viewsTurnerPanel = null; // } // viewsProgressBarPanel.setVisible(true); } }); } /** Loading of new experiments completed Always called from AWT thread */ private void completedLoadingExperiments() { AnUtility.checkIfOnAWTThread(true); innerPanel.remove(metricsPanel); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 12); innerPanel.add(metricsPanel, gridBagConstraints); constructMetricsPanel(); metricsProgressBarPanel.setVisible(false); // metricsBarPanel.setVisible(true); // constructViews(); // viewsProgressBarPanel.setVisible(false); // viewsTurnerPanel.setVisible(true); } public static OverviewPanel getInstance() { return instance; } /* * Should be called if there are changes to the tree */ protected void refreshMetricTree() { AnUtility.checkIfOnAWTThread(false); // Don't do this on AWT thread createAndUpdateMetricTree(); // IPC final String[] preview = getOverviewText(0); // IPC AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { fillStatusPanel(preview); completedLoadingExperiments(); } }); } private void createAndUpdateMetricTree() { if (window.getSettings().getMetricsSetting().getMetricStates().getMetricsRootNode() != null) { List<ValueMetricNode> nodeList = getAllValueMetricNodes( window.getSettings().getMetricsSetting().getMetricStates().getMetricsRootNode(), new ArrayList<ValueMetricNode>()); IPCMetricsAPI.updateMetricValues(0, nodeList); window .getSettings() .getMetricsSetting() .getMetricStates() .getMetricsRootNode() .postProcessRoot(); } } private List<ValueMetricNode> getAllValueMetricNodes( MetricNode parentNode, List<ValueMetricNode> list) { if (parentNode instanceof ValueMetricNode) { list.add((ValueMetricNode) parentNode); } for (MetricNode childNode : parentNode.getChildren()) { getAllValueMetricNodes(childNode, list); // recursive } return list; } /** Always executed on AWT thread */ private void fillStatusPanel(String[] preview) { AnUtility.checkIfOnAWTThread(true); // dumpExpStatus(preview); if (preview != null) { StringBuilder buf = new StringBuilder(); for (String s : preview) { buf.append(s); buf.append("\n"); } // Use Monospaced font to make the info more readable Font f = statusBottomTextPane.getFont(); Font mf = new Font("Monospaced", Font.PLAIN, f.getSize()); statusBottomTextPane.setFont(mf); statusBottomTextPane.setText(buf.toString()); statusBottomTextPane.setCaretPosition(0); } else { statusBottomTextPane.setText(AnLocale.getString("Cancelled or error...")); } } private void dumpExpStatus(String[] preview) { if (false) { return; } for (int ii = 0; ii < preview.length; ii++) { System.out.printf("%s\n", preview[ii]); // DUMP } } /** * Get experiments preview. Use system progressbar and make it cancellable. * * @param expName * @return */ private static String[] getOverviewText(int dbevindex) { IPCContext ipcContext = new IPCContext( AnLocale.getString("Experiment Preview"), IPCContext.Scope.SESSION, true, true, IPCContext.Request.SINGLE, 1, null); IPCHandle ipcHandle = new IPCHandle(IPCHandle.RequestKind.DBE, ipcContext); ipcHandle.append("getOverviewText"); ipcHandle.append(dbevindex); IPCResult ipcResult = ipcHandle.sendRequest(); if (ipcResult.getCC() == IPCResult.CC.SUCCESS) { // blocking String[] result = (String[]) ipcResult.getObject(); return result; } else if (ipcResult.getCC() == IPCResult.CC.CANCELED) { return null; } return null; } public String dump() { return dump(window.getSettings().getMetricsSetting().getMetricStates().getMetricsRootNode()); } public static String dump(MetricNode metricsRootNode) { StringBuffer buf = new StringBuffer(); buf.append("metricsRootNode dump:\n"); if (metricsRootNode != null) { dumpMetricTree(buf, metricsRootNode); } return buf.toString(); } private static void dumpMetricTree(StringBuffer buf, MetricNode node) { dumpMetricTree(buf, node, 0); } private static void dumpMetricTree(StringBuffer buf, MetricNode node, int level) { buf.append(" ".substring(0, 2 * level)); // DUMP if (node instanceof SelectableMetricNode) { SelectableMetricNode sMetricNode = (SelectableMetricNode) node; if (sMetricNode.isSelected()) { buf.append("[X]"); // DUMP } else { buf.append("[ ]"); // DUMP } } if (node.isHiddenInOverview()) { buf.append("HIDDEN "); // DUMP } buf.append(node.getMetricBasic().getDisplayName() + " - " + node.getMetricType()); // DUMP if (node instanceof ValueMetricNode) { ValueMetricNode valueMetricNode = (ValueMetricNode) node; List<MetricValue> mvals = valueMetricNode.getValues(); if (!mvals.isEmpty()) { MetricValue mval0 = mvals.get(0); buf.append(" " + mval0.getLabel() + " Unit=" + mval0.getUnit() + ":"); for (MetricValue mval : mvals) { String hilite = mval.getHighlight() ? "*" : ""; buf.append(" [" + hilite + mval.formatValue() + "]"); } } } buf.append("\n"); String short_desc = node.getMetricBasic().getShortDescription(); if (short_desc != null) { buf.append(" -'" + short_desc + "'\n"); } // DUMP if (!node.getChildren().isEmpty()) { level++; for (MetricNode child : node.getChildren()) { dumpMetricTree(buf, child, level); } } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; innerPanel = new javax.swing.JPanel(); statusLabel = new javax.swing.JLabel(); statusPanel = new javax.swing.JPanel(); metricsLabel = new javax.swing.JLabel(); metricsPanel = new javax.swing.JPanel(); viewsLabel = new javax.swing.JLabel(); viewsPanel = new javax.swing.JPanel(); setLayout(new java.awt.GridBagLayout()); innerPanel.setLayout(new java.awt.GridBagLayout()); statusLabel.setText("Experiment(s)"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 12); innerPanel.add(statusLabel, gridBagConstraints); statusPanel.setBackground(new java.awt.Color(255, 255, 255)); statusPanel.setLayout(new java.awt.BorderLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 12); innerPanel.add(statusPanel, gridBagConstraints); metricsLabel.setText("Metrics"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 12); innerPanel.add(metricsLabel, gridBagConstraints); metricsPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); metricsPanel.setLayout(new java.awt.BorderLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 12); innerPanel.add(metricsPanel, gridBagConstraints); viewsLabel.setText("Shown Metrics"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 12, 0, 12); innerPanel.add(viewsLabel, gridBagConstraints); viewsPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); viewsPanel.setLayout(new java.awt.BorderLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.insets = new java.awt.Insets(0, 12, 0, 12); innerPanel.add(viewsPanel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(innerPanel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel innerPanel; private javax.swing.JLabel metricsLabel; private javax.swing.JPanel metricsPanel; private javax.swing.JLabel statusLabel; private javax.swing.JPanel statusPanel; private javax.swing.JLabel viewsLabel; private javax.swing.JPanel viewsPanel; // End of variables declaration//GEN-END:variables } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/TurnerPanel.java������������������������������������������0000644�0001750�0001750�00000015311�14517772113�020706� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.mpmt.AnIconButton; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import javax.swing.Box.Filler; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class TurnerPanel extends javax.swing.JPanel { private boolean expanded = true; private Filler filler; private static final int fillerWith = 14; private List<ChangeListener> changeListeners = new ArrayList<ChangeListener>(); private JButton turnerButton; public TurnerPanel( JComponent topComponent, JComponent bottomComponent, int turnerButtonInset, boolean align, boolean expanded, Color background) { initComponents(); turnerButton = new AnIconButton(AnUtility.hollowArrowRightIcon); turnerButton.setBorder(null); turnerButton.setBorderPainted(false); // turnerButton.addActionListener(new java.awt.event.ActionListener() { // @Override // public void actionPerformed(java.awt.event.ActionEvent evt) { // TurnerPanel.this.expanded = !TurnerPanel.this.expanded; // updateState(); // } // }); turnerButton.addMouseListener( new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { TurnerPanel.this.expanded = !TurnerPanel.this.expanded; updateState(); } }); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; gridBagConstraints.insets = new java.awt.Insets(0, turnerButtonInset, 0, 1); add(turnerButton, gridBagConstraints); topComponent.setFont(topComponent.getFont().deriveFont(Font.BOLD)); setBackground(background); turnerButton.setBackground(background); turnerButton.setOpaque(false); topPanel.setOpaque(false); topPanel.add(topComponent); bottomPanel.setOpaque(false); if (bottomComponent != null) { bottomPanel.add(bottomComponent); Dimension dim = new Dimension(align ? fillerWith : 3, 0); filler = new javax.swing.Box.Filler(dim, dim, dim); bottomPanel.add(filler, BorderLayout.WEST); } this.expanded = expanded; updateState(); turnerButton.addKeyListener( new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { // System.out.println("turnerButton: " + e); if (e.getKeyCode() == KeyEvent.VK_RIGHT) { TurnerPanel.this.expanded = true; updateState(); } else if (e.getKeyCode() == KeyEvent.VK_LEFT) { TurnerPanel.this.expanded = false; updateState(); } } }); } public void setBottomPanelComponent(JComponent bottomComponent) { bottomPanel.add(bottomComponent); Dimension dim = new Dimension(18, 0); filler = new javax.swing.Box.Filler(dim, dim, dim); bottomPanel.add(filler, BorderLayout.WEST); } public JButton getTurnerButton() { return turnerButton; } private void updateState() { if (expanded) { turnerButton.setToolTipText(AnLocale.getString("Collapse")); turnerButton.setIcon(AnUtility.hollowArrowDownIcon); } else { turnerButton.setToolTipText(AnLocale.getString("Expand")); turnerButton.setIcon(AnUtility.hollowArrowRightIcon); } bottomPanel.setVisible(expanded); fireChange(); } public boolean isExpanded() { return expanded; } public void addChangeListener(ChangeListener changeListener) { changeListeners.add(changeListener); } public void removeChangeListener(ChangeListener changeListener) { changeListeners.remove(changeListener); } private void fireChange() { ChangeEvent changeEvent = new ChangeEvent(this); for (ChangeListener changeListener : changeListeners) { changeListener.stateChanged(changeEvent); } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; topPanel = new javax.swing.JPanel(); bottomPanel = new javax.swing.JPanel(); setLayout(new java.awt.GridBagLayout()); topPanel.setLayout(new java.awt.BorderLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0); add(topPanel, gridBagConstraints); bottomPanel.setLayout(new java.awt.BorderLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; add(bottomPanel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel bottomPanel; private javax.swing.JPanel topPanel; // End of variables declaration//GEN-END:variables } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/GradientPanel.form����������������������������������������0000644�0001750�0001750�00000003307�14517772113�021210� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Form> �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/ProgressBarPanel.form�������������������������������������0000644�0001750�0001750�00000005706�14517772113�021711� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JProgressBar" name="progressBar"> <Properties> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[32767, 10]"/> </Property> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[10, 10]"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="8" insetsBottom="0" insetsRight="8" anchor="23" weightX="0.0" weightY="1.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ����������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/ProgressBarPanel.java�������������������������������������0000644�0001750�0001750�00000004452�14517772113�021664� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; public class ProgressBarPanel extends javax.swing.JPanel { public ProgressBarPanel() { initComponents(); progressBar.setIndeterminate(true); progressBar.setStringPainted(true); progressBar.setFont( progressBar.getFont().deriveFont((float) progressBar.getFont().getSize() - 2)); progressBar.setString(AnLocale.getString("Calculating...")); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; progressBar = new javax.swing.JProgressBar(); setLayout(new java.awt.GridBagLayout()); progressBar.setMaximumSize(new java.awt.Dimension(32767, 10)); progressBar.setMinimumSize(new java.awt.Dimension(10, 10)); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weighty = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 8, 0, 8); add(progressBar, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JProgressBar progressBar; // End of variables declaration//GEN-END:variables } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/TopButtonPanel.form���������������������������������������0000644�0001750�0001750�00000005052�14517772113�021410� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JButton" name="button"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="8" anchor="12" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/OuterPanel.form�������������������������������������������0000644�0001750�0001750�00000003741�14517772113�020553� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Form> �������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/CheckBoxBarPanel.java�������������������������������������0000644�0001750�0001750�00000030153�14517772113�021543� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.metrics.MetricNode; import org.gprofng.mpmt.metrics.MetricsGUI; import org.gprofng.mpmt.metrics.SelectableMetricNode; import org.gprofng.mpmt.settings.MetricNameSelected; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.List; import javax.swing.Box; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; public class CheckBoxBarPanel extends javax.swing.JPanel { private static final int BAR_PANEL_HEIGHT = 16; private final JCheckBox checkBox; private final MetricNode metricNode; private Insets insets = null; private String toolTipText; private static int checkboxFixedPosition = -1; private static List<CheckBoxBarPanel> checkBoxBarPanelList; private static Object selectionsLock = new Object(); private static Thread selectionsThread; private boolean hasFocus; public CheckBoxBarPanel( final MetricNode metricNode, boolean isSelected, boolean hot, String text, String toolTipText, Bar bar, int maxLength, List<Color> keyColorList, int treeLevel, int nodeLevel) { if (metricNode != null) { // System.out.println(metricNode.getMetricBasic().getName() + ": " + isSelected); checkBoxBarPanelList.add(this); } this.metricNode = metricNode; this.toolTipText = toolTipText; initComponents(); setOpaque(false); setLayout(new GridBagLayout()); checkBox = new BarCheckBox(hot); checkBox.setSelected(isSelected); checkBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // metricNodeClicked(false); // AnWindow.getInstance().getSettings().getMetricsSetting().set(this, // metricNode.getMetricBasic().getName(), isSelected()); // // AnWindow.getInstance().getSettings().getMetricsSetting().set(AnWindow.getInstance().getOverviewView(), metricNode.getMetricBasic().getName(), isSelected()); // System.out.println("----------------------------------"); ((SelectableMetricNode) metricNode).setSelected(checkBox.isSelected(), false); processSelections(); // List<MetricNameSelected> metricNameSelected = new // ArrayList<MetricNameSelected>(); // for (CheckBoxBarPanel cbbp : checkBoxBarPanelList) { //// System.out.println(cbbp.metricNode.getMetricBasic().getName() + // " " + cbbp.checkBox.isSelected()); // metricNameSelected.add(new // MetricNameSelected(cbbp.metricNode.getMetricBasic().getName(), // cbbp.checkBox.isSelected())); // } // // AnWindow.getInstance().getSettings().getMetricsSetting().setList(AnWindow.getInstance().getOverviewView(), metricNameSelected); } }); JLabel label = new JLabel(text); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setFont(Overview.defaultPlainFont); label.setOpaque(false); setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); int x = 0; gridBagConstraints.gridy = 0; if (keyColorList != null) { Component colorKeyComponent = new BarColorKey(keyColorList); gridBagConstraints.gridx = x++; gridBagConstraints.insets = new Insets(0, 0, 0, 4); add(colorKeyComponent, gridBagConstraints); } else { maxLength += BarColorKey.barWidth + 4; // make up for not painting color key } gridBagConstraints.gridx = x++; gridBagConstraints.insets = new Insets(1, 0, 0, 0); add(label, gridBagConstraints); int labelLength = getCheckboxFixedPosition(); if (treeLevel >= 1) { labelLength -= 14; labelLength -= treeLevel * 20; } if (nodeLevel >= 3) { labelLength -= (nodeLevel - 2) * 14; } if (bar != null) { labelLength -= Bar.barWidth; } if (keyColorList != null) { labelLength -= (BarColorKey.barWidth + 4); } text = text + " "; label.setText(text); while (label.getPreferredSize().width < labelLength - 20) { text += " ."; label.setText(text); } int w = label.getPreferredSize().width; int hwMetricOffset = 0; if (metricNode != null && metricNode.getMetricBasic() != null) { if (metricNode.getMetricType() == MetricNode.MetricType.PLAIN_ROOT || metricNode.getMetricType() == MetricNode.MetricType.PLAIN_CHILD) { hwMetricOffset = 4; } } Dimension dim = new Dimension(labelLength - w - hwMetricOffset, BAR_PANEL_HEIGHT); Box.Filler filler = new Box.Filler(dim, dim, dim); gridBagConstraints.gridx = x++; add(filler, gridBagConstraints); setToolTip(); if (bar != null && bar.getValue() >= 0) { gridBagConstraints.gridx = x++; add(bar, gridBagConstraints); } gridBagConstraints.gridx = x++; int offSet = 10; if (bar != null && bar.noCompareBars() > 0) { offSet = Bar.BAR_MAX_PERCENT * Bar.barWidth / 100 - bar.getPanelWidth() + 10; } gridBagConstraints.insets = new Insets(0, offSet, 0, 0); JLabel hotMarker = new JLabel(); AnUtility.setAccessibleContext(hotMarker.getAccessibleContext(), AnLocale.getString("Hot")); if (hot) { hotMarker.setIcon(AnUtility.hot_icon); } else { hotMarker.setPreferredSize( new Dimension(AnUtility.hot_icon.getIconWidth(), AnUtility.hot_icon.getIconHeight())); } add(hotMarker, gridBagConstraints); gridBagConstraints.gridx = x++; gridBagConstraints.insets = new Insets(0, 2, 0, 5); add(checkBox, gridBagConstraints); if (metricNode != null && metricNode instanceof SelectableMetricNode) { ((SelectableMetricNode) metricNode) .addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { Object o = e.getSource(); if (o instanceof SelectableMetricNode) { boolean selected = ((SelectableMetricNode) o).isSelected(); getCheckBox().setSelected(selected); } } }); } addKeyListener( new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE) { checkBox.doClick(); } } }); } private static void processSelections() { synchronized (selectionsLock) { if (selectionsThread != null && selectionsThread.isAlive()) { selectionsThread.interrupt(); } selectionsThread = AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { boolean interrupted = false; try { Thread.sleep(1000); } catch (InterruptedException ie) { interrupted = true; } ; if (!interrupted) { List<MetricNameSelected> metricNameSelected = new ArrayList<MetricNameSelected>(); for (CheckBoxBarPanel cbbp : checkBoxBarPanelList) { metricNameSelected.add( new MetricNameSelected( cbbp.metricNode.getMetricBasic().getName(), cbbp.checkBox.isSelected())); } AnWindow.getInstance() .getSettings() .getMetricsSetting() .setList(AnWindow.getInstance().getOverviewView(), metricNameSelected); } } }, "processSelections"); } } protected static void resetCheckBoxBarPanelList() { checkBoxBarPanelList = new ArrayList<CheckBoxBarPanel>(); } /** * @return the checkboxFixedPosition */ public static int getCheckboxFixedPosition() { if (checkboxFixedPosition < 0) { int fontSize = new JLabel().getFont().getSize(); if (fontSize <= 12) { checkboxFixedPosition = MetricsGUI.getInstance().getMetricDisplayNameBaseWidth(); } else { checkboxFixedPosition = MetricsGUI.getInstance().getMetricDisplayNameBaseWidth() + (fontSize - 12) * 25; } } // System.out.println(checkboxFixedPosition); return checkboxFixedPosition; } private void setToolTip() { if (toolTipText != null) { if (metricNode.getMetricBasic().getShortDescription() != null) { StringBuilder buf = new StringBuilder(); buf.append("<html>"); buf.append(toolTipText); buf.append("<br>"); buf.append(metricNode.getMetricBasic().getShortDescription()); buf.append("<html>"); setToolTipText(buf.toString()); } else { setToolTipText(toolTipText); } } } @Override public Insets getInsets() { if (insets != null) { return insets; } else { return super.getInsets(); } } public void setInsets(Insets insets) { this.insets = insets; } /** * @return the checkBox */ public JCheckBox getCheckBox() { return checkBox; } public boolean isSelected() { return checkBox.isSelected(); } public void setSelected(boolean selected) { checkBox.setSelected(selected); setToolTip(); } /** * @param hasFocus the hasFocus to set */ public void setHasFocus(boolean hasFocus) { this.hasFocus = hasFocus; } /** * @return the hasFocus */ public boolean isHasFocus() { return hasFocus; } class BarCheckBox extends JCheckBox { public BarCheckBox(boolean hot) { setOpaque(false); setMargin(new Insets(0, 0, 0, 0)); setBorder(null); setPreferredSize(new Dimension(17, 17)); AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Metric selector")); } @Override public Insets getInsets() { return new Insets(0, 2, 0, 0); } @Override public void paint(Graphics g) { super.paint(g); if (isFocusOwner() || hasFocus) { // For a11y... g.setColor(new Color(122, 138, 153)); g.drawLine(16, 2, 16, 14); } } } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.GridBagLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/AnBarTree.java��������������������������������������������0000644�0001750�0001750�00000032407�14517772113�020257� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.metrics.MetricNode; import org.gprofng.mpmt.metrics.MetricsGUI; import org.gprofng.mpmt.metrics.SelectableMetricNode; import org.gprofng.mpmt.overview.Bar.ValueColor; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Component; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.EventObject; import java.util.List; import java.util.Vector; import javax.swing.AbstractCellEditor; import javax.swing.JTree; import javax.swing.JTree.DynamicUtilTreeNode; import javax.swing.ToolTipManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeCellEditor; import javax.swing.tree.TreeCellRenderer; import javax.swing.tree.TreeNode; public class AnBarTree extends JTree { private static int CHECKBOX_WIDTH = 20; // FIXUP: can this be calculated? private CheckBoxBarPanel[] checkBoxBarPanels = new CheckBoxBarPanel[20]; public AnBarTree(Vector<Object> rootVector) { super(rootVector); AnUtility.setAccessibleContext(getAccessibleContext(), AnLocale.getString("Metrics Tree")); TreeCellRenderer anCellRenderer = new CellRenderer(); setCellRenderer(anCellRenderer); CellEditor anCellEditor = new CellEditor(this); setCellEditor(anCellEditor); setEditable(true); setOpaque(false); // setRootVisible(true); ToolTipManager.sharedInstance().registerComponent(this); addKeyListener( new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_SPACE) { for (CheckBoxBarPanel cbp : checkBoxBarPanels) { if (cbp != null) { if (cbp.isHasFocus()) { cbp.getCheckBox().doClick(); break; } } } } } }); } public void setTreeNodeStateSelected( SelectableMetricNode selectableMetricNode, boolean selected) { CellEditor cellEditor = (CellEditor) getCellEditor(); cellEditor.setTreeNodeStateSelected(selectableMetricNode, selected); } public static class BarNode<E> extends Vector<E> { public MetricNode metricNode; private boolean selected; public String toolTipText; public Bar bar; public int maxLength; public int level; private CheckBoxBarPanel checkBoxBarPanel = null; public BarNode( MetricNode metricNode, boolean isSelected, String toolTipText, Bar bar, List<E> elements, int maxLength, int level) { this.metricNode = metricNode; this.selected = isSelected; this.toolTipText = toolTipText; this.bar = bar; if (elements != null) { for (int i = 0, n = elements.size(); i < n; i++) { add(elements.get(i)); } } this.maxLength = maxLength; this.level = level; if (metricNode instanceof SelectableMetricNode) { ((SelectableMetricNode) metricNode) .addChangeListener( new ChangeListener() { // @Override @Override public void stateChanged(ChangeEvent e) { Object o = e.getSource(); if (o instanceof SelectableMetricNode) { selected = ((SelectableMetricNode) o).hasSelections(); if (checkBoxBarPanel != null /*&& checkBoxBarPanel.isSelected() != selected*/) { checkBoxBarPanel.setSelected(selected); MetricsGUI.getInstance().refreshMetricsPanel(); } } } }); } } public BarNode( MetricNode metricNode, boolean isSelected, String toolTipText, Bar bar, int maxLength, int level) { this(metricNode, isSelected, toolTipText, bar, null, maxLength, level); } /** * @return the bar */ public Bar getBar() { return bar; } public String getName() { return metricNode.getMetricBasic().getName(); } public String getDisplayName() { return metricNode.getMetricBasic().getDisplayName(); } /** * @return the selected */ public boolean isSelected() { return selected; } /** * @param selected the selected to set */ public void setSelected(boolean selected) { this.selected = selected; } /** * @return the barCheckBox */ public CheckBoxBarPanel getCheckBoxBarPanel() { return checkBoxBarPanel; } /** * @param barCheckBox the barCheckBox to set */ public void setCheckBoxBarPanel(CheckBoxBarPanel checkBoxBarPanel) { this.checkBoxBarPanel = checkBoxBarPanel; } } class CellRenderer implements TreeCellRenderer { DefaultTreeCellRenderer defaultRenderer = new DefaultTreeCellRenderer(); Color backgroundSelectionColor = defaultRenderer.getBackgroundSelectionColor(); Color backgroundNonSelectionColor = defaultRenderer.getBackgroundNonSelectionColor(); public CellRenderer() {} @Override public Component getTreeCellRendererComponent( JTree tree, Object value, boolean selected, boolean expanded, boolean leaf, int row, boolean hasFocus) { CheckBoxBarPanel checkBoxBarPanel = null; boolean isSelected = false; String text = null; String toolTipText = null; Bar bar = null; int maxLength = 100; boolean hot = false; if ((value != null) && (value instanceof DynamicUtilTreeNode)) { Object userObject = ((DynamicUtilTreeNode) value).getUserObject(); if (userObject instanceof BarNode) { BarNode node = (BarNode) userObject; isSelected = node.isSelected(); text = node.getDisplayName(); toolTipText = node.toolTipText; bar = node.bar; maxLength = node.maxLength; int level = node.level; maxLength = maxLength - (level - 1) * CHECKBOX_WIDTH; hot = node.metricNode.isHot(); checkBoxBarPanel = node.getCheckBoxBarPanel(); if (checkBoxBarPanel == null) { List<Color> keyColorList = null; if (bar != null && bar.getValueColor() != null && bar.getValueColor().size() <= 3) { keyColorList = new ArrayList<Color>(); for (ValueColor valueColor : bar.getValueColor()) { keyColorList.add(valueColor.getColor()); } } checkBoxBarPanel = new CheckBoxBarPanel( node.metricNode, isSelected, hot, text, toolTipText, bar, maxLength, keyColorList, level, -1); // <=== checkBoxBarPanel.setInsets(new Insets(2, 0, 2, 0)); node.setCheckBoxBarPanel(checkBoxBarPanel); } else { checkBoxBarPanel.setSelected(isSelected); } } } if (checkBoxBarPanel == null) { checkBoxBarPanel = new CheckBoxBarPanel( null, isSelected, hot, text, toolTipText, bar, maxLength, null, 0, -1); } for (CheckBoxBarPanel cbp : checkBoxBarPanels) { if (cbp != null) { cbp.setHasFocus(false); } } if (hasFocus) { checkBoxBarPanel.setHasFocus(true); } if (row >= 0 && row < checkBoxBarPanels.length) { checkBoxBarPanels[row] = checkBoxBarPanel; } return checkBoxBarPanel; } } class CellEditor extends AbstractCellEditor implements TreeCellEditor { ChangeEvent changeEvent = null; JTree tree; ActionListener actionListener = null; public CellEditor(JTree tree) { this.tree = tree; } @Override public Object getCellEditorValue() { return null; // FIXUP: ?????? } @Override public boolean isCellEditable(EventObject event) { return true; } @Override public Component getTreeCellEditorComponent( final JTree tree, final Object value, boolean selected, boolean expanded, boolean leaf, int row) { Component editor = tree.getCellRenderer() .getTreeCellRendererComponent(tree, value, true, expanded, leaf, row, true); final CheckBoxBarPanel checkBoxBarPanel = (CheckBoxBarPanel) editor; ActionListener[] al = checkBoxBarPanel.getCheckBox().getActionListeners(); if (al.length == 1) { // FIXUP: Hack: we only want to add this listener ONCE and we get here many // times!!!!!!!!! checkBoxBarPanel .getCheckBox() .addActionListener( new ActionListener() { // @Override @Override public void actionPerformed(ActionEvent e) { checkBoxClicked(tree, checkBoxBarPanel, value); } }); } return editor; } private List<TreeNode> findNodesInTreeByName(String name) { List<TreeNode> list = new ArrayList<TreeNode>(); Object root = getModel().getRoot(); TreeNode rootNode = (TreeNode) root; findNodesInTreeByName(rootNode, list, name); return list; } private void findNodesInTreeByName(TreeNode treeNode, List<TreeNode> list, String name) { if (treeNode instanceof DynamicUtilTreeNode) { DynamicUtilTreeNode dynamicTreeNode = (DynamicUtilTreeNode) treeNode; Object uo = dynamicTreeNode.getUserObject(); if (uo instanceof BarNode) { BarNode bn = (BarNode) uo; String bnName = bn.metricNode.getMetricBasic().getName(); if (bnName.equals(name)) { list.add(treeNode); } } } for (int i = 0; i < treeNode.getChildCount(); i++) { findNodesInTreeByName(treeNode.getChildAt(i), list, name); } } /** Checkbox clicked.... */ private void checkBoxClicked(JTree tree, CheckBoxBarPanel barPanel, final Object value) { if ((value != null) && (value instanceof DynamicUtilTreeNode)) { DynamicUtilTreeNode dynamicUtilTreeNode = (DynamicUtilTreeNode) value; Object userObject = dynamicUtilTreeNode.getUserObject(); if (userObject instanceof BarNode) { BarNode barNode = (BarNode) userObject; MetricNode metricNode = barNode.metricNode; if (metricNode instanceof SelectableMetricNode) { SelectableMetricNode selectableMetricNode = (SelectableMetricNode) metricNode; // selectableMetricNode.setSelected(barPanel.isSelected(), // false); barNode.setSelected(barPanel.isSelected()); // ??? // synchronize selection with outher node representing same metric (same metric name) List<TreeNode> nodeList = findNodesInTreeByName(selectableMetricNode.getMetricBasic().getName()); for (int i = 0; i < nodeList.size(); i++) { TreeNode treeNode = nodeList.get(i); if (treeNode instanceof DynamicUtilTreeNode) { DynamicUtilTreeNode child = (DynamicUtilTreeNode) treeNode; Object uo = child.getUserObject(); if (uo instanceof BarNode) { BarNode bn = (BarNode) uo; if (bn != barNode) { bn.setSelected(barPanel.isSelected()); } } } } } } } } /** Set internal state in barnode to selected */ protected void setTreeNodeStateSelected( SelectableMetricNode selectableMetricNode, boolean selected) { List<TreeNode> nodeList = findNodesInTreeByName(selectableMetricNode.getMetricBasic().getName()); for (int i = 0; i < nodeList.size(); i++) { TreeNode treeNode = nodeList.get(i); if (treeNode instanceof DynamicUtilTreeNode) { DynamicUtilTreeNode child = (DynamicUtilTreeNode) treeNode; Object uo = child.getUserObject(); if (uo instanceof BarNode) { BarNode bn = (BarNode) uo; bn.setSelected(selected); } } } } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/Bar.java��������������������������������������������������0000644�0001750�0001750�00000020471�14517772113�017156� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.metrics.CompareBarData; import org.gprofng.mpmt.metrics.MetricValue; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.FontMetrics; import java.awt.Graphics; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.swing.JPanel; public class Bar extends JPanel { protected static final int BAR_MAX_PERCENT = 150; public static final Color[] BAR_COMPARE_COLORS = new Color[] {AnEnvironment.BAR_COMPARE_COLOR1, AnEnvironment.BAR_COMPARE_COLOR2}; protected static final int barWidth = 200; public static final int barHeight = 13; private int panelWidth = barWidth; private int panelHeight = barHeight; private Font smallFont; private boolean showBorder = true; private boolean showFillColor = true; private boolean paintNumber = true; private CompareBarData[] compareValues = null; private List<ValueColor> valueColor; private int value; public Bar(Color color, int value, CompareBarData[] compareValues) { List<ValueColor> vc = new ArrayList<ValueColor>(); vc.add(new ValueColor(value, color)); init(vc, value, compareValues); // paintNumber = false; // showBorder = false; } public Bar(ValueColor[] valueColor, int value, CompareBarData[] compareValues) { init(new ArrayList<ValueColor>(Arrays.asList(valueColor)), value, compareValues); } public Bar(List<ValueColor> valueColor, int value, CompareBarData[] compareValues) { init(valueColor, value, compareValues); } private void init(List<ValueColor> valueColor, int value, CompareBarData[] compareValues) { if (compareValues == null) { panelHeight = barHeight; panelWidth = barWidth; } else { panelHeight = barHeight + compareValues.length * barHeight - 2; panelWidth = calculateBarWidth(compareValues); } setPreferredSize(new Dimension(panelWidth, panelHeight)); // smallFont = getFont().deriveFont((float) getFont().getSize() - 2); smallFont = getFont().deriveFont((float) 10); // Always use size 10 font to paint numbers (for now!) this.valueColor = valueColor; this.value = value; this.compareValues = compareValues; setOpaque(false); } private int calculateBarWidth(CompareBarData[] compareValues) { int maxX = barWidth; if (compareValues != null) { for (int compareBarNo = 0; compareBarNo < compareValues.length; compareBarNo++) { // ValueColor compareValueColor = // compareValues[compareBarNo].getValueColors().get(0); // << FIXUP int value = compareValues[compareBarNo].getPercentOfTotal(); if (value == MetricValue.PERCENT_NAN || value >= BAR_MAX_PERCENT) { value = BAR_MAX_PERCENT; } int vbarValue = (int) (barWidth * value) / 100; int fillValue = vbarValue; if (fillValue <= 1) { fillValue = 1; } maxX = ((1 + fillValue) > maxX ? (1 + fillValue) : maxX); } } return maxX; } public int noCompareBars() { if (compareValues == null) { return 0; } else { return compareValues.length; } } // @Override @Override public void paint(Graphics g) { paint(g, 0, 0); } public void paint(Graphics g, int xOffset, int yOffset) { super.paint(g); int maxX = barWidth; int x = xOffset; int y = yOffset; if (showFillColor) { g.setColor(AnEnvironment.BAR_BACKGROUND_COLOR); g.fillRect(x, y, barWidth - 1, barHeight - 1); } if (showBorder) { g.setColor(AnEnvironment.BAR_BORDER_COLOR); g.drawRect(x, y, barWidth - 1, barHeight - 1); } x = x + 1; for (ValueColor vc : getValueColor()) { int vbarValue; // is value of main bar 0? if (noCompareBars() > 0 && compareValues[0].getPercentOfTotal() == MetricValue.PERCENT_NAN) { vbarValue = 0; // YXXX For now, show zero value for main bar (Thomas: TBD) } else { vbarValue = (int) (barWidth * vc.getValue()) / 100; } g.setColor(vc.getColor()); int fillValue = vbarValue; if (fillValue <= 1) { fillValue = 1; } g.fillRect(x, y + 1, fillValue, barHeight - 2); x += vbarValue; } for (int compareBarNo = 0; compareBarNo < noCompareBars(); compareBarNo++) { int combinedValue = 0; int compareX = xOffset + 1; for (ValueColor compareValueColor : compareValues[compareBarNo].getValueColors()) { g.setColor(compareValueColor.color); int value; boolean maxReached = false; if (compareValues[compareBarNo].getPercentOfTotal() == MetricValue.PERCENT_NAN) { maxReached = true; value = BAR_MAX_PERCENT - combinedValue; } else { value = compareValueColor.value * compareValues[compareBarNo].getPercentOfTotal() / 100; combinedValue += value; if (value == MetricValue.PERCENT_NAN || combinedValue >= BAR_MAX_PERCENT) { maxReached = true; value = BAR_MAX_PERCENT - (combinedValue - value); } } int vbarValue = (int) (barWidth * value) / 100; int borderOffset = 1; if (showBorder) { g.setColor(AnEnvironment.BAR_BORDER_COLOR); g.drawRect(xOffset, y + barHeight + compareBarNo * (barHeight - 2), 0, barHeight - 3); borderOffset = 0; } g.setColor(compareValueColor.color); int fillValue = vbarValue; if (fillValue <= 1) { fillValue = 1; } g.fillRect( compareX, y + barHeight + compareBarNo * (barHeight - 1) - borderOffset, fillValue, barHeight - 2); if (maxReached) { int nearEnd = BAR_MAX_PERCENT * barWidth / 100; nearEnd -= 15; g.setColor(Color.WHITE); for (int i = 0; i < 5; i++) { compareX = xOffset + 1 + nearEnd; int yy = y + barHeight + compareBarNo * (barHeight - 2) - 1; g.drawLine(compareX + i, yy, compareX - 20 + i, yy + yy + barHeight - 2); } } maxX = ((compareX + fillValue) > maxX ? (compareX + fillValue) : maxX); compareX += vbarValue; } } // panelWidth = maxX; // Dimension dim = getPreferredSize(); // dim = new Dimension(panelWidth, dim.height); // setPreferredSize(dim); if (paintNumber) { g.setFont(smallFont); String valueString = "" + getValue() + "%"; int valueWidthInPixels = pixelWidth(g, valueString); g.setClip(0, 0, x, y + barHeight); g.setColor(Color.WHITE); g.drawString(valueString, xOffset + barWidth - valueWidthInPixels - 2, y + 10); g.setClip(x, 0, x + barWidth, y + barHeight); g.setColor(Color.BLACK); g.drawString(valueString, xOffset + barWidth - valueWidthInPixels - 2, y + 10); } } private int pixelWidth(Graphics g, String s) { FontMetrics fontMetrics = g.getFontMetrics(); return fontMetrics.stringWidth(s); } /** * @return the value */ public int getValue() { return value; } public int getPanelWidth() { return panelWidth; } /** * @return the valueColor */ public List<ValueColor> getValueColor() { return valueColor; } public static class ValueColor { private int value; private Color color; public ValueColor(int value, Color color) { this.value = value; this.color = color; } /** * @return the value */ public int getValue() { return value; } /** * @return the color */ public Color getColor() { return color; } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/OuterPanel.java�������������������������������������������0000644�0001750�0001750�00000003217�14517772113�020527� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.analyzer.AnEnvironment; import java.awt.BorderLayout; /** * @author tpreisle */ public class OuterPanel extends javax.swing.JPanel { /** Creates new form OuterPanel */ public OuterPanel() { initComponents(); add(new GradientPanel(true), BorderLayout.NORTH); add(new GradientPanel(false), BorderLayout.SOUTH); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.BorderLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/BarPanel.java���������������������������������������������0000644�0001750�0001750�00000010245�14517772113�020134� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import static org.gprofng.mpmt.overview.CheckBoxBarPanel.getCheckboxFixedPosition; import org.gprofng.mpmt.metrics.MetricNode; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.Box; import javax.swing.JLabel; public class BarPanel extends javax.swing.JPanel { private final MetricNode metricNode; private Insets insets = null; private String toolTipText; public BarPanel( final MetricNode metricNode, boolean isSelected, boolean hot, String text, String toolTipText, Bar bar, int maxLength, Color keyColor, int treeLevel, int nodeLevel) { // System.out.println("BarPanel " + text); this.metricNode = metricNode; this.toolTipText = toolTipText; initComponents(); setOpaque(false); setOpaque(false); setLayout(new GridBagLayout()); JLabel label = new JLabel(text); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setFont(Overview.defaultPlainFont); label.setOpaque(false); setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); int x = 0; gridBagConstraints.gridy = 0; if (keyColor != null) { Component colorKeyComponent = new BarColorKey(keyColor); gridBagConstraints.gridx = x++; gridBagConstraints.insets = new Insets(0, 0, 0, 4); add(colorKeyComponent, gridBagConstraints); } else { maxLength += BarColorKey.barWidth + 4; // make up for not painting color key } gridBagConstraints.gridx = x++; gridBagConstraints.insets = new Insets(0, 0, 0, 0); add(label, gridBagConstraints); int labelLength = getCheckboxFixedPosition() + 14; if (treeLevel >= 1) { labelLength -= 14; labelLength -= treeLevel * 20; } if (nodeLevel >= 3) { labelLength -= (nodeLevel - 2) * 14; } if (bar != null) { labelLength -= Bar.barWidth; } if (keyColor != null) { labelLength -= (BarColorKey.barWidth + 4); } int w = label.getPreferredSize().width; Dimension dim = new Dimension(labelLength - w, 20); Box.Filler filler = new Box.Filler(dim, dim, dim); gridBagConstraints.gridx = x++; add(filler, gridBagConstraints); setToolTip(); if (bar != null && bar.getValue() >= 0) { gridBagConstraints.gridx = x++; add(bar, gridBagConstraints); } } private void setToolTip() { if (toolTipText != null) { StringBuilder txt = new StringBuilder(); txt.append(toolTipText); setToolTipText(txt.toString()); } } @Override public Insets getInsets() { if (insets != null) { return insets; } else { return super.getInsets(); } } public void setInsets(Insets insets) { this.insets = insets; } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.GridBagLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/TopButtonPanel.java���������������������������������������0000644�0001750�0001750�00000006360�14517772113�021371� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.event.ActionListener; import javax.swing.JLabel; public class TopButtonPanel extends javax.swing.JPanel { public TopButtonPanel(String labelText, String buttonText, ActionListener actionListener) { initComponents(); setBackground(Color.WHITE); JLabel label = new JLabel(labelText); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); // JTextArea textArea = new JTextArea(); // textArea.setText(labelText); // textArea.setFont(textArea.getFont().deriveFont(Font.PLAIN)); // textArea.setLineWrap(true); // textArea.setWrapStyleWord(true); // textArea.setBorder(null); // textArea.setOpaque(false); // textArea.setMinimumSize(new Dimension(10, 10)); // textArea.setPreferredSize(new Dimension(10, 40)); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.SOUTHWEST; gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new Insets(0, 0, 3, 0); add(label, gridBagConstraints); button.setText(buttonText); button.addActionListener(actionListener); button.setFont(Overview.defaultPlainFont); button.setMargin(new Insets(0, 4, 0, 4)); button.setBackground(new Color(237, 240, 244)); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; button = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST; gridBagConstraints.insets = new java.awt.Insets(0, 0, 0, 8); add(button, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton button; // End of variables declaration//GEN-END:variables } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/TurnerPanel.form������������������������������������������0000644�0001750�0001750�00000006376�14517772113�020743� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Container class="javax.swing.JPanel" name="topPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Container> <Container class="javax.swing.JPanel" name="bottomPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="2" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBorderLayout"/> </Container> </SubComponents> </Form> ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/GradientPanel.java����������������������������������������0000644�0001750�0001750�00000004246�14517772113�021171� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import java.awt.Color; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; /** * @author tpreisle */ public class GradientPanel extends javax.swing.JPanel { private final Color color1 = Color.WHITE; private final Color color2 = new Color(235, 235, 235); private static final int height = 12; private boolean top; public GradientPanel(boolean top) { this.top = top; initComponents(); setPreferredSize(new Dimension(height, height)); } // @Override public void paint(Graphics g) { int width = getWidth(); // int height = getHeight(); Graphics2D g2d = (Graphics2D) g; GradientPaint gp; if (top) { gp = new GradientPaint(0, 0, color2, 0, height, color1); } else { gp = new GradientPaint(0, 0, color1, 0, height, color2); } g2d.setPaint(gp); g2d.fillRect(0, 0, width, height); setOpaque(false); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { setLayout(new java.awt.BorderLayout()); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/TurnerLabelPanel.form�������������������������������������0000644�0001750�0001750�00000007333�14517772113�021675� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="label1"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="hyphenLabel"> <Properties> <Property name="text" type="java.lang.String" value=":"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="6" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="label2"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/overview/BarColorKey.java������������������������������������������0000644�0001750�0001750�00000003760�14517772113�020630� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.analyzer.AnEnvironment; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.util.ArrayList; import java.util.List; import javax.swing.JPanel; public class BarColorKey extends JPanel { protected static final int barWidth = 9; protected static final int barHeight = 14; private List<Color> keyColorList; public BarColorKey(Color keyColor) { List<Color> fillColorList = new ArrayList<Color>(); fillColorList.add(keyColor); this.keyColorList = fillColorList; init(); } public BarColorKey(List<Color> keyColorList) { this.keyColorList = keyColorList; init(); } private void init() { Dimension dim = new Dimension(barWidth, barHeight); setMinimumSize(dim); setMaximumSize(dim); setPreferredSize(dim); setBackground(Color.WHITE); } @Override public void paint(Graphics g) { super.paint(g); if (keyColorList != null) { int x = 0; int y = 1; // Fill int yStep = (barHeight - 2) / keyColorList.size(); for (Color color : keyColorList) { g.setColor(color); g.fillRect(x, y, barWidth - 1, barHeight - 1); y += yStep; } // Border g.setColor(AnEnvironment.BAR_BORDER_COLOR); g.drawRect(0, 0, barWidth - 1, barHeight - 1); } } } ����������������gprofng-gui-1.0/org/gprofng/mpmt/overview/OverviewView.java�����������������������������������������0000644�0001750�0001750�00000024100�14517772113�021104� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.overview; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.MiniFuncListDisp; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dimension; import java.util.ArrayList; import java.util.List; import javax.accessibility.AccessibleContext; import javax.swing.ToolTipManager; public final class OverviewView extends AnDisplay implements ExportSupport, AnChangeListener { private MiniFuncListDisp miniFuncListDisp = null; private String lastSortMetrics = null; private OverviewPanel overviewPanel; private boolean metricsHaveChanged = false; private int defaultToolTipDismissDelay = 0; private static final int ToolTipDismissDelay = 10000; private Thread miniFuncListDispComputeThread; private Object miniFuncListDispComputeThreadLock = new Object(); // Constructor public OverviewView() { super(AnWindow.getInstance(), AnDisplay.DSP_Overview, AnVariable.HELP_Overview); setAccessibility(AnLocale.getString("Overview")); AnEventManager.getInstance().addListener(this); miniFuncListDisp = constructMiniFuncListDisp(); defaultToolTipDismissDelay = ToolTipManager.sharedInstance().getDismissDelay(); } @Override public void requestFocus() { overviewPanel.requestFocus(); // To change body of generated methods, choose Tools | Templates. } public String getShortDescr() { return "Overview short description..."; } public String getLongDescr() { return "<HTML><b>Overview View</b><br>Overview long" + " description......<br>..............................................<br>..............................................</HTML>"; } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("OverviewView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: setComputed(false); clear(); clearHistory(); String[][] groups = (String[][]) e.getSource(); if (groups.length > 0) { overviewPanel.initLoadingExperiments(groups, true); } break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: setComputed(false); if (selected) { computeOnAWorkerThread(); } miniFuncListDisp.setComputed(false); if (selected) { computeMiniFuncListDisp(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.COMPARE_MODE) { setComputed(false); if (selected) { computeOnAWorkerThread(); } miniFuncListDisp.setComputed(false); if (selected) { computeMiniFuncListDisp(); } } if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { if (anSettingChangeEvent.getOriginalSource() != this) { metricsHaveChanged = true; if (selected) { computeOnAWorkerThread(); } } miniFuncListDisp.setComputed(false); if (selected) { computeMiniFuncListDisp(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } private void computeMiniFuncListDisp() { synchronized (miniFuncListDispComputeThreadLock) { if (miniFuncListDispComputeThread != null && miniFuncListDispComputeThread.isAlive()) { miniFuncListDispComputeThread.interrupt(); } miniFuncListDispComputeThread = AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { boolean interrupted = false; try { Thread.sleep(100); } catch (InterruptedException ie) { interrupted = true; } ; if (!interrupted) { miniFuncListDisp.computeOnAWorkerThread(); } } }, "computeMiniFuncListDisp"); } } private MiniFuncListDisp constructMiniFuncListDisp() { MiniFuncListDisp miniFLD = new MiniFuncListDisp(window, AnDisplay.DSP_Functions, AnVariable.HELP_Overview); // Dimension dim = new java.awt.Dimension(100, overviewPanel.getFont().getSize() * 4 + 20); miniFLD.setPreferredSize(dim); AccessibleContext context = miniFLD.getAccessibleContext(); context.setAccessibleName(AnLocale.getString("Functions")); context.setAccessibleDescription(AnLocale.getString("List of functions")); return miniFLD; } public MiniFuncListDisp getMiniFuncListDisp() { return miniFuncListDisp; } private void saveLastSortMetrics() { lastSortMetrics = AnWindow.getInstance().getSettings().getMetricsSetting().getSortColumnMetricDisplayName(0); } private void restoreLastSortMetrics() { if (lastSortMetrics != null) { String sortMetrics = AnWindow.getInstance() .getSettings() .getMetricsSetting() .getSortColumnMetricDisplayName(0); if (sortMetrics != null && !sortMetrics.equals(lastSortMetrics)) { AnWindow.getInstance() .getSettings() .getMetricsSetting() .setSortColumnName(lastSortMetrics, 0); } } } @Override public void setSelected(boolean set) { if (isSelected() == set) { return; } super.setSelected(set); if (set) { saveLastSortMetrics(); ToolTipManager.sharedInstance().setDismissDelay(ToolTipDismissDelay); } else { restoreLastSortMetrics(); ToolTipManager.sharedInstance().setDismissDelay(defaultToolTipDismissDelay); } miniFuncListDisp.setSelected(set); } @Override public void setComputed(boolean set) { super.setComputed(set); miniFuncListDisp.setComputed(set); } // Initialize GUI components @Override protected void initComponents() { setLayout(new BorderLayout()); overviewPanel = new OverviewPanel(window, this); add(overviewPanel, BorderLayout.CENTER); } // Compute & update Statistics display @Override public void doCompute() { AnUtility.checkIfOnAWTThread(false); if (!selected) { return; } if (computed) { if (metricsHaveChanged) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { overviewPanel.updateMetricTree( AnWindow.getInstance() .getSettings() .getMetricsSetting() .getMetricStates() .getMetricStateList()); } }); metricsHaveChanged = false; } } if (!computed) { overviewPanel.initLoadingExperiments(AnWindow.getInstance().getExperimentGroups(), false); overviewPanel.refreshMetricTree(); saveLastSortMetrics(); } computeMiniFuncListDisp(); computed = true; } @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { StringBuilder buf = new StringBuilder(); buf.append(overviewPanel.dump()); buf.append(miniFuncListDisp.exportAsText(0, format, delimiter)); return buf.toString(); } @Override public List<ExportFormat> getSupportedExportFormats() { List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return false; } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/CalledByCallsSourceView.java���������������������������������������0000644�0001750�0001750�00000001760�14517772113�021256� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; public final class CalledByCallsSourceView extends CalledByCallsDisp { public CalledByCallsSourceView() { super( AnWindow.getInstance(), AnDisplay.DSP_Callers, AnVariable.HELP_TabsSource, AnDisplay.DSP_Source); setAccessibility(AnLocale.getString("Called By Calls")); } } ����������������gprofng-gui-1.0/org/gprofng/mpmt/LibraryVisibilityPanel.form����������������������������������������0000644�0001750�0001750�00000063437�14517772113�021273� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="infoLabel"> <Properties> <Property name="text" type="java.lang.String" value="info..."/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="filterPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="14" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="23" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="filterLabel"> <Properties> <Property name="text" type="java.lang.String" value="Filter:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="-1" gridY="-1" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="6" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JPanel" name="radioButtonPanel"> <Properties> <Property name="opaque" type="boolean" value="false"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JRadioButton" name="nativeRadioButton"> <Properties> <Property name="text" type="java.lang.String" value="Native"/> <Property name="opaque" type="boolean" value="false"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="nativeRadioButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JRadioButton" name="javaRadioButton"> <Properties> <Property name="text" type="java.lang.String" value="Java"/> <Property name="opaque" type="boolean" value="false"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="javaRadioButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> <Component class="javax.swing.JLabel" name="includeLabel"> <Properties> <Property name="text" type="java.lang.String" value="Include"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="4" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="includeComboBox"> <Properties> <Property name="editable" type="boolean" value="true"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="4" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="excludeLabel"> <Properties> <Property name="text" type="java.lang.String" value="and exclude"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="8" insetsBottom="4" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JComboBox" name="excludeComboBox"> <Properties> <Property name="editable" type="boolean" value="true"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="3" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="4" insetsBottom="4" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="refreshButton"> <Properties> <Property name="text" type="java.lang.String" value="Refresh"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="refreshButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="4" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="8" insetsBottom="4" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="listLabelPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="8" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="listLabel"> <Properties> <Property name="text" type="java.lang.String" value="List:"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="maxListLabel"> <Properties> <Property name="text" type="java.lang.String" value="jLabel1"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="0" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="outerListPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="3" gridWidth="3" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.Box$Filler" name="filler1"> <Properties> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.Box$Filler" name="filler2"> <Properties> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.Box$Filler" name="filler3"> <Properties> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[60, 0]"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.Box$Filler" name="filler4"> <Properties> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[120, 0]"/> </Property> <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[120, 0]"/> </Property> <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[120, 0]"/> </Property> <Property name="autoscrolls" type="boolean" value="true"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="3" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="functionsLabel"> <Properties> <Property name="text" type="java.lang.String" value="Functions"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="apiLabel"> <Properties> <Property name="text" type="java.lang.String" value="API"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="libraryLabel"> <Properties> <Property name="text" type="java.lang.String" value="Library"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="2" gridY="2" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="nameButton"> <Properties> <Property name="text" type="java.lang.String" value="Name"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="nameButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="3" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="14" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="pathButton"> <Properties> <Property name="text" type="java.lang.String" value="Path"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="pathButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="4" gridY="3" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="21" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Container class="javax.swing.JScrollPane" name="scrollPane"> <Properties> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Border info="null"/> </Property> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="4" gridWidth="5" gridHeight="1" fill="1" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="23" weightX="1.0" weightY="1.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <SubComponents> <Container class="javax.swing.JPanel" name="listPanel"> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> </Container> </SubComponents> </Container> <Container class="javax.swing.JPanel" name="buttonPanel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="5" gridWidth="0" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="maxLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="0" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="12" insetsBottom="0" insetsRight="12" anchor="22" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="defaultsButton"> <Properties> <Property name="text" type="java.lang.String" value="Defaults"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="defaultsButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="4" insetsLeft="12" insetsBottom="4" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JLabel" name="listedLabel"> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="1" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="12" anchor="22" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Container> </SubComponents> </Container> </SubComponents> </Form> ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnMetric.java������������������������������������������������������0000644�0001750�0001750�00000023021�14517772113�016300� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.settings.CompareModeSetting.CompareMode; import java.awt.Color; import java.util.Hashtable; import java.util.List; // See BaseMetric.h and Metric.h for definitions of members public final class AnMetric { // BaseMetric.h: public String expr_spec, aux, legend; private final String comd, user_name, data_type_name, data_type_uname; // private final int id private final int valtype, clock, type, flavors; private final int value_styles; private int sub_type, vis_bits; // Metric.h: private final String name, abbr, unit /*aka abbr_unit*/; // MetricList.h::get_sort_ref_index() private final String short_desc; // one-liner description of metric. May be NULL private boolean sorted; public static final Color defaultBackground = new Color(0xef, 0xef, 0xef); private static final Color[] compareColors = { new Color(0xce, 0xce, 0xce), defaultBackground, Color.WHITE, new Color(0xd0, 0xfc, 0xff), new Color(0xff, 0xfa, 0xd0), new Color(0xea, 0xd0, 0xff), }; private final Color backgroundColor; private boolean hot = false; // Constructor public AnMetric(AnMetric bm) { type = bm.type; sub_type = bm.sub_type; clock = bm.clock; flavors = bm.flavors; value_styles = bm.value_styles; user_name = bm.user_name; legend = bm.legend; expr_spec = bm.expr_spec; aux = bm.aux; name = bm.name; abbr = bm.abbr; comd = bm.comd; unit = bm.unit; vis_bits = bm.vis_bits; valtype = bm.valtype; data_type_name = bm.data_type_name; data_type_uname = bm.data_type_uname; sorted = false; backgroundColor = getMetricBackgroundInternal(expr_spec); short_desc = bm.short_desc; } public AnMetric( int type, int sub_type, int clock, int flavors, int value_styles, String user_name, String expr_spec, String aux, String name, String abbr, String comd, String unit, String legend, int vis_bits, boolean sorted, int valtype, String data_type_name, String data_type_uname, String short_desc) { this.type = type; this.sub_type = sub_type; this.clock = clock; this.flavors = flavors; this.value_styles = value_styles; this.user_name = user_name; this.legend = legend; this.expr_spec = expr_spec; this.aux = aux; this.name = name; this.abbr = abbr; this.comd = comd; this.unit = unit; this.vis_bits = vis_bits; this.sorted = sorted; this.valtype = valtype; this.data_type_name = data_type_name; this.data_type_uname = data_type_uname; this.short_desc = short_desc; backgroundColor = getMetricBackgroundInternal(expr_spec); } // public int get_id() { return id; } public int getType() { return type; } public String getName() { return name; } public String getUserName() { return user_name == null ? name : user_name; } public String getDataTypeName() { return data_type_name; } public String getDataTypeUserName() { return data_type_uname; } public String getShortDesc() { return short_desc; } public String getAbbr() { return abbr; } public String getComd() { return comd; } public String getAux() { return aux; } public String getUnit() { return unit; } public int getSubType() { return sub_type; } public int get_valtype() { return valtype; } public int getClock() { return clock; } public int get_vis_bits() { return vis_bits; } public boolean isSorted() { return sorted; } public boolean isTimeMetric() { return (value_styles & VAL_TIMEVAL) != 0; } public boolean isValMetric() { return (value_styles & VAL_VALUE) != 0; } public boolean isNameMetric() { return (type == METRIC_TYPE_ONAME); } public boolean isStatic() { return (flavors & STATIC) != 0; } public boolean canExclusive() { return (flavors & EXCLUSIVE) != 0; } public boolean canInclusive() { return (flavors & INCLUSIVE) != 0; } public boolean canPercent() { return (value_styles & VAL_PERCENT) != 0; } @Override public String toString() { return getUserName(); } // public void set_id(int _id) { id = _id; } public void setSubType(int t) { sub_type = t; } public void setSorted(boolean set) { sorted = set; } public boolean isHidden() { return (vis_bits & VAL_HIDE_ALL) != 0; } public void set_hidden(boolean hide_all) { vis_bits &= ~(VAL_HIDE_ALL); if (hide_all) { vis_bits |= VAL_HIDE_ALL; } } public boolean isPVisible() { if (isHidden()) { return false; } return (vis_bits & VAL_PERCENT) != 0; } public boolean isVVisible() { if (isHidden()) { return false; } if (is_time_val()) { return (vis_bits & VAL_VALUE) != 0; } else if (isValMetric()) { return (vis_bits & (VAL_VALUE | VAL_TIMEVAL)) != 0; } return false; } public boolean isTVisible() { if (isHidden()) { return false; } if (is_time_val()) { return (vis_bits & VAL_TIMEVAL) != 0; } else if (isTimeMetric()) { return (vis_bits & (VAL_VALUE | VAL_TIMEVAL)) != 0; } return false; } public void set_vis_bits(boolean tvis, boolean vvis, boolean pvis) { int v = 0; if (is_time_val()) { if (tvis) { v |= VAL_TIMEVAL; } if (vvis) { v |= VAL_VALUE; } } else if ((vvis || tvis)) { v |= VAL_VALUE; } if (pvis && canPercent()) { v |= VAL_PERCENT; } vis_bits &= ~(VAL_VALUE | VAL_TIMEVAL | VAL_PERCENT); vis_bits |= v; } public boolean is_time_val() { final int v = VAL_TIMEVAL | VAL_VALUE; return (value_styles & v) == v; } private static Hashtable simulatedGroupIds = new Hashtable(); private Color getMetricBackgroundInternal( String expr_spec) { // YXXX should use group id value from dbe if (expr_spec == null) { return defaultBackground; } Integer simulatedGroupId; if (!simulatedGroupIds.containsKey(expr_spec)) { simulatedGroupId = simulatedGroupIds.size() + 1; simulatedGroupIds.put(expr_spec, simulatedGroupId); } else { simulatedGroupId = (Integer) simulatedGroupIds.get(expr_spec); } return getMetricBackground(simulatedGroupId); } public Color getMetricBackground() { return backgroundColor; } public static Color getMetricBackground(int groupId) { if (groupId < 1) { return defaultBackground; } int ii = (groupId - 1) % compareColors.length; return compareColors[ii]; } private int compareTo(String a, String b) { if (a == null) { return b == null ? 0 : -1; } else { return b == null ? 1 : a.compareTo(b); } } public boolean equals(AnMetric m) { if (m == null) { return false; } return (getType() == m.getType()) && (getSubType() == m.getSubType()) && (compareTo(getUserName(), m.getUserName()) == 0) && (compareTo(expr_spec, m.expr_spec) == 0); } public int indexIn(List<AnMetric> mlist) { for (int i = 0; i < mlist.size(); i++) { if (equals(mlist.get(i))) { return i; } } return -1; } public CompareMode getCompareMode() { if ((expr_spec == null) || expr_spec.equalsIgnoreCase("EXPGRID==1")) { return CompareMode.CMP_DISABLE; } CompareMode mode = AnWindow.getInstance().getSettings().getCompareModeSetting().get(); return mode; } // flavors bits: (should match BaseMetric.h) public static final int STATIC = 1; public static final int EXCLUSIVE = 2; public static final int INCLUSIVE = 4; // ValueTag (should match dbe_structs.h and AnVariable.java) // public final static int VT_SHORT = 1; // unused public static final int VT_INT = 2; public static final int VT_LLONG = 3; // public final static int VT_FLOAT = 4; // unused public static final int VT_DOUBLE = 5; // public final static int VT_HRTIME = 6; // unused public static final int VT_LABEL = 7; public static final int VT_ADDRESS = 8; // unused // public final static int VT_OFFSET = 9; // unused public static final int VT_ULLONG = 10; // vis_bits (should match enums.h) public static final int VAL_NA = 0; public static final int VAL_TIMEVAL = 1; public static final int VAL_VALUE = 2; public static final int VAL_PERCENT = 4; public static final int VAL_DELTA = 8; public static final int VAL_RATIO = 16; public static final int VAL_HIDE_ALL = 64; // metric types (should match BaseMetric.h) //YXXX TBR, yuck public static final int METRIC_TYPE_ONAME = 1; public static final int METRIC_TYPE_USER_CPU_TIME = 9; public static final int METRIC_TYPE_LOCK_WAIT_TIME = 19; // aka "LWT" public boolean isHot() { return hot; } public void setHot(boolean hot) { this.hot = hot; } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/��������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�016172� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/ViewPanel.form������������������������������������������0000644�0001750�0001750�00000005443�14517772113�020661� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <NonVisualComponents> <Component class="javax.swing.ButtonGroup" name="buttonGroup1"> </Component> </NonVisualComponents> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="nameLabel"> <Properties> <Property name="text" type="java.lang.String" value="Functions"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="6" insetsBottom="6" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/NavigationPanel.java������������������������������������0000644�0001750�0001750�00000012457�14517772113�022027� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.navigation; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.compare.CompareNavigationPanel; import org.gprofng.mpmt.filter.FilterNavigationPanel; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.util.gui.AnJScrollPane; import org.gprofng.mpmt.util.gui.AnSplitPane; import org.gprofng.mpmt.util.gui.AnSplitPaneFixedRightSize; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import javax.swing.BorderFactory; import javax.swing.JPanel; import javax.swing.JScrollPane; public class NavigationPanel extends JPanel { private static boolean compareStatusPanelShowing = false; private static int heightOfCompareStatusPanel = 0; private AnWindow anWindow; private AnJScrollPane scrollPane; private ViewsPanel viewsPanel; private TopNavigationPanel topNavigationPanel; private AnSplitPaneFixedRightSize navigationSplitPane; private FilterNavigationPanel filterNavigationPanel; private CompareNavigationPanel compareNavigationPanel; public NavigationPanel(AnWindow anWindow) { this.anWindow = anWindow; setLayout(new GridBagLayout()); setBackground(AnEnvironment.DEFAULT_BACKGROUND_COLOR); JPanel viewsNavigationPanel = new JPanel(); viewsNavigationPanel.setBorder( BorderFactory.createMatteBorder(0, 0, 0, 1, AnEnvironment.NAVIGATION_PANEL_BORDER_COLOR)); viewsNavigationPanel.setLayout(new BorderLayout()); // Top Navigation area topNavigationPanel = new TopNavigationPanel(anWindow); viewsNavigationPanel.add(topNavigationPanel, BorderLayout.NORTH); // View Panels scrollPane = new AnJScrollPane(); viewsPanel = new ViewsPanel(scrollPane); // viewPanels.setViewPanelOrderList(UserPref.getInstance().getViewPanelOrder()); scrollPane.setBorder(null); scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setViewportView(viewsPanel); scrollPane.setMinimumSize(new Dimension(0, 50)); scrollPane.getVerticalScrollBar().setUnitIncrement(16); viewsNavigationPanel.add(scrollPane, BorderLayout.CENTER); filterNavigationPanel = new FilterNavigationPanel(anWindow); compareNavigationPanel = new CompareNavigationPanel(); JPanel filterCompareNavigationPanel = new JPanel(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; filterCompareNavigationPanel.add(filterNavigationPanel, gridBagConstraints); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 1; filterCompareNavigationPanel.add(compareNavigationPanel, gridBagConstraints); navigationSplitPane = new AnSplitPaneFixedRightSize( AnSplitPane.VERTICAL_SPLIT, viewsNavigationPanel, filterCompareNavigationPanel, UserPref.getInstance().getNavigationFilterSplitPane().getSize(), UserPref.getInstance().getNavigationFilterSplitPane().getDefaultSize()); navigationSplitPane.setOneTouchExpandable(false); navigationSplitPane.setDividerSize(2); navigationSplitPane.setBackground(AnEnvironment.NAVIGATION_SPLIT_PANE_DIVIDER_COLOR); // filterPanel.setBackground(Color.red); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(0, 0, 0, 0); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(navigationSplitPane, gridBagConstraints); setMinimumSize(new Dimension(5, 5)); // so the divider can be moved all the way to the left } public void adjustCompareNavigationPanelHeightChanged(int diff) { int now = navigationSplitPane.getDividerLocation(); navigationSplitPane.setDividerLocationInternal(now - diff); } /** * @return the panel holding all the views */ public ViewsPanel getViewsPanel() { return viewsPanel; } public int getNavigationSplitPaneSizeInPixels() { int sizeInPixels = navigationSplitPane.getSizeInPixels(); sizeInPixels -= compareNavigationPanel.getDiffFromInitialHeight(); return sizeInPixels; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/PanelDropTargetListener.java����������������������������0000644�0001750�0001750�00000004427�14517772113�023507� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.navigation; import java.awt.Component; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DropTargetContext; import java.awt.dnd.DropTargetDragEvent; import java.awt.dnd.DropTargetDropEvent; import java.awt.dnd.DropTargetEvent; import java.awt.dnd.DropTargetListener; public class PanelDropTargetListener implements DropTargetListener { private ViewsPanel sidePanel = null; public PanelDropTargetListener(ViewsPanel sidePanel) { this.sidePanel = sidePanel; } // @Override @Override public void dragEnter(DropTargetDragEvent dtde) {} // @Override @Override public void dragOver(DropTargetDragEvent dtde) {} // @Override @Override public void dropActionChanged(DropTargetDragEvent dtde) {} // @Override @Override public void dragExit(DropTargetEvent dte) {} @Override public void drop(DropTargetDropEvent dtde) { DataFlavor dadPanelFlavor = null; Object transferableObj = null; Component targetComponent = null; Transferable transferable = null; try { dadPanelFlavor = ViewPanel.getDADDataFlavor(); transferable = dtde.getTransferable(); DropTargetContext c = dtde.getDropTargetContext(); targetComponent = c.getComponent(); if (transferable.isDataFlavorSupported(dadPanelFlavor)) { transferableObj = dtde.getTransferable().getTransferData(dadPanelFlavor); } } catch (Exception e) { } if (transferableObj == null) { return; } ViewPanel droppedPanel = (ViewPanel) transferableObj; sidePanel.dropPanelTo(droppedPanel, targetComponent); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/ViewsPanel.java�����������������������������������������0000644�0001750�0001750�00000101134�14517772113�021014� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.navigation; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.AnWindow.AnDispTab; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.persistence.UserPref.ViewPanelOrder; import org.gprofng.mpmt.settings.ViewsSetting; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BasicStroke; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.MouseInfo; import java.awt.Point; import java.awt.Rectangle; import java.awt.dnd.DragSource; import java.awt.dnd.DragSourceDragEvent; import java.awt.dnd.DragSourceDropEvent; import java.awt.dnd.DragSourceEvent; import java.awt.dnd.DragSourceListener; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.FocusAdapter; import java.awt.event.FocusEvent; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; import java.util.Stack; import javax.swing.AbstractAction; import javax.swing.JCheckBoxMenuItem; import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.JToolTip; import javax.swing.KeyStroke; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; public class ViewsPanel extends javax.swing.JPanel { private List<ViewPanel> viewPanelList = new ArrayList(); private List<ViewPanel> viewPanelOriginalOrder = new ArrayList(); private int dropLine = -1; private static final int dropLineOffset = 0; private int gridY = 2; private JDialog viewsSelectorDialog = null; private JPopupMenu viewsSelectorpopup = null; private Point cancelPoint = null; // private List<ViewPanelOrder> viewPanelOrderList = null; private ViewPanel defaultViewPanel = null; private JScrollPane scrollPane; private ActionPanel moreViewsPanel; private static Integer maxMenus = null; private int keyboardFocusIndex = 0; private Stack<String> viewStack = new Stack<String>(); private int viewStackPointer = -1; public String dumpAvailableViews() { StringBuilder buf = new StringBuilder(); buf.append("--------------------------available views"); buf.append("\n"); for (ViewPanel viewPanel : viewPanelList) { buf.append((viewPanel.isShown() ? "*" : " ") + viewPanel.getView().getDisplayName()); buf.append("\n"); } return buf.toString(); } public ViewsPanel(JScrollPane scrollPane) { this.scrollPane = scrollPane; initComponents(); moreViewsPanel = new ActionPanel( AnLocale.getString("More..."), AnLocale.getString("Add more views..."), new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Object source = e.getSource(); if (source instanceof MouseEvent) { // Mouse click MouseEvent me = (MouseEvent) e.getSource(); AnWindow.getInstance() .getViewsPanel() .showViewsConfigurationPopup( moreViewsPanel, me.getPoint().x + 5, me.getPoint().y + 5); } else if (source instanceof JComponent) { // Keyboard JComponent component = (JComponent) source; AnWindow.getInstance() .getViewsPanel() .showViewsConfigurationPopup( moreViewsPanel, component.getX() + component.getWidth() - 5, component.getY() - 5); } } }); setBackground( AnEnvironment.NAVIGATION_PANEL_BACKGROUND_COLOR /*AnEnvironment.DEFAULT_PANEL_BACKGROUND*/); setDropTarget(new DropTarget(this, new PanelDropTargetListener(this))); DragSource.getDefaultDragSource() .addDragSourceListener( new DragSourceListener() { // @Override @Override public void dragDropEnd(DragSourceDropEvent dsde) { // System.out.println("DragSource:dragDropEnd: " + // dsde.getDragSourceContext().getComponent()); if (dsde.getDragSourceContext().getComponent() instanceof ViewPanel) { dropLine = -1; repaint(); } } // @Override @Override public void dragExit(DragSourceEvent dse) { // System.out.println("DragSource:dragExit: " + dse); if (dse.getDragSourceContext().getComponent() instanceof ViewPanel) { dropLine = -1; repaint(); } } // @Override @Override public void dragEnter(DragSourceDragEvent dsde) { // System.out.println("DragSource:dragEnter: " + dsde); if (dsde.getDragSourceContext().getComponent() instanceof ViewPanel) { // This is the right kind of drop object int y1 = 0; int y2 = 0; for (int i = 0; i < viewPanelList.size(); i++) { ViewPanel viewPanel = (ViewPanel) viewPanelList.get(i); if (!viewPanel.isShown()) { continue; } y1 = viewPanelList.get(i).getLocationOnScreen().y; y2 = y1 + viewPanelList.get(i).getHeight(); if (dsde.getLocation().y >= y1 && dsde.getLocation().y <= y2) { dropLine = y1 - getYLocationOnScreenOfFirstShownView(); break; } } if (dropLine < 0) { dropLine = y2 - getYLocationOnScreenOfFirstShownView(); } repaint(); } } private int getYLocationOnScreenOfFirstShownView() { int y = 0; for (ViewPanel viewPanel : viewPanelList) { if (viewPanel.isShowing()) { y = viewPanel.getLocationOnScreen().y; break; } } return y; } @Override public void dragOver(DragSourceDragEvent dsde) {} @Override public void dropActionChanged(DragSourceDragEvent dsde) {} }); addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { showViewsConfigurationPopup(ViewsPanel.this, e.getPoint().x + 5, e.getPoint().y + 5); } } }); // A11Y KeyStroke keyStroke = KeyboardShortcuts.contextMenuActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, keyStroke); getActionMap() .put( keyStroke, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { final Point loc1 = MouseInfo.getPointerInfo().getLocation(); final Point loc2 = getLocationOnScreen(); showViewsConfigurationPopup( ViewsPanel.this, loc1.x - loc2.x + 5, loc1.y - loc2.y + 5); } }); getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getInputMap(JComponent.WHEN_FOCUSED) .put(KeyboardShortcuts.helpActionShortcut, KeyboardShortcuts.helpActionShortcut); getActionMap() .put( KeyboardShortcuts.helpActionShortcut, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { ViewPanel viewPanel = getHasKeyboardFocus(); if (viewPanel != null) { // Show help for current keyboard focus String name = viewPanel.getView().getName(); ViewsSetting.View view = AnWindow.getInstance().getSettings().getViewsSetting().findView(name); if (view != null) { view.getAnDispTab().getTComp().showHelp(); return; } } // Show help for current showing AnWindow.getInstance().getViews().getCurrentViewDisplay().showHelp(); } }); addKeyListener( new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { handleKeyEvent(e); } }); addFocusListener( new FocusAdapter() { @Override public void focusGained(FocusEvent e) { keyboardFocusIndex = getSelected(); makeVisible(keyboardFocusIndex); viewPanelList.get(keyboardFocusIndex).setKeyboardFocused(true); viewPanelList.get(keyboardFocusIndex).repaint(); } @Override public void focusLost(FocusEvent e) { resetKeyboardFocus(); } }); } void handleKeyEvent(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_DOWN || e.getKeyCode() == KeyEvent.VK_UP) { if (keyboardFocusIndex >= 0 && keyboardFocusIndex < viewPanelList.size()) { viewPanelList.get(keyboardFocusIndex).setKeyboardFocused(false); viewPanelList.get(keyboardFocusIndex).repaint(); } else { moreViewsPanel.setKeyboardFocused(false); moreViewsPanel.repaint(); } if (e.getKeyCode() == KeyEvent.VK_DOWN) { keyboardFocusIndex = nextKeyboardFocused(keyboardFocusIndex); } else if (e.getKeyCode() == KeyEvent.VK_UP) { keyboardFocusIndex = previousKeyboardFocused(keyboardFocusIndex); } if (keyboardFocusIndex >= 0 && keyboardFocusIndex < viewPanelList.size()) { viewPanelList.get(keyboardFocusIndex).setKeyboardFocused(true); viewPanelList.get(keyboardFocusIndex).repaint(); } else { moreViewsPanel.setKeyboardFocused(true); moreViewsPanel.repaint(); } e.consume(); makeVisible(keyboardFocusIndex); } else if (e.getKeyCode() == KeyEvent.VK_SPACE || e.getKeyCode() == KeyEvent.VK_ENTER) { if (keyboardFocusIndex < viewPanelList.size()) { ViewPanel viewPanel = viewPanelList.get(keyboardFocusIndex); String name = viewPanel.getView().getName(); AnWindow.getInstance().setSelectedView(name); } else { moreViewsPanel.performAction(); } e.consume(); } } private int getRelativeYLocation(int index) { int y = 0; for (int i = 0; i < index; i++) { ViewPanel viewPanel = viewPanelList.get(i); if (viewPanel.isShowing()) { y += viewPanel.getHeight(); } } return y; } private void makeVisible(int index) { int y = getRelativeYLocation(index); Rectangle rectangle = new Rectangle(0, y - 5, 10, ViewPanel.getPanelHeight() + 10); scrollRectToVisible(rectangle); } private int previousKeyboardFocused(int currentKeyboardFocusIndex) { int n = currentKeyboardFocusIndex - 1; while (n >= 0 && !viewPanelList.get(n).isShown()) { n--; } if (n >= 0) { return n; } else { return currentKeyboardFocusIndex; } } private int nextKeyboardFocused(int currentKeyboardFocusIndex) { int n = currentKeyboardFocusIndex + 1; while (n < viewPanelList.size() && !viewPanelList.get(n).isShown()) { n++; } if (n < viewPanelList.size()) { return n; } else { return viewPanelList.size(); } } private void resetKeyboardFocus() { for (ViewPanel viewPanel : viewPanelList) { if (viewPanel.hasKeyboardFocus()) { viewPanel.setKeyboardFocused(false); viewPanel.repaint(); } } if (moreViewsPanel.hasKeyboardFocus()) { moreViewsPanel.setKeyboardFocused(false); moreViewsPanel.repaint(); } keyboardFocusIndex = -1; } public ViewPanel getHasKeyboardFocus() { for (ViewPanel viewPanel : viewPanelList) { if (viewPanel.hasKeyboardFocus()) { return viewPanel; } } return null; } public ViewPanel getIsFocused() { for (ViewPanel viewPanel : viewPanelList) { if (viewPanel.isFocused()) { return viewPanel; } } return null; } public ViewPanel getIsSelected() { for (ViewPanel viewPanel : viewPanelList) { if (viewPanel.isSelected()) { return viewPanel; } } return null; } @Override public void paint(Graphics g) { super.paint(g); if (dropLine >= 0) { g.setColor(AnEnvironment.DROP_LINE_COLOR); Graphics2D g2 = (Graphics2D) g; g2.setStroke(new BasicStroke(2)); g.drawLine(0, dropLine + dropLineOffset, getSize().width, dropLine + dropLineOffset); } int i; for (i = viewPanelList.size() - 1; i >= 0; i--) { ViewPanel viewPanel = (ViewPanel) viewPanelList.get(i); if (viewPanel.isShown()) { break; } } } private JComponent addViewPanelInternal(JComponent viewPanel) { GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = gridY++; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.FIRST_LINE_START; gridBagConstraints.weightx = 1.0; add(viewPanel, gridBagConstraints); return viewPanel; } private void removeAllPanel() { for (ViewPanel vp : viewPanelList) { remove(vp); } remove(moreViewsPanel); } // API begin ---------------------------------------------------- public void removeAllViews() { removeAllPanel(); viewPanelList.clear(); viewPanelOriginalOrder.clear(); relayout(); defaultViewPanel = null; emptyViewStack(); } public void createView(AnWindow anWindow, AnDispTab anDispTab, View.Type type) { // System.out.println("ViewPanels:createView: " + anDispTab.getTCmd()); if (findIndexViewPanel(anDispTab.getTCmd()) >= 0) { // Already there... return; } View view = new View( anDispTab.getTCmd(), anDispTab.getTName(), anDispTab.getShortDescr(), anDispTab.getLongDesc(), anWindow, type, null /*View.generateIconPath()*/); int oldPosition = -1; int thisPostion = 0; // anWindow.presentation may be null if IPC is not started yet boolean showTab = false; if (Analyzer.getInstance().IPC_started) { showTab = anWindow.getSettings().getViewsSetting().isAvailableAndShowing(anDispTab.getTCmd()); } if (getSavedViewPanelOrderList() != null && !getSavedViewPanelOrderList().isEmpty()) { int index = 0; for (ViewPanelOrder cpo : getSavedViewPanelOrderList()) { if (cpo.getName().equals(anDispTab.getTCmd())) { oldPosition = index; showTab = cpo.isShown(); break; } index++; } for (; thisPostion < viewPanelList.size(); thisPostion++) { if (viewPanelList.get(thisPostion).getPosition() > oldPosition) { break; } } } if (oldPosition == -1) { oldPosition = viewPanelList.size(); thisPostion = viewPanelList.size(); } ViewPanel viewPanel = new ViewPanel(view); viewPanel.setPosition(oldPosition); viewPanel.setSidePanel(this); viewPanel.setShown(showTab); viewPanelList.add(thisPostion, viewPanel); viewPanelOriginalOrder.add(viewPanel); // Make the first standard tab the default view to select. if (defaultViewPanel == null && type == View.Type.STANDARD) { defaultViewPanel = viewPanel; } } public ViewPanel getDefaultViewPanel() { return defaultViewPanel; } public void resetAllViews() { removeAllPanel(); for (ViewPanel viewPanel : viewPanelList) { viewPanel.setShown(false); } relayout(); } public void showView(AnDispTab anDispTab) { ViewPanel viewPanel = findViewPanel(anDispTab.getTCmd()); if (viewPanel != null) { viewPanel.setShown(true); } } public void refresh() { // int i = getSelected(); // if (i < 0 || !viewPanelList.get(i).isShown()) { // for (ViewPanel viewPanel : viewPanelList) { // if (viewPanel.isShown()) { // setSelected(viewPanel, true); // break; // } // } // } relayout(); getScrollPane().setVisible(viewPanelList.size() > 1); } public void setSelectedComponent(String cmd) { // System.out.println("ViewsPanel setSelectedComponent " + cmd); for (int i = 0; i < viewPanelList.size(); i++) { ViewPanel viewPanel = viewPanelList.get(i); if (viewPanel.getView().getName().equals(cmd)) { if (!viewPanel.isSelected()) { setSelected(i); } makeVisible(i); if (viewStackPointer >= 0 && viewStackPointer < viewStack.size() && viewStack.elementAt(viewStackPointer).equals(cmd)) { // nothing, just moving up or down the stack } else { // start a 'new' stack pushViewToViewStack(cmd); } break; } } } public void moveViewStackPointer(int x) { viewStackPointer = viewStackPointer + x; } private void emptyViewStack() { viewStack.removeAllElements(); viewStackPointer = -1; } private void pushViewToViewStack(String cmd) { if (viewStackPointer != (viewStack.size() - 1)) { for (int index = viewStack.size() - 1; index > viewStackPointer; index--) { viewStack.remove(index); } } viewStack.push(cmd); viewStackPointer++; } public String nextViewName() { String nextViewName = null; if (viewStack.size() > 0 && (viewStackPointer + 1) >= 0 && (viewStackPointer + 1) < viewStack.size()) { nextViewName = viewStack.elementAt(viewStackPointer + 1); } return nextViewName; } public String previousViewName() { String previousViewName = null; if (viewStack.size() > 0 && (viewStackPointer - 1) >= 0 && (viewStackPointer - 1) < viewStack.size()) { previousViewName = viewStack.elementAt(viewStackPointer - 1); } return previousViewName; } public boolean hasNextViewName() { String nextViewName = nextViewName(); return nextViewName != null; } public boolean hasPreviousViewName() { String previousViewName = previousViewName(); return previousViewName != null; } /** * Called when saving to user pref * * @return */ public List<ViewPanelOrder> getViewPanelOrderPref() { if (viewPanelList == null || viewPanelList.isEmpty()) { return getSavedViewPanelOrderList(); // from user pref. } List<ViewPanelOrder> list = new ArrayList(); for (ViewPanel viewPanel : viewPanelList) { list.add(new ViewPanelOrder(viewPanel.getView().getName(), viewPanel.isShown())); } return list; } public boolean onlyStaticViews() { boolean ret = true; for (ViewPanel viewPanel : viewPanelList) { if (viewPanel.getView().getType() != View.Type.STATIC_VIEW) { ret = false; break; } } return ret; } public boolean onlyWelcomeView() { boolean ret = true; for (ViewPanel viewPanel : viewPanelList) { if (!viewPanel.getView().getName().equals("welcome")) { ret = false; break; } } return ret; } // API end ---------------------------------------------------- private void relayout() { gridY = 2; for (ViewPanel vp : viewPanelList) { if (vp.isShown()) { addViewPanelInternal(vp); } } addViewPanelInternal(moreViewsPanel); refreshInternal(); } private void refreshInternal() { validate(); repaint(100); } private int findViewPanel(ViewPanel viewPanel) { int i = 0; for (i = 0; i < viewPanelList.size(); i++) { if (viewPanelList.get(i) == viewPanel) { return i; } } return -1; } private ViewPanel findViewPanel(String name) { for (int i = 0; i < viewPanelList.size(); i++) { if (viewPanelList.get(i).getView().getName().equals(name)) { return viewPanelList.get(i); } } return null; } private int findIndexViewPanel(String name) { for (int i = 0; i < viewPanelList.size(); i++) { if (viewPanelList.get(i).getView().getName().equals(name)) { return i; } } return -1; } public void addViewPanelAt(int index, ViewPanel viewPanel) { viewPanel.setSidePanel(this); viewPanelList.add(index, viewPanel); removeAllPanel(); relayout(); } public void removeViewPanel(ViewPanel viewPanel) { viewPanel.setShown(false); removeAllPanel(); relayout(); if (viewPanel.isSelected()) { for (ViewPanel vp : viewPanelList) { if (vp.isShown() && vp != viewPanel) { setSelected(vp, true); break; } } } } protected void setSelected(ViewPanel viewPanel, boolean performAction) { if (viewsSelectorDialog != null && viewsSelectorDialog.isVisible()) { viewsSelectorDialog.setVisible(false); viewsSelectorDialog = null; } for (ViewPanel vp : viewPanelList) { vp.setSelected(vp == viewPanel); if (performAction && vp == viewPanel) { View view = viewPanel.getView(); viewPanel.getView().getAnWindow().setSelectedView(view.getName()); } } } public int getSelected() { int sel = -1; int i = 0; for (ViewPanel vp : viewPanelList) { if (vp.isSelected()) { sel = i; } i++; } return sel; } public ViewPanel getSelectedViewPanel() { ViewPanel sel = null; for (ViewPanel vp : viewPanelList) { if (vp.isSelected()) { sel = vp; break; } } return sel; } private void setSelected(int panelNo) { ViewPanel vp = viewPanelList.get(panelNo); setSelected(vp, false); } protected void dropPanelTo(ViewPanel dropViewPanel, Component dropTargetComponent) { int moveFromIndex = findViewPanel(dropViewPanel); int moveToIndex; if (dropTargetComponent instanceof ViewPanel) { ViewPanel targetPanel = (ViewPanel) dropTargetComponent; moveToIndex = findViewPanel(targetPanel); } else { moveToIndex = viewPanelList.size(); while (moveToIndex > 0 && !viewPanelList.get(moveToIndex - 1).isShown()) { moveToIndex--; } } if (moveToIndex < 0) { // something is wrong return; } if (moveFromIndex == moveToIndex) { return; } if (moveFromIndex >= 0) { viewPanelList.remove(moveFromIndex); } if (moveFromIndex < moveToIndex) { moveToIndex--; } addViewPanelAt(moveToIndex, dropViewPanel); refreshInternal(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; filler1 = new javax.swing.Box.Filler( new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 0), new java.awt.Dimension(0, 32767)); setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 100; gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL; gridBagConstraints.weighty = 1.0; add(filler1, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents public void toggleViewsConfigurationPopup(Component component, int x, int y) { Point mouseLocation = MouseInfo.getPointerInfo().getLocation(); if (cancelPoint != null && mouseLocation.x == cancelPoint.x && mouseLocation.y == cancelPoint.y) { cancelPoint = null; return; } showViewsConfigurationPopup(component, x, y); cancelPoint = null; } public void showViewsConfigurationPopup(Component component, int x, int y) { ViewPanel viewPanel; viewPanel = getHasKeyboardFocus(); if (viewPanel == null) { viewPanel = getIsFocused(); } if (viewPanel == null) { viewPanel = getIsSelected(); } viewsSelectorpopup = getViewSelectorPopup(viewPanel != null ? viewPanel.getView() : null); viewsSelectorpopup.show(component, x, y); } private int maxMenus() { if (maxMenus == null) { JPopupMenu popup = new JPopupMenu(); for (int i = 0; i < 10; i++) { popup.add(new JMenu("XXX")); } int height = popup.getPreferredSize().height; maxMenus = AnVariable.SCREEN_SIZE.height / height * 10 - 5; } return maxMenus; } private JPopupMenu getViewSelectorPopup(final View view) { JPopupMenu popup = new JPopupMenu(); JMenu moreMenu = new JMenu(AnLocale.getString("More...")); if (view != null) { String txt = String.format(AnLocale.getString("Help %s View"), view.getDisplayName()); JMenuItem helpMenuItem = new JMenuItem(txt); helpMenuItem.setMnemonic(AnLocale.getString('H', "HelpMenuInViewContextMenu")); helpMenuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { ViewsSetting.View view2 = AnWindow.getInstance().getSettings().getViewsSetting().findView(view.getName()); if (view2 != null) { view2.getAnDispTab().getTComp().showHelp(); } } }); popup.add(helpMenuItem); popup.add(new JSeparator()); } int count = 0; for (ViewPanel viewPanel : viewPanelList) { if (count > maxMenus()) { moreMenu.add(addViewSelector(viewPanel)); } else { popup.add(addViewSelector(viewPanel)); } count++; } if (moreMenu.getSubElements().length > 0) { // popup.addSeparator(); popup.add(moreMenu); } popup.addPopupMenuListener( new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {} @Override public void popupMenuCanceled(PopupMenuEvent e) { cancelPoint = MouseInfo.getPointerInfo().getLocation(); } }); return popup; } private JCheckBoxMenuItem addViewSelector(final ViewPanel viewPanel) { JCheckBoxMenuItem checkBox = new JCheckBoxMenuItem(viewPanel.getView().getDisplayName()); checkBox.setSelected(viewPanel.isShown()); checkBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { String preferredViewName; if (viewPanel.isShown()) { preferredViewName = AnWindow.getInstance().getViews().getCurrentViewName(); } else { preferredViewName = viewPanel.getView().getName(); } AnWindow.getInstance() .getSettings() .getViewsSetting() .toggleTab(viewPanel.getView().getName(), preferredViewName); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { refreshInternal(); } }); } }); return checkBox; } private class MenuItem extends JMenuItem { public MenuItem(String text) { super(text); } @Override public JToolTip createToolTip() { JToolTip toolTip = super.createToolTip(); toolTip.setBackground(AnEnvironment.TOOLTIP_VIEW_BACKGROUND_COLOR); return toolTip; } } public void createViewsMenu(JMenu viewsMenu) { int count = 0; JMenu moreMenu = new JMenu(AnLocale.getString("More...")); viewsMenu.removeAll(); if (!viewPanelOriginalOrder.isEmpty()) { View.Type type = viewPanelOriginalOrder.get(0).getView().getType(); for (ViewPanel viewPanel : viewPanelOriginalOrder) { JMenuItem menuItem = new MenuItem(viewPanel.getView().getDisplayName()); // menuItem.setToolTipText(viewPanel.getView().getLongDescr()); menuItem.addActionListener(new ViewMenuActionListener(viewPanel)); if (count > maxMenus()) { moreMenu.add(menuItem); } else { if (viewPanel.getView().getType() != type) { viewsMenu.addSeparator(); } viewsMenu.add(menuItem); type = viewPanel.getView().getType(); } count++; } if (moreMenu.getSubElements().length > 0) { // viewsMenu.addSeparator(); viewsMenu.add(moreMenu); } } viewsMenu.add(new JSeparator(SwingConstants.HORIZONTAL)); JMenuItem previousViewMenuItem = AnWindow.getInstance().getPreviousViewAction().getMenuItem(); previousViewMenuItem.setIcon(null); viewsMenu.add(previousViewMenuItem); JMenuItem nextViewMenuItem = AnWindow.getInstance().getNextViewAction().getMenuItem(); nextViewMenuItem.setIcon(null); viewsMenu.add(nextViewMenuItem); for (JComponent component : AnWindow.getInstance().getSettings().getViewsSetting().createViewsSettingsSelector()) { viewsMenu.add(component); } } /** * @return the scrollPane */ public JScrollPane getScrollPane() { return scrollPane; } public void selectView(String name) { ViewPanel viewPanel = findViewPanel(name); if (viewPanel != null) { selectView(viewPanel); } } private void selectView(ViewPanel viewPanel) { if (!viewPanel.isShown()) { AnWindow.getInstance() .getSettings() .getViewsSetting() .toggleTab(viewPanel.getView().getName(), viewPanel.getView().getName()); } else { setSelected(viewPanel, true); } } /** * @return the viewPanelOrderList */ public List<ViewPanelOrder> getSavedViewPanelOrderList() { return AnWindow.getInstance().getSettings().getViewsSetting().getSavedViewOrderList(); } class ViewMenuActionListener implements ActionListener { private ViewPanel viewPanel; public ViewMenuActionListener(ViewPanel viewPanel) { this.viewPanel = viewPanel; } @Override public void actionPerformed(ActionEvent e) { selectView(viewPanel); } } class MoreViewsPanel extends JPanel { public MoreViewsPanel() { setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints = new GridBagConstraints(); JLabel label = new JLabel("More Views..."); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); gridBagConstraints.insets = new Insets(4, 4, 4, 4); add(label, gridBagConstraints); } } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.Box.Filler filler1; // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/TopNavigationPanel.java���������������������������������0000644�0001750�0001750�00000015376�14517772113�022515� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.navigation; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Font; import java.awt.GridBagConstraints; import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.JButton; import javax.swing.event.MouseInputAdapter; public class TopNavigationPanel extends javax.swing.JPanel { private AnWindow anWindow; private JButton previousViewButton; private JButton nextViewButton; /** Creates new form TopNavigationPanel */ public TopNavigationPanel(final AnWindow anWindow) { this.anWindow = anWindow; initComponents(); previousViewButton = AnWindow.getInstance().getPreviousViewAction().createActionButton(); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = GridBagConstraints.LINE_END; add(previousViewButton, gridBagConstraints); nextViewButton = AnWindow.getInstance().getNextViewAction().createActionButton(); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(0, 2, 0, 0); gridBagConstraints.anchor = GridBagConstraints.LINE_END; add(nextViewButton, gridBagConstraints); label.setFont(label.getFont().deriveFont(Font.BOLD)); setBackground(AnEnvironment.NAVIGATION_PANEL_SECTION_BACKGROUND_COLOR); // seperator.setForeground(AnEnvironment.VIEW_SELECTED_BORDER_COLOR); setBorder( BorderFactory.createMatteBorder( 0, 0, 1, 0, AnEnvironment.NAVIGATION_SPLIT_PANE_DIVIDER_COLOR)); label.setText(AnLocale.getString("Views")); AnUtility.setAccessibleContext(label.getAccessibleContext(), label.getText()); label.setDisplayedMnemonic(AnLocale.getString('W', "MainPanelViewsMN")); label.setLabelFor(showTabConfigurationButton); // label.setFont(label.getFont().deriveFont(((float)label.getFont().getSize()+1))); showTabConfigurationButton.setBackground( AnEnvironment.NAVIGATION_PANEL_SECTION_BACKGROUND_COLOR); showTabConfigurationButton.setToolTipText(AnLocale.getString("More views...")); showTabConfigurationButton.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { anWindow .getViewsPanel() .toggleViewsConfigurationPopup(showTabConfigurationButton, 15, 15); } }); showTabConfigurationButton.addMouseListener( new MouseInputAdapter() { @Override public void mouseEntered(MouseEvent evt) { JButton btn = (JButton) evt.getSource(); if (btn.isEnabled()) { btn.setBorderPainted(true); btn.setContentAreaFilled(true); } } @Override public void mouseExited(MouseEvent evt) { JButton btn = (JButton) evt.getSource(); if (btn.isEnabled()) { btn.setBorderPainted(false); btn.setContentAreaFilled(false); } } }); addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { anWindow .getViewsPanel() .showViewsConfigurationPopup( TopNavigationPanel.this, e.getPoint().x + 5, e.getPoint().y + 5); } } }); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; label = new javax.swing.JLabel(); showTabConfigurationButton = new javax.swing.JButton(); setLayout(new java.awt.GridBagLayout()); label.setText("NOI18N"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(0, 6, 0, 0); add(label, gridBagConstraints); showTabConfigurationButton.setIcon( new javax.swing.ImageIcon( getClass().getResource("/org/gprofng/mpmt/icons/more_icon.png"))); showTabConfigurationButton.setBorderPainted(false); showTabConfigurationButton.setMargin(new java.awt.Insets(1, 1, 1, 1)); showTabConfigurationButton.setOpaque(false); showTabConfigurationButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showTabConfigurationButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 10; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_END; add(showTabConfigurationButton, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void showTabConfigurationButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_showTabConfigurationButtonActionPerformed // showTabConfigurationActionPerformed(true, // showTabConfigurationButton.getLocation().x+10, // showTabConfigurationButton.getLocation().y+10); } // GEN-LAST:event_showTabConfigurationButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel label; private javax.swing.JButton showTabConfigurationButton; // End of variables declaration//GEN-END:variables } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/ActionPanel.form����������������������������������������0000644�0001750�0001750�00000005232�14517772113�021160� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="nameLabel"> <Properties> <Property name="text" type="java.lang.String" value="NOI18N"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="6" insetsLeft="6" insetsBottom="6" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/ViewsPanel.form�����������������������������������������0000644�0001750�0001750�00000005621�14517772113�021042� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="2"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.Box$Filler" name="filler1"> <Properties> <Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor"> <Dimension value="[0, 32767]"/> </Property> </Properties> <AuxValues> <AuxValue name="classDetails" type="java.lang.String" value="Box.Filler.VerticalGlue"/> </AuxValues> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="100" gridWidth="1" gridHeight="1" fill="3" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="1.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ���������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/ViewPanel.java������������������������������������������0000644�0001750�0001750�00000040741�14517772113�020637� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.navigation; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Font; import java.awt.FontMetrics; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.MouseInfo; import java.awt.Point; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DropTarget; import java.awt.event.ActionEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionAdapter; import java.awt.event.MouseMotionListener; import java.net.URL; import javax.swing.AbstractAction; import javax.swing.ImageIcon; import javax.swing.JComponent; import javax.swing.JToolTip; import javax.swing.KeyStroke; import javax.swing.TransferHandler; public class ViewPanel extends javax.swing.JPanel implements MouseListener, MouseMotionListener, Transferable { private static Image removeImage = null; private static Image removeImageFocused = null; private Image buttonImage = null; private Image selectedArrowImage = null; private static int removeImageWidth = 0; private static int removeImageHeight = 0; private int removeImageXOffset = 4; private int removeImageYOffset = 8; private static int selectedArrowImageWidth = 0; private static int selectedArrowImageHeight = 0; private int selectedArrowXOffset = 4; private int selectedArrowYOffset = 8; private static int scrollbarWidth = 0; private View view; private ViewsPanel sidePanel; private boolean focused = false; private boolean selected = false; private boolean keyboardFocus = false; private boolean shown; private int position; private static Integer panelHeight = null; public ViewPanel(View view) { initComponents(); this.view = view; setBorder(null); nameLabel.setText(view.getDisplayName()); nameLabel.setFont(nameLabel.getFont().deriveFont(Font.BOLD)); AnUtility.setAccessibleContext(nameLabel.getAccessibleContext(), nameLabel.getText()); // nameLabel.setIcon(new javax.swing.ImageIcon(view.getImage())); setBackground( AnEnvironment.NAVIGATION_PANEL_BACKGROUND_COLOR /*AnEnvironment.DEFAULT_PANEL_BACKGROUND*/); addMouseListener(this); addMouseMotionListener(this); addMouseListener( new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { if (e.getButton() == MouseEvent.BUTTON3) { final Point loc1 = MouseInfo.getPointerInfo().getLocation(); final Point loc2 = getLocationOnScreen(); sidePanel.showViewsConfigurationPopup( ViewPanel.this, loc1.x - loc2.x + 5, loc1.y - loc2.y + 5); } } }); // A11Y KeyStroke keyStroke = KeyboardShortcuts.contextMenuActionShortcut; getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(keyStroke, keyStroke); getActionMap() .put( keyStroke, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { final Point loc1 = MouseInfo.getPointerInfo().getLocation(); final Point loc2 = getLocationOnScreen(); sidePanel.showViewsConfigurationPopup( ViewPanel.this, loc1.x - loc2.x + 5, loc1.y - loc2.y + 5); } }); this.shown = false; if (panelHeight == null) { panelHeight = getPreferredSize().height; } } public View getView() { return view; } public void setSidePanel(ViewsPanel sidePanel) { this.sidePanel = sidePanel; addMouseMotionListener(new MouseDraggedListener()); setTransferHandler(new DADTransferHandler()); setDropTarget(new DropTarget(this, new PanelDropTargetListener(sidePanel))); } // @Override @Override public void mouseClicked(MouseEvent me) {} // @Override @Override public void mouseDragged(MouseEvent me) {} // @Override @Override public void mouseEntered(MouseEvent me) { focused = true; refresh(); } // @Override @Override public void mouseExited(MouseEvent me) { focused = false; refresh(); } // @Override @Override public void mouseReleased(MouseEvent me) {} public void setSelected(boolean selected) { this.selected = selected; refresh(); } private void refresh() { // Set background Color backgroundColor; if (isSelected()) { backgroundColor = AnEnvironment.VIEW_SELECTED_BACKGROUND_COLOR; } else if (focused) { backgroundColor = AnEnvironment.VIEW_FOCUSED_BACKGROUND_COLOR; } else { backgroundColor = AnEnvironment.NAVIGATION_PANEL_BACKGROUND_COLOR; } setBackground(backgroundColor); repaint(); } // @Override @Override public void mousePressed(MouseEvent me) { if (me.getButton() == MouseEvent.BUTTON1) { int scrollbarOffset = 0; // getScrollbarOffset(); int x = me.getPoint().x; int y = me.getPoint().y; if (x >= getSize().width - removeImageWidth - removeImageXOffset - scrollbarOffset && x <= getSize().width - removeImageXOffset - scrollbarOffset && y >= removeImageYOffset && y <= removeImageHeight + removeImageYOffset) { closeButtonActionPerformed(null); } else { sidePanel.setSelected(this, true); } } } @Override public JToolTip createToolTip() { JToolTip toolTip = super.createToolTip(); toolTip.setBackground(AnEnvironment.TOOLTIP_VIEW_BACKGROUND_COLOR); return toolTip; } // @Override @Override public void mouseMoved(MouseEvent me) { Image newButtonImage; int scrollbarOffset = 0; // getScrollbarOffset(); int x = me.getPoint().x; int y = me.getPoint().y; if (x >= getSize().width - removeImageWidth - removeImageXOffset - scrollbarOffset && x <= getSize().width - removeImageXOffset - scrollbarOffset && y >= removeImageYOffset && y <= removeImageHeight + removeImageYOffset) { newButtonImage = getRemoveTabFocusedImage(); setToolTipText(AnLocale.getString("Remove this view")); } else { newButtonImage = getRemoveTabImage(); // setToolTipText(getView().getLongDescr()); } if (newButtonImage != getRemoveButtonImage()) { buttonImage = newButtonImage; repaint(); } } // private boolean isScrollbarShowing() { // return sidePanel.getScrollPane().getVerticalScrollBar().isShowing(); // } // private int getScrollbarWidth() { // if (scrollbarWidth == 0) { // scrollbarWidth = sidePanel.getScrollPane().getVerticalScrollBar().getWidth(); // } // return scrollbarWidth; // } // private int getScrollbarOffset() { // if (isScrollbarShowing()) { // return getScrollbarWidth(); // } // else { // return 0; // } // } @Override public void paint(Graphics g) { if (selected || focused) { Graphics2D g2d = (Graphics2D) g; // g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, // RenderingHints.VALUE_ANTIALIAS_ON); Color topColor = selected ? AnEnvironment.VIEW_SELECTED_TOP_COLOR : AnEnvironment.VIEW_FOCUSED_TOP_COLOR; Color bottomColor = selected ? AnEnvironment.VIEW_SELECTED_BOTTOM_COLOR : AnEnvironment.VIEW_FOCUSED_BOTTOM_COLOR; GradientPaint gp = new GradientPaint(0, 0, topColor, 0, getHeight(), bottomColor); g2d.setPaint(gp); g2d.fillRect(0, 0, getWidth(), getHeight()); // Set border Color borderColor; if (selected || focused) { borderColor = AnEnvironment.VIEW_SELECTED_BORDER_COLOR; } else { borderColor = AnEnvironment.NAVIGATION_PANEL_BACKGROUND_COLOR; } g.setColor(borderColor); g.drawLine(0, 0, getWidth(), 0); g.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1); setOpaque(false); } else { setOpaque(true); } super.paint(g); int scrollbarOffset = 0; // getScrollbarOffset(); // FIXUP: doesn't affect rendering here anymore ? if (focused) { g.drawImage( getRemoveButtonImage(), getSize().width - removeImageWidth - removeImageXOffset - scrollbarOffset, removeImageYOffset, this); } else if (selected) { g.drawImage( getSelectedArrowImage(), getSize().width - selectedArrowImageWidth - selectedArrowXOffset - scrollbarOffset, selectedArrowYOffset, this); } String labelText = displayText(g, view.getDisplayName(), true); nameLabel.setText(labelText); setToolTipText(null); if (labelText.endsWith("...")) { setToolTipText(view.getDisplayName()); } if (keyboardFocus) { g.setColor(new Color(180, 180, 180)); g.drawRect(3, 3, getWidth() - 7, getHeight() - 7); } // int w = getWidth(); // int h = getHeight(); // g.setColor(/*selected ? AnEnvironment.DEFAULT_PANEL_BACKGROUND : */selectedBorder); // g.drawLine(w-1, 0, w-1, h); } private String displayText(Graphics g, String name, boolean shortName) { int maxTextWidth = getWidth(); maxTextWidth -= 20; // make room for spaces around text // if (shortName) { // maxTextWidth -= 15; // make room for '>' arrow or 'x' // } // if (isScrollbarShowing()) { // maxTextWidth -= getScrollbarWidth(); // } FontMetrics fontMetrics = g.getFontMetrics(nameLabel.getFont()); int nameWidth = fontMetrics.stringWidth(name); String ret = name; if (nameWidth > maxTextWidth) { ret = shortenText(fontMetrics, name, maxTextWidth); } return ret; } private String shortenText(FontMetrics fontMetrics, String name, int maxTextWidth) { String ret = name; for (int newLength = name.length(); newLength > 0; newLength--) { ret = name.substring(0, newLength) + "..."; ; if (fontMetrics.stringWidth(ret) < maxTextWidth) { break; } } return ret; } private Image getRemoveButtonImage() { if (buttonImage == null) { buttonImage = getRemoveTabImage(); } return buttonImage; } private Image getRemoveTabImage() { if (removeImage == null) { removeImage = AnUtility.removeIcon.getImage(); removeImageWidth = removeImage.getWidth(this); removeImageHeight = removeImage.getHeight(this); } return removeImage; } private Image getRemoveTabFocusedImage() { if (removeImageFocused == null) { removeImageFocused = AnUtility.removeFocusedIcon.getImage(); } return removeImageFocused; } private Image getSelectedArrowImage() { if (selectedArrowImage == null) { URL url = this.getClass().getResource("/org/gprofng/mpmt/icons/nav_bar_arrow.png"); if (url != null) { ImageIcon imageIcon = new ImageIcon(url); selectedArrowImage = imageIcon.getImage(); selectedArrowImageWidth = selectedArrowImage.getWidth(this); selectedArrowImageHeight = selectedArrowImage.getHeight(this); } } return selectedArrowImage; } protected static int getPanelHeight() { if (panelHeight != null) { return panelHeight; } else { return 27; } } /** * @return the shown */ public boolean isShown() { return shown; } /** * @param shown the shown to set */ public void setShown(boolean shown) { this.shown = shown; } /** * @return the position */ public int getPosition() { return position; } /** * @param position the position to set */ public void setPosition(int position) { this.position = position; } class MouseDraggedListener extends MouseMotionAdapter { // @Override @Override public void mouseDragged(MouseEvent e) { JComponent c = (JComponent) e.getSource(); TransferHandler handler = c.getTransferHandler(); handler.exportAsDrag(c, e, TransferHandler.COPY); } } private static DataFlavor dadDataFlavor = null; public static DataFlavor getDADDataFlavor() throws Exception { if (dadDataFlavor == null) { dadDataFlavor = new DataFlavor( DataFlavor.javaJVMLocalObjectMimeType + ";class=org.gprofng.mpmt.navigation.ViewPanel"); } return dadDataFlavor; } // @Override @Override public Object getTransferData(DataFlavor flavor) { DataFlavor thisFlavor; try { thisFlavor = getDADDataFlavor(); } catch (Exception ex) { ex.printStackTrace(System.err); return null; } if (thisFlavor != null && flavor.equals(thisFlavor)) { return ViewPanel.this; } return null; } // @Override @Override public DataFlavor[] getTransferDataFlavors() { DataFlavor[] flavors = {null}; try { flavors[0] = getDADDataFlavor(); } catch (Exception ex) { ex.printStackTrace(System.err); return null; } return flavors; } // @Override @Override public boolean isDataFlavorSupported(DataFlavor flavor) { DataFlavor[] flavors = {null}; try { flavors[0] = getDADDataFlavor(); } catch (Exception ex) { ex.printStackTrace(System.err); return false; } for (DataFlavor f : flavors) { if (f.equals(flavor)) { return true; } } return false; } class DADTransferHandler extends TransferHandler { public DADTransferHandler() { super(); } // @Override() @Override public Transferable createTransferable(JComponent c) { if (c instanceof ViewPanel) { Transferable tip = (ViewPanel) c; return tip; } return null; } // @Override() @Override public int getSourceActions(JComponent c) { if (c instanceof ViewPanel) { return TransferHandler.COPY; } return TransferHandler.NONE; } } // @Override @Override public String toString() { return nameLabel.getText(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; buttonGroup1 = new javax.swing.ButtonGroup(); nameLabel = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); nameLabel.setText("Functions"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 6, 6, 0); add(nameLabel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) { AnWindow.getInstance() .getSettings() .getViewsSetting() .toggleTab(getView().getName(), AnWindow.getInstance().getViews().getCurrentViewName()); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JLabel nameLabel; // End of variables declaration//GEN-END:variables public boolean isSelected() { return selected; } public boolean isFocused() { return focused; } public boolean hasKeyboardFocus() { return keyboardFocus; } public void setKeyboardFocused(boolean keyboardFocused) { this.keyboardFocus = keyboardFocused; } } �������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/View.java�����������������������������������������������0000644�0001750�0001750�00000006357�14517772113�017664� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.navigation; import org.gprofng.mpmt.AnWindow; import java.awt.Image; public class View { public enum Type { STATIC_VIEW, VIEW, STANDARD, INDEX, MEMORY }; private String name; private String displayName; private AnWindow anWindow; private String imagePath; private Image image = null; private Type type; private String shortDescr; private String longDescr; public View( String name, String displayName, String shortDescr, String longDescr, AnWindow anWindow, Type type, String imagePath) { this.name = name; this.displayName = displayName; this.anWindow = anWindow; this.imagePath = imagePath; this.type = type; this.shortDescr = shortDescr; this.longDescr = longDescr; } /** * @return the name */ public String getName() { return name; } /** * @return the type */ public Type getType() { return type; } /** * @return the displayName */ public String getDisplayName() { return displayName; } // /** // * @return the imagePath // */ // public String getImagePath() { // if (imagePath == null) { // imagePath = generateIconPath(); // } // return imagePath; // } // /** // * @return the image // */ // public Image getImage() { // if (image == null) { // URL url = this.getClass().getResource(getImagePath()); // if (url != null) { // ImageIcon imageIcon = new ImageIcon(url); // image = imageIcon.getImage(); // } // } // return image; // } /** * @return the anWindow */ public AnWindow getAnWindow() { return anWindow; } // private static int iconNameIndex = 0; // public static String generateIconPath() { // if (iconNameIndex > 12) { // iconNameIndex = 0; // } // return "/org/gprofng/mpmt/icons/" + "dummy" + iconNameIndex++ + ".png"; // } /** * @return the shortDescr */ public String getShortDescr() { return shortDescr; } /** * @return the longDescr */ public String getLongDescr() { if (longDescr == null) { return "<html><b>" + displayName + " " + "View" + " </b><br>" + displayName + " long" + " description......<br>..............................................<br>..............................................</html>"; } else { return longDescr; } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/ActionPanel.java����������������������������������������0000644�0001750�0001750�00000013603�14517772113�021137� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.navigation; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.awt.Font; import java.awt.GradientPaint; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; public class ActionPanel extends javax.swing.JPanel implements MouseListener, MouseMotionListener { private ActionListener actionListener; private boolean focused = false; private boolean selected = false; private boolean keyboardFocus = false; public ActionPanel(String name, String tooltip, ActionListener actionListener) { initComponents(); nameLabel.setFont(nameLabel.getFont().deriveFont(Font.BOLD)); nameLabel.setText(name); AnUtility.setAccessibleContext(nameLabel.getAccessibleContext(), nameLabel.getText()); setToolTipText(tooltip); setBorder(null); setBackground( AnEnvironment.NAVIGATION_PANEL_BACKGROUND_COLOR /*AnEnvironment.DEFAULT_PANEL_BACKGROUND*/); addMouseListener(this); addMouseMotionListener(this); this.actionListener = actionListener; } // @Override @Override public void mouseClicked(MouseEvent me) { ActionEvent ae = new ActionEvent(me, 0, null); actionListener.actionPerformed(ae); } // @Override @Override public void mouseDragged(MouseEvent me) {} // @Override @Override public void mouseEntered(MouseEvent me) { focused = true; refresh(); } // @Override @Override public void mouseExited(MouseEvent me) { focused = false; refresh(); } // @Override @Override public void mouseReleased(MouseEvent me) { selected = false; refresh(); } // @Override @Override public void mousePressed(MouseEvent me) { selected = true; refresh(); } // @Override @Override public void mouseMoved(MouseEvent me) {} public void setSelected(boolean selected) { this.selected = selected; refresh(); } private void refresh() { // Set background Color backgroundColor; if (isSelected()) { backgroundColor = AnEnvironment.VIEW_SELECTED_BACKGROUND_COLOR; } else if (focused) { backgroundColor = AnEnvironment.VIEW_FOCUSED_BACKGROUND_COLOR; } else { backgroundColor = AnEnvironment.NAVIGATION_PANEL_BACKGROUND_COLOR; } setBackground(backgroundColor); repaint(); } @Override public void paint(Graphics g) { if (selected || focused) { Graphics2D g2d = (Graphics2D) g; Color topColor = selected ? AnEnvironment.VIEW_SELECTED_TOP_COLOR : AnEnvironment.VIEW_FOCUSED_TOP_COLOR; Color bottomColor = selected ? AnEnvironment.VIEW_SELECTED_BOTTOM_COLOR : AnEnvironment.VIEW_FOCUSED_BOTTOM_COLOR; GradientPaint gp = new GradientPaint(0, 0, topColor, 0, getHeight(), bottomColor); g2d.setPaint(gp); g2d.fillRect(0, 0, getWidth(), getHeight()); // Set border Color borderColor; if (selected || focused) { borderColor = AnEnvironment.VIEW_SELECTED_BORDER_COLOR; } else { borderColor = AnEnvironment.NAVIGATION_PANEL_BACKGROUND_COLOR; } g.setColor(borderColor); g.drawLine(0, 0, getWidth(), 0); g.drawLine(0, getHeight() - 1, getWidth(), getHeight() - 1); setOpaque(false); } else { setOpaque(true); } super.paint(g); if (keyboardFocus) { g.setColor(new Color(180, 180, 180)); g.drawRect(3, 3, getWidth() - 7, getHeight() - 7); } } public void performAction() { actionListener.actionPerformed(new ActionEvent(this, 0, null)); } /** * @return the keyboardFocus */ public boolean hasKeyboardFocus() { return keyboardFocus; } /** * @param keyboardFocused the keyboardFocus to set */ public void setKeyboardFocused(boolean keyboardFocused) { this.keyboardFocus = keyboardFocused; } // @Override @Override public String toString() { return nameLabel.getText(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; nameLabel = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); nameLabel.setText("NOI18N"); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(6, 6, 6, 0); add(nameLabel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JLabel nameLabel; // End of variables declaration//GEN-END:variables /** * @return the selected */ public boolean isSelected() { return selected; } } �����������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/navigation/TopNavigationPanel.form���������������������������������0000644�0001750�0001750�00000007706�14517772113�022535� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8" ?> <!-- Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. --> <Form version="1.3" maxVersion="1.8" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <AuxValues> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/> <AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/> <AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/> <AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/> <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,1,44,0,0,1,-112"/> </AuxValues> <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/> <SubComponents> <Component class="javax.swing.JLabel" name="label"> <Properties> <Property name="text" type="java.lang.String" value="NOI18N"/> </Properties> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="6" insetsBottom="0" insetsRight="0" anchor="21" weightX="1.0" weightY="0.0"/> </Constraint> </Constraints> </Component> <Component class="javax.swing.JButton" name="showTabConfigurationButton"> <Properties> <Property name="icon" type="javax.swing.Icon" editor="org.netbeans.modules.form.editors2.IconEditor"> <Image iconType="3" name="/org/gprofng/mpmt/icons/more_icon.png"/> </Property> <Property name="borderPainted" type="boolean" value="false"/> <Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor"> <Insets value="[1, 1, 1, 1]"/> </Property> <Property name="opaque" type="boolean" value="false"/> </Properties> <Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="showTabConfigurationButtonActionPerformed"/> </Events> <Constraints> <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription"> <GridBagConstraints gridX="10" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="22" weightX="0.0" weightY="0.0"/> </Constraint> </Constraints> </Component> </SubComponents> </Form> ����������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ExperimentPickListElement.java�������������������������������������0000644�0001750�0001750�00000004103�14517772113�021673� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.picklist.PickListElement; public class ExperimentPickListElement implements PickListElement { private String path; private String workingDirectory; private String confPath; public ExperimentPickListElement(String path, String workingDirectory, String confPath) { this.path = path; this.workingDirectory = workingDirectory; this.confPath = confPath; } public String getPath() { return path; } public String getWorkingDirectory() { return workingDirectory; } public String getConfPath() { return confPath; } public String getToolTip() { String tt = getPath(); if (getWorkingDirectory() != null) { StringBuilder sb = new StringBuilder(); sb.append("<html>"); sb.append(AnLocale.getString("Path: ")); sb.append(getPath()); sb.append("<br>"); sb.append(AnLocale.getString("Working Directory: ")); sb.append(getWorkingDirectory()); if (confPath != null) { sb.append("<br>"); sb.append(AnLocale.getString("Configuration: ")); sb.append(getConfPath()); } sb.append("<html>"); tt = sb.toString(); } return tt; } /** Compares two PicklistElement for equality. Returns true if equal, otherwise false. */ @Override public boolean equals(PickListElement elem) { return ((ExperimentPickListElement) elem).getPath().equals(this.path); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/flame/�������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�015116� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/flame/FlameView.java�����������������������������������������������0000644�0001750�0001750�00000130257�14517772113�017553� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.flame; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnAction; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnEvent; import org.gprofng.mpmt.AnListener; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnVariable; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.IPC; import org.gprofng.mpmt.KeyboardShortcuts; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnChangeListener; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.export.ExportSupport; import org.gprofng.mpmt.filter.CustomFilterAction; import org.gprofng.mpmt.filter.FilterClause; import org.gprofng.mpmt.filter.RedoFilterAction; import org.gprofng.mpmt.filter.RemoveAllFilterAction; import org.gprofng.mpmt.filter.UndoFilterAction; import org.gprofng.mpmt.mainview.Subview; import org.gprofng.mpmt.settings.AnSettingChangeEvent; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.settings.MetricsSetting.MetricCheckBox; import org.gprofng.mpmt.settings.Settings; import org.gprofng.mpmt.settings.ViewModeSetting; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.statecolors.StateColorMap; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.List; import javax.swing.AbstractAction; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JScrollPane; import javax.swing.JSeparator; import javax.swing.KeyStroke; import javax.swing.SwingUtilities; public class FlameView extends AnDisplay implements ExportSupport, AnChangeListener, AnListener { private static final String ADD_FILTER = AnLocale.getString("Add Filter: "); private static final String FILTER_SELECTED_BRANCH_LONG_NAME = AnLocale.getString("Include only stacks containing the selected branch"); private static final String FILTER_SELECTED_BRANCH_SHORT_NAME = AnLocale.getString("Selected Branch"); private static final String FILTER_NOT_SELECTED_BRANCH_LONG_NAME = AnLocale.getString("Include only stacks not containing the selected branch"); private static final String FILTER_NOT_SELECTED_BRANCH_SHORT_NAME = AnLocale.getString("Not Selected Branch"); private static final String FILTER_SELECTED_FUNCTION_LONG_NAME = AnLocale.getString("Include only stacks containing the selected function"); private static final String FILTER_SELECTED_FUNCTION_SHORT_NAME = AnLocale.getString("Selected Function"); private static final String FILTER_SELECTED_LEAF_LONG_NAME = AnLocale.getString("Include only stacks with the selected function as leaf"); private static final String FILTER_SELECTED_LEAF_SHORT_NAME = AnLocale.getString("Selected Leaf"); private static final String STR_ACTION_UNDO_FILTER = AnLocale.getString("Undo Filter Action"); private static final String STR_ACTION_REDO_FILTER = AnLocale.getString("Redo Filter Action"); private static final String STR_ACTION_REMOVE_ALL_FILTERS = AnLocale.getString("Remove All Filters"); private static final String STR_ACTION_CUSTOM_FILTER = ADD_FILTER + AnLocale.getString("Advanced Custom Filter..."); // Data private int rowCount = -1; private FlameData flameData = null; private Object flameDataLock = new Object(); private MainThread mainThread = null; // GUI private FlamePanel flamePanel; private JScrollPane mainScrollPane; private JPanel mainToolbarPanel; private FlameToolBar flameToolBar; private JPanel detailsPanel; private JLabel detailsLabel; // States private boolean mainThreadKilled = false; private AnMetric anMetricToBeUsed = null; private boolean supportedExperiments = true; // Actions private AnAction undoSetBaseAction; private AnAction redoSetBaseAction; private AnAction resetBaseAction; private AnAction setBaseAction; private AnAction upOneAction; private AnAction downOneAction; private AnAction leftOneAction; private AnAction rightOneAction; // Debug // private static Date beginDate = new Date(); // Constructor public FlameView() { super(AnWindow.getInstance(), AnDisplay.DSP_CallFlame, AnVariable.HELP_CallFlameChart); setAccessibility(AnLocale.getString("Flame Graph")); AnEventManager.getInstance().addListener(this); AnWindow.getInstance().getColorChooser().getColorMap().addAnListener(this); KeyStroke ks = KeyboardShortcuts.contextMenuActionShortcut; getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks, ks); getActionMap() .put( ks, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { flamePanel.showPopup(getFlameData().getSelectedFlameBlock()); } }); } /** * AnChangeEvent handler. Events are always dispatched on AWT thread. Requirements to an event * handler like this one: o When it done handling the event and returns, all it's states need to * be *consistent* and *well-defined*. It cannot dispatch that or part of that work to a different * (worker) thread and not wait for it to finish. o It cannot spend significant time handling the * event. Significant work like doCompute needs to be dispatched to a worker thread. * * @param e the event */ @Override public void stateChanged(AnChangeEvent e) { // System.out.println("CallTreeView stateChanged: " + e.getType()); switch (e.getType()) { case EXPERIMENTS_LOADING_ADDED_OR_REMOVED: case EXPERIMENTS_LOADING_NEW: computed = false; initView(); break; case EXPERIMENTS_LOADED_FAILED: // Nothing break; case EXPERIMENTS_LOADED: handleSupportedExperiments(); if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGED: interruptMainThread(); computed = false; if (selected) { computeOnAWorkerThread(); } break; case FILTER_CHANGING: case REMOTE_CONNECTION_CHANGING: case REMOTE_CONNECTION_CANCELLED_OR_FAILED: case REMOTE_CONNECTION_CHANGED: case MOST_RECENT_EXPERIMENT_LIST_CHANGED: case SOURCE_FINDING_CHANGING: case SOURCE_FINDING_CHANGED: case SETTING_CHANGING: case SELECTED_OBJECT_CHANGED: case SELECTION_CHANGING: case SELECTION_CHANGED: case SELECTION_UPDATE: // Nothing break; case SETTING_CHANGED: AnSettingChangeEvent anSettingChangeEvent = (AnSettingChangeEvent) e.getSource(); if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.VIEW_MODE || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.LIBRARY_VISIBILITY || anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { if (anSettingChangeEvent.getType() == AnSettingChangeEvent.Type.METRICS) { Object o = anSettingChangeEvent.getOriginalSource(); if (o instanceof MetricsSetting.MetricCheckBox) { anMetricToBeUsed = ((MetricCheckBox) o).getAnMetric(); } else { anMetricToBeUsed = null; } } computed = false; if (selected) { computeOnAWorkerThread(); } } break; case DEBUG: debug(); break; default: System.err.println("AnChanged event " + e.getType() + " not handled: " + this); break; } } @Override public void valueChanged(AnEvent e) { flamePanel.functionColorsChanged(); } @Override public JPopupMenu getFilterPopup() { if (getFlameData() != null) { JPopupMenu popup = new JPopupMenu(); for (JComponent jmi : getFilterMenuList(getFlameData().getSelectedFlameBlock())) { popup.add(jmi); } return popup; } else { return null; } } protected FlameToolBar getFlameToolBar() { return flameToolBar; } private void initActions() { undoSetBaseAction = new AnAction( AnLocale.getString("Undo Set As Base"), AnUtility.undo_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (undoSetBaseAction.isEnabled()) { flameToolBar.undoSetBaseStack(); } } }); undoSetBaseAction.setKeyboardShortCut( this, "FLAME_BACKSPACE", KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)); redoSetBaseAction = new AnAction( AnLocale.getString("Redo Set As Base"), AnUtility.redo_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (redoSetBaseAction.isEnabled()) { flameToolBar.redoSetBaseStack(); } } }); redoSetBaseAction.setKeyboardShortCut( this, "FLAME_SHIFT_BACKSPACE", KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, InputEvent.SHIFT_DOWN_MASK)); resetBaseAction = new AnAction( AnLocale.getString("Reset Base"), AnUtility.base2Icon, AnLocale.getString("Reset Base to <Total>"), null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (resetBaseAction.isEnabled()) { flamePanel.resetBase(); } } }); resetBaseAction.setKeyboardShortCut( this, "FLAME_SHIFT_ENTER", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK)); setBaseAction = new AnAction( AnLocale.getString("Set As Base"), AnUtility.base1Icon, AnLocale.getString("Set Base to Selected Function"), null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (setBaseAction.isEnabled()) { flamePanel.setAsBase(); } } }); setBaseAction.setKeyboardShortCut( this, "FLAME_ENTER", KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false)); upOneAction = new AnAction( AnLocale.getString("Up One"), AnUtility.up_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (upOneAction.isEnabled()) { flamePanel.upOne(); } } }); upOneAction.setKeyboardShortCut( this, "FLAME_UP", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false)); // String ks_string = "FLAME_UP"; ;;; // KeyStroke ks_def = KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false); // this.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(ks_def, // ks_string); // this.getActionMap().put(ks_string, new AbstractAction() { // @Override // public void actionPerformed(ActionEvent ev) { // upOneAction.actionPerformed(ev); // } // }); downOneAction = new AnAction( AnLocale.getString("Down One"), AnUtility.down_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (downOneAction.isEnabled()) { flamePanel.downOne(); } } }); downOneAction.setKeyboardShortCut( this, "FLAME_DOWN", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false)); leftOneAction = new AnAction( AnLocale.getString("Left One"), AnUtility.back_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (leftOneAction.isEnabled()) { flamePanel.leftOne(); } } }); leftOneAction.setKeyboardShortCut( this, "FLAME_LEFT", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false)); rightOneAction = new AnAction( AnLocale.getString("Right One"), AnUtility.forw_icon, null, null, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if (rightOneAction.isEnabled()) { flamePanel.rightOne(); } } }); rightOneAction.setKeyboardShortCut( this, "FLAME_RIGHT", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false)); } protected AnAction getUndoSetBaseAction() { return undoSetBaseAction; } protected AnAction getRedoSetBaseAction() { return redoSetBaseAction; } protected AnAction getResetBaseAction() { return resetBaseAction; } protected AnAction getSetBaseAction() { return setBaseAction; } protected AnAction getUpOneAction() { return upOneAction; } protected AnAction getDownOneAction() { return downOneAction; } protected AnAction getLeftOneAction() { return leftOneAction; } protected AnAction getRightOneAction() { return rightOneAction; } protected void updateActionsEnableStatus() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { getFlameToolBar().setControilsEnabled(true); getUndoSetBaseAction().setEnabled(flameToolBar.canUndoSetBaseStack()); getRedoSetBaseAction().setEnabled(flameToolBar.canRedoSetBaseStack()); getResetBaseAction().setEnabled(flamePanel.canResetBase()); getSetBaseAction().setEnabled(flamePanel.canSetBase()); getUpOneAction().setEnabled(flamePanel.canUpOne()); getDownOneAction().setEnabled(flamePanel.canDownOne()); getLeftOneAction().setEnabled(flamePanel.canLeftOne()); getRightOneAction().setEnabled(flamePanel.canRightOne()); } }); } protected void resetActionsEnableStatus() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { getFlameToolBar().setControilsEnabled(false); getUndoSetBaseAction().setEnabled(false); getRedoSetBaseAction().setEnabled(false); getResetBaseAction().setEnabled(false); getSetBaseAction().setEnabled(false); getUpOneAction().setEnabled(false); getDownOneAction().setEnabled(false); getLeftOneAction().setEnabled(false); getRightOneAction().setEnabled(false); } }); } @Override protected void initComponents() { initActions(); setLayout(new BorderLayout()); JPanel toolbarPanel = new JPanel(); toolbarPanel.setBackground(AnEnvironment.TOOLBAR_BACKGROUND_COLOR); toolbarPanel.add(flameToolBar = new FlameToolBar(this)); mainToolbarPanel = new JPanel(new BorderLayout()); mainToolbarPanel.add(toolbarPanel, BorderLayout.NORTH); add(mainToolbarPanel, BorderLayout.NORTH); flamePanel = new FlamePanel(this); mainScrollPane = new JScrollPane(flamePanel); mainScrollPane.setBorder(null); mainScrollPane.getVerticalScrollBar().setUnitIncrement(32); mainScrollPane.getVerticalScrollBar().setBlockIncrement(32); mainScrollPane.getVerticalScrollBar().setValueIsAdjusting(true); add(mainScrollPane, BorderLayout.CENTER); detailsPanel = new JPanel(); detailsPanel.setBorder( BorderFactory.createMatteBorder(1, 0, 0, 0, AnEnvironment.TABBED_PANE_BORDER_COLOR)); detailsPanel.setLayout(new GridBagLayout()); GridBagConstraints gridBagConstraints; detailsLabel = new JLabel(); // detailsLabel.setFont(detailsLabel.getFont().deriveFont(Font.BOLD)); gridBagConstraints = new GridBagConstraints(); gridBagConstraints.fill = GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 0; gridBagConstraints.insets = new Insets(4, 4, 0, 0); detailsPanel.add(detailsLabel, gridBagConstraints); detailsPanel.setMinimumSize(new Dimension(10, 10)); add(detailsPanel, BorderLayout.SOUTH); resetActionsEnableStatus(); } protected void updateSelection() { if (getFlameData() != null) { updateSelection(getFlameData().getSelectedFlameBlock()); } else { updateSelection(null); } } protected void updateSelection(final FlameBlock selectedFlameBlock) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { if (selectedFlameBlock != null) { detailsLabel.setText(selectedFlameBlock.getDetailsTextHTML()); } else { detailsLabel.setText(FlameBlock.getDetailsEmptyTextHTML()); } detailsLabel.setToolTipText(detailsLabel.getText()); } }); } protected void updateGUI(final AnMetric anMetric) { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { flamePanel.setPanelSize(rowCount); SwingUtilities.invokeLater( new Runnable() { @Override public void run() { flameToolBar.resetZoom(); flameToolBar.resetMetrics(anMetric); scrollToRow(0); } }); } }); } protected void scrollToRow(final int row) { SwingUtilities.invokeLater( new Runnable() { @Override public void run() { int extraPixels = 10; // System.out.println(height + " " + (height - (row + 1) * // flamePanel.getRowHeight() + 2)); flamePanel.scrollRectToVisible( new Rectangle( 0, flamePanel.getSize().height - (row + 1) * flamePanel.getRowHeight() - flamePanel.getOuterGap() - flamePanel.getInnerGap() - extraPixels / 2, 10, flamePanel.getRowHeight() + 1 + extraPixels)); mainScrollPane.revalidate(); } }); } protected void setMetric(AnMetric anMetric) { anMetricToBeUsed = anMetric; computed = false; if (selected) { computeOnAWorkerThread(); } } private final long getFuncObj() { final long funcObj; funcObj = AnWindow.getInstance().getSelectedObject().getSelObjV2("FUNCTION"); // API V2 return funcObj; } @Override public void doCompute() { if (!supportedExperiments) { // Some not suppoted conditions (compare) return; } long selectedFunction = getFuncObj(); // Synchronize selected function from Functions and other views. if (!computed) { resetActionsEnableStatus(); if (mainThreadKilled) { if (mainThread != null) { try { mainThread.join(); } catch (InterruptedException ie) { System.err.println("mainThread.join() interrupted..."); } mainThread = null; } mainThreadKilled = false; } if (mainThread != null) { // being computed return; } // Do compute // beginDate = new Date(); AnMetric anMetric; if (anMetricToBeUsed != null) { anMetric = anMetricToBeUsed; } else { anMetric = AnWindow.getInstance().getSettings().getMetricsSetting().getSortColumnMetric(0); } resetView(); rowCount = getCallTreeNumLevelsIPC(); updateGUI(anMetric); if (rowCount > 0) { flameData = new FlameData(this, anMetric, rowCount); mainThread = new MainThread(anMetric.getComd(), selectedFunction); mainThread.start(); } else { initView(); // ??? } } else { FlameBlock selectedFlameBlock = flameData.findFunctionFlameBlock(selectedFunction); if (selectedFlameBlock != null) { flameData.setSelectedFlameBlock(selectedFlameBlock); updateActionsEnableStatus(); } } } @Override protected boolean supportsFindText() { return true; } @Override public int find(String str, boolean forward, boolean caseSensitive) { FlameBlock selectedFlameBlock = getFlameData().getSelectedFlameBlock(); FlameBlock fb = getFlameData().nextFlameBlock(selectedFlameBlock, forward); while (fb != null) { boolean match = false; if (caseSensitive) { match = fb.getFunctionDisplayName().contains(str); } else { match = fb.getFunctionDisplayName().toLowerCase().contains(str.toLowerCase()); } if (match) { flamePanel.setSelectedFlameBlock(fb); return 1; } if (fb == selectedFlameBlock) { return -1; } fb = getFlameData().nextFlameBlock(fb, forward); } return -1; } @Override public List<ExportFormat> getSupportedExportFormats() { List<ExportFormat> formats = new ArrayList<ExportFormat>(); formats.add(ExportFormat.JPG); return formats; } @Override public boolean exportLimitSupported() { return false; } /* * For GUI testing */ @Override public String exportAsText( Integer limit, ExportSupport.ExportFormat format, Character delimiter) { return getFlameData().dump(limit); } @Override public List<Subview> getVisibleSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); // list.add(window.getTimelineCallStackSubview()); // list.add(window.getIoCallStackSubview()); return list; } @Override public List<Subview> getSelectedSubviews() { List<Subview> list = new ArrayList(); list.add(window.getSelectedDetailsSubview()); return list; } private void handleSupportedExperiments() { if (window.getSettings().getCompareModeSetting().comparingExperiments()) { // Not supported remove(mainToolbarPanel); remove(mainScrollPane); JLabel errorLabel = new JLabel(); errorLabel.setHorizontalAlignment(JLabel.CENTER); errorLabel.getAccessibleContext().setAccessibleName(AnLocale.getString("Error message")); errorLabel .getAccessibleContext() .setAccessibleDescription(AnLocale.getString("Error message")); String msg = AnLocale.getString("Not available when comparing experiments"); errorLabel.setText(msg); add(errorLabel, BorderLayout.CENTER); supportedExperiments = false; } else { // Supported if (!supportedExperiments) { add(mainToolbarPanel, BorderLayout.NORTH); add(mainScrollPane, BorderLayout.CENTER); } supportedExperiments = true; } } /** Called when new experiment loaded */ private void initView() { mainThread = null; flameData = null; flamePanel.initView(); resetActionsEnableStatus(); } /** Called before everything is recomputed (doCompute) */ private void resetView() { mainThread = null; flameData = null; flamePanel.resetView(); } private void interruptMainThread() { if (mainThread != null) { mainThread.kill(); mainThreadKilled = true; } } class MainThread extends Thread { String metricName; long selectedFunction; RowThread[] rowThreads = null; boolean killed = false; private MainThread(String metricName, long selectedFunction) { this.metricName = metricName; this.selectedFunction = selectedFunction; } @Override public void run() { killed = false; rowThreads = new RowThread[rowCount]; for (int row = 0; row < rowCount; row++) { rowThreads[row] = new RowThread(this, metricName, row); rowThreads[row].start(); } // Wait till all rows are filled (or thred is killed) synchronized (this) { try { wait(); } catch (InterruptedException ie) { } } if (!killed) { computed = true; FlameBlock selectedFlameBlock = flameData.findFunctionFlameBlock(selectedFunction); if (selectedFlameBlock != null) { flameData.setSelectedFlameBlock(selectedFlameBlock); } updateActionsEnableStatus(); } mainThread = null; } private void rowIsComplete(FlameRow flameRow) { getFlameData().rowDone(flameRow); // FIXUP: NPE rowThreads[flameRow.getRow()] = null; flamePanel.rowIsComplete(flameRow.getRow()); // Check if all rows are done boolean allDone = true; for (RowThread rowThread : rowThreads) { if (rowThread != null) { allDone = false; break; } } if (allDone) { interrupt(); } } private void kill() { for (RowThread rowThread : rowThreads) { if (rowThread != null) { rowThread.kill(); } } killed = true; interrupt(); } } protected FlamePanel getFlamePanel() { return flamePanel; } class RowThread extends Thread { MainThread mainThread; private int row; private String metricName; private boolean killed = false; private RowThread(MainThread mainThread, String metricName, int row) { this.mainThread = mainThread; this.metricName = metricName; this.row = row; } @Override public void run() { killed = false; List<FlameRow> flameRows = getRowDataIPC(metricName, row); if (!killed && !isInterrupted()) { for (FlameRow flameRow : flameRows) { mainThread.rowIsComplete(flameRow); } } } private void kill() { killed = true; interrupt(); } } protected List<JComponent> getFilterMenuList(FlameBlock flameBlock) { String text; JMenuItem menuItem; List<JComponent> list = new ArrayList<JComponent>(); text = ADD_FILTER + FILTER_SELECTED_BRANCH_LONG_NAME; menuItem = new JMenuItem(new FilterSelectedBranch(text, flameBlock)); menuItem.getAccessibleContext().setAccessibleDescription(text); menuItem.setEnabled(flameBlock != null); list.add(menuItem); text = ADD_FILTER + FILTER_NOT_SELECTED_BRANCH_LONG_NAME; menuItem = new JMenuItem(new FilterNotSelectedBranch(text, flameBlock)); menuItem.getAccessibleContext().setAccessibleDescription(text); menuItem.setEnabled(flameBlock != null); list.add(menuItem); text = ADD_FILTER + FILTER_SELECTED_FUNCTION_LONG_NAME; menuItem = new JMenuItem(new FilterSelectedFunction(text, flameBlock)); menuItem.getAccessibleContext().setAccessibleDescription(text); menuItem.setEnabled(flameBlock != null); list.add(menuItem); text = ADD_FILTER + FILTER_SELECTED_LEAF_LONG_NAME; menuItem = new JMenuItem(new FilterSelectedLeaf(text, flameBlock)); menuItem.getAccessibleContext().setAccessibleDescription(text); menuItem.setEnabled(flameBlock != null); list.add(menuItem); text = STR_ACTION_CUSTOM_FILTER; menuItem = new JMenuItem(new CustomFilterAction()); menuItem.getAccessibleContext().setAccessibleDescription(text); list.add(menuItem); list.add(new JSeparator()); text = STR_ACTION_UNDO_FILTER; menuItem = new JMenuItem(new UndoFilterAction()); menuItem.getAccessibleContext().setAccessibleDescription(text); menuItem.setEnabled(window.getFilters().canUndoLastFilter()); list.add(menuItem); text = STR_ACTION_REDO_FILTER; menuItem = new JMenuItem(new RedoFilterAction()); menuItem.getAccessibleContext().setAccessibleDescription(text); menuItem.setEnabled(window.getFilters().canRedoLastFilter()); list.add(menuItem); text = STR_ACTION_REMOVE_ALL_FILTERS; menuItem = new JMenuItem(new RemoveAllFilterAction()); menuItem.getAccessibleContext().setAccessibleDescription(text); menuItem.setEnabled(window.getFilters().canRemoveAllFilters()); list.add(menuItem); if (window.getFilters().anyFilters()) { list.add(window.getFilters().removeFilterMenuItem()); } return list; } private class FilterSelectedBranch extends AbstractAction { private FlameBlock flameBlock; private FilterSelectedBranch(String text, FlameBlock flameBlock) { super(text); this.flameBlock = flameBlock; } @Override public void actionPerformed(ActionEvent e) { StringBuilder buf = new StringBuilder(); buf.append("(("); String buf2 = ""; FlameBlock fb = flameBlock; while (fb != null) { if (!buf2.isEmpty()) { buf2 = "," + buf2; } buf2 = fb.getFunctionID() + buf2; fb = fb.getNextFlameBlock(FlameBlock.DOWN); } buf.append(buf2); buf.append(") ORDERED IN " + getStack() + ")"); String clause = buf.toString(); setFilterClause(FILTER_SELECTED_BRANCH_SHORT_NAME, FILTER_SELECTED_BRANCH_LONG_NAME, clause); } } private class FilterNotSelectedBranch extends AbstractAction { private FlameBlock flameBlock; private FilterNotSelectedBranch(String text, FlameBlock flameBlock) { super(text); this.flameBlock = flameBlock; } @Override public void actionPerformed(ActionEvent e) { StringBuilder buf = new StringBuilder(); buf.append("(!(("); String buf2 = ""; FlameBlock fb = flameBlock; while (fb != null) { if (!buf2.isEmpty()) { buf2 = "," + buf2; } buf2 = fb.getFunctionID() + buf2; fb = fb.getNextFlameBlock(FlameBlock.DOWN); } buf.append(buf2); buf.append(") ORDERED IN " + getStack() + "))"); String clause = buf.toString(); setFilterClause( FILTER_NOT_SELECTED_BRANCH_SHORT_NAME, FILTER_NOT_SELECTED_BRANCH_LONG_NAME, clause); } } private class FilterSelectedFunction extends AbstractAction { private FlameBlock flameBlock; private FilterSelectedFunction(String text, FlameBlock flameBlock) { super(text); this.flameBlock = flameBlock; } @Override public void actionPerformed(ActionEvent e) { StringBuilder buf = new StringBuilder(); buf.append("(("); buf.append("" + flameBlock.getFunctionID()); buf.append(") IN " + getStack() + ")"); String clause = buf.toString(); setFilterClause( FILTER_SELECTED_FUNCTION_SHORT_NAME, FILTER_SELECTED_FUNCTION_LONG_NAME, clause); } } private class FilterSelectedLeaf extends AbstractAction { private FlameBlock flameBlock; private FilterSelectedLeaf(String text, FlameBlock flameBlock) { super(text); this.flameBlock = flameBlock; } @Override public void actionPerformed(ActionEvent e) { StringBuilder buf = new StringBuilder(); buf.append("((" + getStack() + "+0) IN ("); buf.append("" + flameBlock.getFunctionID()); buf.append("))"); String clause = buf.toString(); setFilterClause(FILTER_SELECTED_LEAF_SHORT_NAME, FILTER_SELECTED_LEAF_LONG_NAME, clause); } } private String getStack() { String stack = "USTACK"; Settings settings = AnWindow.getInstance().getSettings(); if (settings.getViewModeEnabledSetting().isViewModeEnabled()) { ViewModeSetting viewModeSetting = settings.getViewModeSetting(); if (viewModeSetting.get() == ViewModeSetting.ViewMode.USER) { stack = "USTACK"; } else if (viewModeSetting.get() == ViewModeSetting.ViewMode.EXPERT) { stack = "XSTACK"; } else if (viewModeSetting.get() == ViewModeSetting.ViewMode.MACHINE) { stack = "MSTACK"; } } return stack; } private void setFilterClause(String shortName, String longName, String clause) { window .getFilters() .addClause( getAnDispTab().getTName() + ": " + shortName, longName, clause, FilterClause.Kind.STANDARD); } // **************** Public ************************ protected FlameData getFlameData() { return flameData; } protected Object getFlameDataLock() { return flameDataLock; } // **************** IPC ************************ private int getCallTreeNumLevelsIPC() { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { anWindow.IPC().send("getCallTreeNumLevels"); anWindow.IPC().send(0); return anWindow.IPC().recvInt(); } } private Object[] getCallTreeFuncsIPC(int startLevel, int endLevel) { AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { // Date start = new Date();//YXXX timing debug (delete-me later) anWindow.IPC().send("getCallTreeLevelFuncs"); anWindow.IPC().send(0); anWindow.IPC().send(startLevel); anWindow.IPC().send(endLevel); Object[] res = (Object[]) anWindow.IPC().recvObject(); // {//YXXX timing debug (delete-me later) // Date now = new Date(); // long duration = now.getTime() - start.getTime(); // int nfuncs = (res == null) ? 0 : ((long[]) res[0]).length; // System.out.println("getCallTreeFuncsIPC duration=" + duration + "ms // funcCount=" + nfuncs); // System.out.flush(); // } return res; } } private Object[] getCallTreeLevelsIPC(String metricName) { // get all rows AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { // Date start = new Date();//YXXX timing debug (delete-me later) anWindow.IPC().send("getCallTreeLevels"); anWindow.IPC().send(0); anWindow.IPC().send(metricName); Object[] res = (Object[]) anWindow.IPC().recvObject(); // {//YXXX timing debug (delete-me later) // Date now = new Date(); // long duration = now.getTime() - start.getTime(); // int row_count = res.length; // System.out.println("getRowDataIPC duration=" + duration + "ms total_rows=" + // row_count); // System.out.flush(); // } return res; } } private static long YXXXduration = 0; private static long YXXXnode_total = 0; private Object[] getCallTreeLevelIPC(String metricName, int row) { // get one row AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { Date start = new Date(); // YXXX timing debug (delete-me later) anWindow.IPC().send("getCallTreeLevel"); anWindow.IPC().send(0); anWindow.IPC().send(metricName); anWindow.IPC().send(row); Object[] res = (Object[]) anWindow.IPC().recvObject(); { // YXXX timing debug (delete-me later) Date now = new Date(); long duration = now.getTime() - start.getTime(); YXXXduration += duration; int item_cnt = (res != null) ? ((int[]) res[0]).length : 0; YXXXnode_total += item_cnt; System.out.printf( "getRowDataIPC row=%d items=%d sum_items=%d duration=%dms sum_duration=%dms\n", row, item_cnt, YXXXnode_total, duration, YXXXduration); System.out.flush(); } return res; } } private Object[] getCallTreeChildrenIPC( String metricName, int row, int[] parentNodeIds) { // get node children AnWindow anWindow = AnWindow.getInstance(); synchronized (IPC.lock) { Date start = new Date(); // YXXX timing debug (delete-me later) anWindow.IPC().send("getCallTreeChildren"); anWindow.IPC().send(0); anWindow.IPC().send(metricName); anWindow.IPC().send(parentNodeIds); Object[] res = (Object[]) anWindow.IPC().recvObject(); { // YXXX timing debug (delete-me later) Date now = new Date(); long duration = now.getTime() - start.getTime(); YXXXduration += duration; int parent_cnt = 0; int node_cnt = 0; if (res != null) { parent_cnt = res.length; for (int ii = 0; ii < parent_cnt; ii++) { Object[] tmp = (Object[]) res[ii]; if (tmp != null) { int tmp2[] = (int[]) tmp[0]; node_cnt += tmp2 != null ? tmp2.length : 0; } } } YXXXnode_total += node_cnt; System.out.printf( "getCallTreeChildrenIPC row=%d parents=%d items=%d sum_items=%d duration=%dms" + " sum_duration=%dms\n", row, parent_cnt, node_cnt, YXXXnode_total, duration, YXXXduration); System.out.flush(); } return res; } } // processing of processCallTree*IPC() data for one set of blocks private List<FlameBlock> processCallTreeNodeIPC(Object[] blockInfo) { List<FlameBlock> flameBlocks = new ArrayList<FlameBlock>(); if (blockInfo == null) { return flameBlocks; } int[] blockIDs = (int[]) blockInfo[0]; int[] parentIDs = (int[]) blockInfo[1]; long[] functionIDs = (long[]) blockInfo[2]; Object metricObjs = (Object) blockInfo[3]; // could be double, int, long if (blockIDs == null || blockIDs.length == 0) { return flameBlocks; } final double metricValues[]; { if (metricObjs instanceof int[]) { int objv[] = (int[]) metricObjs; metricValues = new double[objv.length]; for (int kk = 0; kk < objv.length; kk++) { metricValues[kk] = objv[kk]; } } else if (metricObjs instanceof long[]) { long objv[] = (long[]) metricObjs; metricValues = new double[objv.length]; for (int kk = 0; kk < objv.length; kk++) { metricValues[kk] = objv[kk]; } } else if (metricObjs instanceof double[]) { double objv[] = (double[]) metricObjs; metricValues = new double[objv.length]; for (int kk = 0; kk < objv.length; kk++) { metricValues[kk] = objv[kk]; } } else { return flameBlocks; // weird } } for (int kk = 0; kk < blockIDs.length; kk++) { int id = blockIDs[kk]; int parentId = parentIDs[kk]; long functionId = functionIDs[kk]; double exclusiveValue = 0; double attributedValue = metricValues[kk]; if (kk < (blockIDs.length - 1) && functionId == functionIDs[kk + 1] && parentId == parentIDs[kk + 1]) { // Combine exclusive and attributed into one block id = blockIDs[kk + 1]; exclusiveValue = metricValues[kk]; attributedValue = metricValues[kk + 1]; kk++; } flameBlocks.add(new FlameBlock(id, parentId, functionId, exclusiveValue, attributedValue)); } Collections.sort(flameBlocks, new FlameBlockComrator()); // Sort by value return flameBlocks; } class FlameBlockComrator implements Comparator<FlameBlock> { @Override public int compare(FlameBlock o1, FlameBlock o2) { if (o1.getParentID() == o2.getParentID()) { double v1 = o1.getInclusiveValue(); double v2 = o2.getInclusiveValue(); if (v1 == v2) { return 0; } else if (v1 < v2) { return 1; } else { return -1; } } else { return 0; // keep parent order unchanged } } } private boolean XXXgetRowByLevel = false; private boolean XXXallRowsAtOnce = true; private void updateColorMapIPC(int row) { int level_start = 0, level_end = -1; if (XXXgetRowByLevel) { level_start = level_end = row; } else if (row != 0) { return; } Object[] res = getCallTreeFuncsIPC(level_start, level_end); if (res != null) { AnWindow anWindow = AnWindow.getInstance(); StateColorMap colorMap = anWindow.getColorChooser().getColorMap(); long[] ids = (long[]) res[0]; String[] names = (String[]) res[1]; long[] functions = (long[]) res[2]; List<StackState> states = new ArrayList(); HashMap<Long, StackState> functionIdNameMap = new HashMap<Long, StackState>(); for (int ii = 0; ii < ids.length; ii++) { // Colors if (names[ii] == null) { continue; } StackState state = new StackState(names[ii], functions[ii]); // name, Histable::Function* states.add(state); // Function names functionIdNameMap.put(ids[ii], state); } colorMap.addStates(states); getFlameData().setFunctionIdNameMap(functionIdNameMap); // FIXUP: NPE } } /** returns row data */ private List<FlameRow> getRowDataIPC(String metricName, int row) { // examples of three methods. updateColorMapIPC(row); List<FlameRow> flameRows = new ArrayList(); if (XXXgetRowByLevel) { Object[] tmp = getCallTreeLevelIPC(metricName, row); List<FlameBlock> blocks = processCallTreeNodeIPC(tmp); flameRows.add(new FlameRow(getFlameData(), row, blocks)); return flameRows; } if (row != 0) { // only return multi-row values on thread 0 return flameRows; } int row_count = 0; int totalBlockCount = 0; if (XXXallRowsAtOnce) { // get all levels with single IPC Object[] tmp = getCallTreeLevelsIPC(metricName); if (tmp != null) { row_count = tmp.length; for (int tmpRow = 0; tmpRow < row_count; tmpRow++) { List<FlameBlock> blocks = processCallTreeNodeIPC((Object[]) tmp[tmpRow]); flameRows.add(new FlameRow(getFlameData(), tmpRow, blocks)); totalBlockCount += blocks.size(); // YXXX sanity checking node counts } } } else { // get each level by querying list of nodes row_count = getCallTreeNumLevelsIPC(); int node_idxs[] = {0}; // 0 will fetch the root node for (int tmpRow = 0; tmpRow < row_count; tmpRow++) { List<FlameBlock> blocks = new ArrayList(); // get children of nodes in list Object[] res = getCallTreeChildrenIPC(metricName, tmpRow, node_idxs); // get results ArrayList<Integer> children = new ArrayList<Integer>(); // nodes for next query if (res != null) { for (int jj = 0; jj < res.length; jj++) { // should match node_idxs.length Object[] tmp = (Object[]) res[jj]; List<FlameBlock> nodeBlocks = processCallTreeNodeIPC(tmp); for (FlameBlock block : nodeBlocks) { children.add(block.getID()); blocks.add(block); // addall? // children of a given node_idxs[] } } } flameRows.add(new FlameRow(getFlameData(), tmpRow, blocks)); // build node list for next query int level_total = children.size(); if (level_total > 0) { totalBlockCount += level_total; // just for sanity checking node_idxs = new int[level_total]; for (int kk = 0; kk < level_total; kk++) { node_idxs[kk] = children.get(kk); } } else if (tmpRow != row_count - 1) { int ii = 0; // weird!; break; } } } // System.out.printf("getRowDataIPC rows=%d blocks=%d\n", row_count, totalBlockCount); return flameRows; } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/flame/FlameBlock.java����������������������������������������������0000644�0001750�0001750�00000031227�14517772113�017670� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.flame; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; public class FlameBlock { protected static final int UP = 0; protected static final int DOWN = 1; protected static final int LEFT = 2; protected static final int RIGHT = 3; protected static final int LAST_UP = 4; private int id; private int parentID; private long functionID; private double exclusiveValue; private double attributedValue; private PaintDetails paintDetails; // Only available (!= null) if block shuld be painted. class PaintDetails { private FlameRow flameRow; private boolean paintBlock; private int xPos; // relative to FlamePanel private int xWidth; private Color color; private String functionName; private FlameBlock[] next; private PaintDetails() { next = new FlameBlock[5]; } private FlameRow getFlameRow() { return flameRow; } private void setFlameRow(FlameRow flameRow) { this.flameRow = flameRow; } private int getXPos() { return xPos; } private void setXPos(int xPos) { this.xPos = xPos; } private int getXWidth() { return xWidth; } private void setXWidth(int xWidth) { this.xWidth = xWidth; } private Color getColor() { Color returnColor = null; if (flameRow.getFlameData().getBaseFlameBlock() == FlameBlock.this) { // Special case returnColor = AnEnvironment.FLAME_BLOCK_BASE_BACKGROUND; } if (color == null) { if (xWidth >= 1) { StackState state = flameRow.getFlameData().getFunctionIdNameMap().get(getFunctionID()); if (state != null) { long function = state.getNumber(); // Histable::Function* color = AnWindow.getInstance().getColorChooser().getColorMap().getFuncColor(function); } else { returnColor = Color.LIGHT_GRAY; // weird } } } if (returnColor == null) { returnColor = color; } if (flameRow.getFlameData().getSelectedFlameBlock() == FlameBlock.this && flameRow.getFlameData().getBaseFlameBlock() != FlameBlock.this) { returnColor = AnEnvironment.FLAME_BLOCK_SELECTED_BACKGROUND; } if (flameRow.getFlameData().getMouseOverFlameBlock() == FlameBlock.this) { returnColor = returnColor.brighter(); } return returnColor; } protected void resetColor() { color = null; } private String getFunctionName() { if (functionName == null) { StackState state = flameRow.getFlameData().getFunctionIdNameMap().get(getFunctionID()); if (state != null) { functionName = state.getName(); } if (functionName == null && flameRow.getRow() == 0) { // YLM: not sure if this still can happen, keeping it: // Special case functionName = "<Total>"; } if (functionName == null) { functionName = "" + getFunctionID(); } } return functionName; } private String getFunctionDisplayName() { String fn = getFunctionName(); String prefix = ""; // if (getFlameRow().getFlameData().getBaseFlameBlock() == FlameBlock.this) { // prefix = AnLocale.getString("Base: "); // } return prefix + fn; } private FlameBlock[] getNext() { return next; } private void setNextFlameBlock(int direction, FlameBlock flameBlock) { next[direction] = flameBlock; } private FlameBlock getNextFlameBlock(int direction) { return next[direction]; } private boolean paintBlock() { return paintBlock; } private void setPaintBlock(boolean paintBlock) { this.paintBlock = paintBlock; } } protected FlameBlock( int id, int parentID, long functionID, double exclusiveValue, double attributedValue) { this.id = id; this.parentID = parentID; this.functionID = functionID; this.exclusiveValue = exclusiveValue; this.attributedValue = attributedValue; } protected int getID() { return id; } protected int getParentID() { return parentID; } protected long getFunctionID() { return functionID; } protected double getInclusiveValue() { return exclusiveValue + attributedValue; } protected double getExclusiveValue() { return exclusiveValue; } protected double getAttributedValue() { return attributedValue; } protected String getInclusiveValueFormatted() { return getValueFormatted(getInclusiveValue()); } protected String getExclusiveValueFormatted() { return getValueFormatted(getExclusiveValue()); } protected String getAttributedValueFormatted() { return getValueFormatted(getAttributedValue()); } private String getValueFormatted(double value) { // FIXUP: This logic is not always correct. AnMetric anMetric = getFlameRow().getFlameData().getAnMetric(); if (anMetric.isTimeMetric()) { return String.format("%.3f", value); } else { // // YXXX Format with '@' to indicate half-spaces between digits // AnLong anLong = new AnLong((long) value); // return anLong.toFormString(); return "" + (long) value; } } protected Color getColor() { return paintDetails.getColor(); } protected void resetColor() { if (paintDetails != null) { paintDetails.resetColor(); } } protected void setXPosAndWidth(int xPos, int xWidth) { paintDetails.setXPos(xPos); paintDetails.setXWidth(xWidth); } protected int getXPos() { return paintDetails.getXPos(); } protected int getXWidth() { return paintDetails.getXWidth(); } protected boolean paintBlock() { return paintDetails != null && paintDetails.paintBlock(); } protected void setPaintBlock(boolean paintBlock) { paintDetails.setPaintBlock(paintBlock); } protected void resetPaintBlock() { paintDetails = new PaintDetails(); } protected String getFunctionName() { return paintDetails.getFunctionName(); } protected String getFunctionDisplayName() { return paintDetails.getFunctionDisplayName(); } protected FlameRow getFlameRow() { return paintDetails.getFlameRow(); } protected void setFlameRow(FlameRow flameRow) { paintDetails.setFlameRow(flameRow); } protected FlameBlock[] getNext() { return paintDetails.getNext(); } protected void setNextFlameBlock(int direction, FlameBlock flameBlock) { paintDetails.setNextFlameBlock(direction, flameBlock); } protected FlameBlock getNextFlameBlock(int direction) { if (paintDetails != null) { return paintDetails.getNextFlameBlock(direction); } else { return null; } } protected String getToolTipTextHTML() { String toolTipText = ""; if (getFlameRow() != null && getFlameRow().getFlameData() != null) { double totalValue = getFlameRow().getFlameData().getTotalValue(); StringBuilder buf = new StringBuilder(); buf.append("<html>"); buf.append("<font " + "face=\"monospaced\">"); buf.append("<b>"); buf.append("<nobr>"); buf.append(AnUtility.escapeSpecialHTMLCharacters(getFunctionName())); buf.append("</b>"); String inclExclText; if (getNextFlameBlock(UP) == null) { inclExclText = AnLocale.getString("Exclusive"); } else { inclExclText = AnLocale.getString("Inclusive"); } buf.append("<br>"); buf.append("<nobr>"); buf.append( formatValueHTML( inclExclText, totalValue, getInclusiveValue(), getInclusiveValueFormatted())); if (getExclusiveValue() > 0) { buf.append("<br>"); buf.append("<nobr>"); buf.append( formatValueHTML( AnLocale.getString("Exclusive"), totalValue, getExclusiveValue(), getExclusiveValueFormatted())); buf.append("<br>"); buf.append("<nobr>"); buf.append( formatValueHTML( AnLocale.getString("Calls"), totalValue, getAttributedValue(), getAttributedValueFormatted())); } else { buf.append("<br>"); buf.append("< "); buf.append("<br>"); buf.append("< "); } buf.append("</html>"); toolTipText = buf.toString(); } return toolTipText; } private String formatValueHTML( String what, double totalValue, double value, String formattedValue) { String percentText = ""; if (totalValue != 0) { double percent = value / totalValue * 100; percentText = String.format("%.2f", percent); } String text = String.format( "%-9s: %7s%% %10s %s", what, percentText, formattedValue, getFlameRow().getFlameData().getAnMetric().getUnit()); text = text.replaceAll(" ", " "); return text; } protected String getDetailsTextHTML() { return getToolTipTextHTML(); } protected static String getDetailsEmptyTextHTML() { String text; StringBuilder buf = new StringBuilder(); buf.append("<html>"); buf.append("< "); buf.append("<br>"); buf.append("< "); buf.append("<br>"); buf.append("< "); buf.append("<br>"); buf.append("< "); buf.append("<br>"); buf.append("</html>"); text = buf.toString(); return text; } protected String getValueText() { String text = ""; if (getFlameRow() != null && getFlameRow().getFlameData() != null) { double totalValue = getFlameRow().getFlameData().getTotalValue(); StringBuilder buf = new StringBuilder(); String percentText = null; if (totalValue != 0) { double percent = getInclusiveValue() / totalValue * 100; percentText = String.format("%.2f", percent); } if (percentText != null) { buf.append(percentText); buf.append("%"); } buf.append(" "); buf.append(getInclusiveValueFormatted()); buf.append(getFlameRow().getFlameData().getAnMetric().getUnit()); text = buf.toString(); } return text; } protected void initNext() { setNextFlameBlock(FlameBlock.UP, null); setNextFlameBlock(FlameBlock.DOWN, null); setNextFlameBlock(FlameBlock.LEFT, null); setNextFlameBlock(FlameBlock.RIGHT, null); } protected String dump() { StringBuilder buf = new StringBuilder(); buf.append("-------------------"); buf.append("id=" + id); buf.append("\n"); buf.append("parentID=" + parentID); buf.append("\n"); buf.append("functionID=" + functionID); buf.append("\n"); // buf.append("function name=" + // AnWindow.getInstance().getFlameView().getFlameData().getFunctionIdNameMap().get(functionID).getName()); StackState state = AnWindow.getInstance() .getFlameView() .getFlameData() .getFunctionIdNameMap() .get(getFunctionID()); final String name; if (state != null) { name = state.getName(); } else { name = null; } buf.append("function name=" + name); buf.append("\n"); buf.append("unformatted metric value=" + String.format("%.3f", exclusiveValue)); buf.append("\n"); buf.append("block width=" + (paintDetails != null ? paintDetails.getXWidth() : "")); buf.append("\n"); buf.append( "block next=" + " " + dumpNext(UP) + " " + dumpNext(DOWN) + " " + dumpNext(LEFT) + " " + dumpNext(RIGHT)); buf.append("\n"); return buf.toString(); } private String dumpNext(int direction) { FlameBlock fb = getNextFlameBlock(direction); if (fb != null) { return "" + fb.getID(); } else { return "-"; } } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/flame/FlameToolBar.java��������������������������������������������0000644�0001750�0001750�00000024062�14517772113�020177� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.flame; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.settings.MetricsSetting.MetricCheckBox; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Stack; import javax.swing.BorderFactory; import javax.swing.Box; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JLabel; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import javax.swing.JSpinner; import javax.swing.JToolBar; import javax.swing.SpinnerNumberModel; import javax.swing.SwingUtilities; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.PopupMenuEvent; import javax.swing.event.PopupMenuListener; public class FlameToolBar extends JToolBar { private FlameView flameView; private AnMetric[] availableMetrics; private JComboBox metricComboBox; private JSpinner zoomSpinner; private int defaultZoomLevel; private JPopupMenu metricsSelectorpopup = null; private Stack<FlameBlock> setBaseStack = new Stack<FlameBlock>(); private int setBaseStackpointer = -1; private int comboboxSelectedIndex = -1; protected FlameToolBar(final FlameView flameView) { this.flameView = flameView; setOpaque(false); setBorder(null); defaultZoomLevel = getFont().getSize(); zoomSpinner = new JSpinner(new SpinnerNumberModel(0, -defaultZoomLevel - 3, 99, 1)); zoomSpinner.setBorder(BorderFactory.createLineBorder(new Color(122, 138, 153), 1)); JLabel zoomSpinnerlabel = new JLabel(AnLocale.getString("Zoom:")); zoomSpinnerlabel.setToolTipText(AnLocale.getString("Vertical zoom")); zoomSpinnerlabel.setDisplayedMnemonic(AnLocale.getString('Z', "FlameToolBar_ZoomLabel")); zoomSpinnerlabel.setLabelFor(zoomSpinner); zoomSpinner.addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { int zoomLevel = (int) zoomSpinner.getValue(); flameView.getFlamePanel().setZoomLevel(zoomLevel); } }); add(zoomSpinnerlabel); add(zoomSpinner); add(getFiller(6)); add(new JSeparator(JSeparator.VERTICAL)); add(getFiller(4)); add(flameView.getUndoSetBaseAction().createActionButton()); add(flameView.getRedoSetBaseAction().createActionButton()); add(flameView.getResetBaseAction().createActionButton()); add(flameView.getSetBaseAction().createActionButton()); add(getFiller(4)); add(new JSeparator(JSeparator.VERTICAL)); add(getFiller(4)); add(flameView.getUpOneAction().createActionButton()); add(flameView.getDownOneAction().createActionButton()); add(flameView.getLeftOneAction().createActionButton()); add(flameView.getRightOneAction().createActionButton()); add(getFiller(4)); add(new JSeparator(JSeparator.VERTICAL)); add(getFiller(4)); add(AnWindow.getInstance().getFunctionColorsAction().createActionButton()); add(getFiller(4)); add(new JSeparator(JSeparator.VERTICAL)); add(getFiller(8)); JLabel metricLabel = new JLabel(AnLocale.getString("Metric: ")); metricLabel.setToolTipText(AnLocale.getString("Selected metric")); metricLabel.setDisplayedMnemonic(AnLocale.getString('e', "FlameViewMetricLabel")); add(metricLabel); metricComboBox = new JComboBox(); metricLabel.setLabelFor(metricComboBox); metricComboBox.setToolTipText(AnLocale.getString("Selected metric")); metricComboBox.addPopupMenuListener( new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { comboboxSelectedIndex = metricComboBox.getSelectedIndex(); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (metricComboBox.getSelectedItem() instanceof AnMetric) { flameView.setMetric((AnMetric) metricComboBox.getSelectedItem()); } else { if (comboboxSelectedIndex >= 0 && comboboxSelectedIndex < metricComboBox.getItemCount()) { metricComboBox.setSelectedIndex(comboboxSelectedIndex); } SwingUtilities.invokeLater( new Runnable() { @Override public void run() { showMetricsConfigurationPopup( metricComboBox, 0, metricComboBox.getHeight(), AnDisplay.DSP_CallFlame); } }); } } @Override public void popupMenuCanceled(PopupMenuEvent e) {} }); add(metricComboBox); setMinimumSize(new Dimension(10, 10)); getAccessibleContext().setAccessibleName(AnLocale.getString("Flame Chart Toolbar")); getAccessibleContext().setAccessibleDescription(AnLocale.getString("Flame Chart Toolbar")); } public void showMetricsConfigurationPopup(Component component, int x, int y, int dtype) { metricsSelectorpopup = getmetricsSelectorPopup(dtype); metricsSelectorpopup.show(component, x, y); } private JPopupMenu getmetricsSelectorPopup(int dtype) { JPopupMenu popup = new JPopupMenu(); AnWindow.getInstance() .getSettings() .getMetricsSetting() .addMetricsPopupSelector(popup, dtype, false); // Customize: Slecting an already enabled metric will just use that metric (and not unselect // it). for (Component component : popup.getComponents()) { if (component instanceof MetricCheckBox) { final MetricCheckBox metricCheckBox = (MetricCheckBox) component; if (metricCheckBox.isSelected()) { // component.setEnabled(false); ActionListener[] als = metricCheckBox.getActionListeners(); for (ActionListener al : als) { metricCheckBox.removeActionListener(al); } metricCheckBox.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { flameView.setMetric(metricCheckBox.getAnMetric()); } }); } } } return popup; } protected void resetZoom() { zoomSpinner.setValue(0); } protected void resetMetrics(AnMetric anMetric) { metricComboBox.removeAllItems(); availableMetrics = AnWindow.getInstance() .getSettings() .getMetricsSetting() .getMetricListByMType(MetricsSetting.MET_CALL_AGR); if (availableMetrics != null) { int selectedIndex = -1; int index = 0; for (AnMetric am : availableMetrics) { if (am.isNameMetric() || am.isStatic()) { continue; } metricComboBox.addItem(am); if (anMetric.getUserName().equals(am.getUserName())) { selectedIndex = index; } index++; } if (selectedIndex >= 0) { metricComboBox.setSelectedIndex(selectedIndex); } else { metricComboBox.addItem(null); metricComboBox.setSelectedIndex(metricComboBox.getItemCount() - 1); } metricComboBox.addItem(AnLocale.getString("More Metrics...")); } } private JComponent getFiller(int x) { Dimension dim = new Dimension(x, 0); Box.Filler filler = new Box.Filler(dim, dim, dim); return filler; } protected void initSetBaseStack() { setBaseStack = new Stack<FlameBlock>(); setBaseStackpointer = -1; } protected void pushToSetBaseStack(FlameBlock fb) { while (setBaseStack.size() > 0 && (setBaseStack.size() - 1) > setBaseStackpointer) { setBaseStack.pop(); } if (setBaseStack.empty() || setBaseStack.peek() != fb) { setBaseStack.push(fb); setBaseStackpointer = setBaseStack.size() - 1; } } protected void undoSetBaseStack() { if (canUndoSetBaseStack()) { FlameBlock selectedFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); setBaseStackpointer--; FlameBlock flameBlock = setBaseStack.get(setBaseStackpointer); flameView.getFlamePanel().setBaseFlameBlock(flameBlock, false); flameView.getFlameData().setSelectedFlameBlock(selectedFlameBlock); } flameView.updateActionsEnableStatus(); } protected void redoSetBaseStack() { if (canRedoSetBaseStack()) { FlameBlock selectedFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); setBaseStackpointer++; FlameBlock flameBlock = setBaseStack.get(setBaseStackpointer); flameView.getFlamePanel().setBaseFlameBlock(flameBlock, false); flameView.getFlameData().setSelectedFlameBlock(selectedFlameBlock); } flameView.updateActionsEnableStatus(); } protected boolean canUndoSetBaseStack() { return setBaseStackpointer > 0; } protected boolean canRedoSetBaseStack() { return setBaseStackpointer < setBaseStack.size() - 1; } protected boolean canZoom() { FlameData flameData = flameView.getFlameData(); return !(flameData.getFlameRows().length == 0 || flameData.getFlameRows()[0] == null || flameData.getFlameRows()[0].getFlameBlocks().isEmpty()); } protected void setControilsEnabled(boolean enabled) { if (enabled) { zoomSpinner.setEnabled(canZoom()); } else { zoomSpinner.setEnabled(false); } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/flame/FlamePanel.java����������������������������������������������0000644�0001750�0001750�00000055746�14517772113�017711� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.flame; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.AnDisplay; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.filter.Filters; import org.gprofng.mpmt.settings.MetricsSetting; import org.gprofng.mpmt.util.gui.AnGradientPanel; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.GridBagConstraints; import java.awt.GridBagLayout; import java.awt.Insets; import java.awt.MouseInfo; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; import java.awt.event.MouseMotionListener; import java.util.ArrayList; import java.util.List; import javax.swing.JComponent; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.JSeparator; import javax.swing.SwingUtilities; public class FlamePanel extends JPanel implements MouseListener, MouseMotionListener { private enum State { CLEAR, RESET, ROWS }; private FlameView flameView; private State state; private final Object stateLock = new Object(); private int lastWidth = 0; private DataPanel dataPanel; private int rowHeight; private Font font; private int defaultFontSize; private static final int outerGap = 2; private static final int innerGap = 2; protected FlamePanel(FlameView flameView) { this.flameView = flameView; setOpaque(true); setBackground(AnEnvironment.SPLIT_PANE_DIVIDER_BACKGROUND_COLOR); font = getFont().deriveFont((float) (getFont().getSize() - 0)); defaultFontSize = font.getSize(); rowHeight = font.getSize() + 4; state = State.CLEAR; setLayout(new GridBagLayout()); dataPanel = new DataPanel(); GridBagConstraints gridBagConstraints = new GridBagConstraints(); gridBagConstraints.insets = new Insets(outerGap, outerGap, outerGap, outerGap); gridBagConstraints.fill = GridBagConstraints.BOTH; gridBagConstraints.weightx = 1.0; gridBagConstraints.weighty = 1.0; add(dataPanel, gridBagConstraints); dataPanel.addMouseListener(this); dataPanel.addMouseMotionListener(this); } @Override public void mouseClicked(MouseEvent e) { if (flameView.getFlameData() != null) { FlameBlock mouseOverFlameBlock = flameView.getFlameData().getMouseOverFlameBlock(); if (mouseOverFlameBlock != null) { if (SwingUtilities.isLeftMouseButton(e)) { setSelectedFlameBlock(mouseOverFlameBlock); if (e.getClickCount() >= 2) { // System.out.println("left mouse clicked " + e.getClickCount() + " " // + mouseOverFlameBlock.getFunctionName()); setBaseFlameBlock(mouseOverFlameBlock, true); } } } } } @Override public void mouseReleased(MouseEvent e) {} @Override public void mousePressed(MouseEvent e) { if (flameView.getFlameData() == null) { return; } final FlameBlock mouseOverFlameBlock = flameView.getFlameData().getMouseOverFlameBlock(); if (SwingUtilities.isRightMouseButton(e)) { if (mouseOverFlameBlock != null) { setSelectedFlameBlock(mouseOverFlameBlock); } if (e.isPopupTrigger()) { JPopupMenu popup = new JPopupMenu("Popup"); FlameBlock selectedFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); for (JComponent jmi : getMenuList(selectedFlameBlock)) { popup.add(jmi); } popup.show(dataPanel, e.getX(), e.getY()); } } } protected void showPopup(FlameBlock selectedFlameBlock) { // int row = flameBlock.getFlameRow().getRow(); // int x = flameBlock.getXPos(); // int y = dataPanel.getHeight() - (rowHeight * row); Point mousePoint = MouseInfo.getPointerInfo().getLocation(); // screen position Point panelPoint = dataPanel.getLocationOnScreen(); int x = mousePoint.x - panelPoint.x; int y = mousePoint.y - panelPoint.y; JPopupMenu popup = new JPopupMenu("Popup"); for (JComponent jmi : getMenuList(selectedFlameBlock)) { popup.add(jmi); } popup.show(dataPanel, x, y); } private List<JComponent> getMenuList(final FlameBlock selectedFlameBlock) { List<JComponent> list = new ArrayList<JComponent>(); JMenuItem showSource = new JMenuItem(AnLocale.getString("Show Source")); showSource.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().setSelectedView(AnDisplay.DSP_Source); } }); list.add(showSource); JMenuItem showDis = new JMenuItem(AnLocale.getString("Show Disassembly")); showDis.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { AnWindow.getInstance().setSelectedView(AnDisplay.DSP_Disassembly); } }); list.add(showDis); list.add(new JSeparator()); for (JComponent jmi : flameView.getFilterMenuList(selectedFlameBlock)) { list.add(jmi); } list.add(new JSeparator()); JMenu setMetricMenu = new JMenu(AnLocale.getString("Set Metric")); AnMetric[] availableMetrics = AnWindow.getInstance() .getSettings() .getMetricsSetting() .getMetricListByMType(MetricsSetting.MET_CALL_AGR); if (availableMetrics != null) { for (AnMetric am : availableMetrics) { if (am.isNameMetric() || am.isStatic()) { continue; } final AnMetric am2 = am; JMenuItem metricMenuItem = new JMenuItem(am2.getUserName()); metricMenuItem.addActionListener( new ActionListener() { @Override public void actionPerformed(ActionEvent e) { flameView.setMetric(am2); } }); setMetricMenu.add(metricMenuItem); } // More metrics JMenu moreMetricMenu = new JMenu(AnLocale.getString("More Metrics")); AnWindow.getInstance() .getSettings() .getMetricsSetting() .addMetricMenuSelector(moreMetricMenu, AnDisplay.DSP_CallFlame, false); // Customize: diasble already enabled metrics (?) for (Component component : moreMetricMenu.getMenuComponents()) { if (component instanceof MetricsSetting.MetricCheckBox) { if (((MetricsSetting.MetricCheckBox) component).isSelected()) { component.setEnabled(false); } } } setMetricMenu.add(moreMetricMenu); } list.add(setMetricMenu); list.add(new JSeparator()); list.add(flameView.getUndoSetBaseAction().getMenuItem(false)); list.add(flameView.getRedoSetBaseAction().getMenuItem(false)); list.add(flameView.getSetBaseAction().getMenuItem(false)); list.add(flameView.getResetBaseAction().getMenuItem(false)); list.add(new JSeparator()); list.add(flameView.getUpOneAction().getMenuItem(false)); list.add(flameView.getDownOneAction().getMenuItem(false)); list.add(flameView.getLeftOneAction().getMenuItem(false)); list.add(flameView.getRightOneAction().getMenuItem(false)); if (selectedFlameBlock == null) { showSource.setEnabled(false); showDis.setEnabled(false); } return list; } protected void setAsBase() { FlameBlock newBaseFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); if (newBaseFlameBlock != null) { setBaseFlameBlock(newBaseFlameBlock, true); flameView.scrollToRow(newBaseFlameBlock.getFlameRow().getRow()); } flameView.updateActionsEnableStatus(); } protected boolean canSetBase() { return flameView != null && flameView.getFlameData() != null && flameView.getFlameData().getSelectedFlameBlock() != flameView.getFlameData().getBaseFlameBlock(); } protected void resetBase() { FlameBlock selectedFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); FlameBlock newBaseFlameBlock = flameView.getFlameData().getTotalFlameBlock(); if (newBaseFlameBlock != null) { setBaseFlameBlock(newBaseFlameBlock, true); flameView.scrollToRow(newBaseFlameBlock.getFlameRow().getRow()); } flameView.getFlameData().setSelectedFlameBlock(selectedFlameBlock); flameView.updateActionsEnableStatus(); } protected boolean canResetBase() { return flameView != null && flameView.getFlameData() != null && flameView.getFlameData().getBaseFlameBlock() != flameView.getFlameData().getTotalFlameBlock(); } protected void upOne() { FlameBlock selectedFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); FlameBlock newSelectedFlameBlock = selectedFlameBlock.getNextFlameBlock(FlameBlock.LAST_UP); if (newSelectedFlameBlock == null) { newSelectedFlameBlock = selectedFlameBlock.getNextFlameBlock(FlameBlock.UP); } if (newSelectedFlameBlock != null) { setSelectedFlameBlock(newSelectedFlameBlock); flameView.scrollToRow(newSelectedFlameBlock.getFlameRow().getRow()); } flameView.updateActionsEnableStatus(); } protected boolean canUpOne() { return flameView != null && flameView.getFlameData() != null && flameView.getFlameData().getSelectedFlameBlock() != null && flameView.getFlameData().getSelectedFlameBlock().getNextFlameBlock(FlameBlock.UP) != null; } protected void downOne() { FlameBlock selectedFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); FlameBlock newSelectedFlameBlock = selectedFlameBlock.getNextFlameBlock(FlameBlock.DOWN); if (newSelectedFlameBlock != null) { newSelectedFlameBlock.getNext()[FlameBlock.LAST_UP] = selectedFlameBlock; setSelectedFlameBlock(newSelectedFlameBlock); flameView.scrollToRow(newSelectedFlameBlock.getFlameRow().getRow()); } flameView.updateActionsEnableStatus(); } protected boolean canDownOne() { return flameView != null && flameView.getFlameData() != null && flameView.getFlameData().getSelectedFlameBlock() != null && flameView.getFlameData().getSelectedFlameBlock().getNextFlameBlock(FlameBlock.DOWN) != null; } protected void leftOne() { FlameBlock selectedFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); FlameBlock newSelectedFlameBlock = selectedFlameBlock.getNextFlameBlock(FlameBlock.LEFT); if (newSelectedFlameBlock != null) { setSelectedFlameBlock(newSelectedFlameBlock); } flameView.updateActionsEnableStatus(); } protected boolean canLeftOne() { return flameView != null && flameView.getFlameData() != null && flameView.getFlameData().getSelectedFlameBlock() != null && flameView.getFlameData().getSelectedFlameBlock().getNextFlameBlock(FlameBlock.LEFT) != null; } protected void rightOne() { FlameBlock selectedFlameBlock = flameView.getFlameData().getSelectedFlameBlock(); FlameBlock newSelectedFlameBlock = selectedFlameBlock.getNextFlameBlock(FlameBlock.RIGHT); if (newSelectedFlameBlock != null) { setSelectedFlameBlock(newSelectedFlameBlock); } flameView.updateActionsEnableStatus(); } protected boolean canRightOne() { return flameView != null && flameView.getFlameData() != null && flameView.getFlameData().getSelectedFlameBlock() != null && flameView.getFlameData().getSelectedFlameBlock().getNextFlameBlock(FlameBlock.RIGHT) != null; } protected void setBaseFlameBlock(FlameBlock baseFlameBlock, boolean pushToSetBaseStack) { // System.out.println("FlamePanel setBaseFlameBlock " + pushToSetBaseStack); if (pushToSetBaseStack) { flameView.getFlameToolBar().pushToSetBaseStack(baseFlameBlock); } flameView.getFlameData().setBaseFlameBlock(baseFlameBlock); flameView.getFlameData().recalculateFlameBlockWidths(dataPanel.getWidth() - 2 * innerGap); dataPanel.repaint(500); flameView.updateActionsEnableStatus(); flameView.requestFocus(); // so key events keep working! (???). } protected void setSelectedFlameBlock(FlameBlock selectedFlameBlock) { if (flameView.getFlameData().setSelectedFlameBlock(selectedFlameBlock)) { dataPanel.repaint(500); } flameView.updateActionsEnableStatus(); flameView.requestFocus(); // so key events keep working! (???). } @Override public void mouseExited(MouseEvent e) {} @Override public void mouseEntered(MouseEvent e) {} @Override public void mouseDragged(MouseEvent e) {} @Override public void mouseMoved(MouseEvent e) { if (flameView.getFlameData() == null) { return; } int panelHeight = dataPanel.getHeight(); int row = (panelHeight - innerGap - e.getY()) / rowHeight; FlameBlock flameBlock = flameView.getFlameData().findFlameBlock(row, e.getX() - innerGap); // System.out.println(e.getX() + " " + e.getY() + " " + row); if (flameView.getFlameData().setMouseOverFlameBlock(flameBlock)) { String toolTipText = null; if (flameBlock != null) { toolTipText = flameBlock.getToolTipTextHTML(); } dataPanel.setToolTipText(toolTipText); dataPanel.repaint(500); } } /** Called when new experiment loaded */ protected void initView() { synchronized (stateLock) { state = State.CLEAR; dataPanel.repaint(500); } } /** Called just before everything is recomputed (doCompute) */ protected void resetView() { synchronized (stateLock) { state = State.RESET; dataPanel.repaint(500); } } /** Called when function colors have changed */ protected void functionColorsChanged() { synchronized (stateLock) { if (flameView.getFlameData() != null) { flameView.getFlameData().resetBlockColors(); if (flameView.isSelected()) { dataPanel.repaint(500); } } } } /** Called when a row is complete */ protected void rowIsComplete(int newRow) { // System.out.println("rowIsComplete " + newRow); if (flameView.getFlameData().allRowsDone()) { flameView.getFlameData().calculateFlameBlockWidths(dataPanel.getSize().width); synchronized (stateLock) { state = State.ROWS; dataPanel.repaint(500); } } } protected int getRowHeight() { return rowHeight; } protected void setZoomLevel(int zoomLevel) { int newRowHeight = defaultFontSize + zoomLevel + 4; if (newRowHeight != this.rowHeight) { this.rowHeight = newRowHeight; font = getFont().deriveFont((float) (defaultFontSize + zoomLevel)); setPanelSize(flameView.getFlameData().getFlameRows().length); flameView.scrollToRow(0); repaint(); } } protected void setPanelSize(int rowCount) { int newHeight = rowCount * rowHeight + 2 * outerGap; // System.out.println("setPanelSize " + newHeight); setMinimumSize(new Dimension(10, newHeight)); setPreferredSize(new Dimension(10, newHeight)); revalidate(); } class DataPanel extends AnGradientPanel { private DataPanel() { super(AnEnvironment.FLAME_TOP_COLOR, AnEnvironment.FLAME_BOTTOM_COLOR); } @Override public void paint(Graphics g) { // System.out.println("paint() " + getSize()); super.paint(g); // Paints background synchronized (stateLock) { switch (state) { case CLEAR: paintClear(g); break; case RESET: paintClear(g); paintReset(g); break; case ROWS: paintClear(g); int width = getSize().width; FlameData flameData = flameView.getFlameData(); if (width != lastWidth) { flameData.recalculateFlameBlockWidths(width - 2 * innerGap); } lastWidth = width; // Date start = new Date(); paintRows(g, flameData); // System.out.println("paint() " + (new Date().getTime() - // start.getTime())); break; } } } private void paintClear(Graphics g) { // Nothing } private void paintReset(Graphics g) { int width = getSize().width; Rectangle ret = getVisibleRect(); g.setColor(AnEnvironment.FLAME_INFO_TEXT_COLOR); Font font = getFont().deriveFont((float) (getFont().getSize() + (float) 3)); g.setFont(font); String msg = AnLocale.getString("Fetching data..."); int msgWidth = g.getFontMetrics().stringWidth(msg); g.drawString(msg, width / 2 - msgWidth / 2, ret.y + ret.height / 2 + 10); flameView.updateSelection(); } private void paintNoData(Graphics g) { setPanelSize(1); int width = getSize().width; Rectangle ret = getVisibleRect(); g.setColor(AnEnvironment.FLAME_INFO_TEXT_COLOR); Font font = getFont().deriveFont((float) (getFont().getSize() + (float) 3)); g.setFont(font); String msg = String.format( AnLocale.getString("Data not available for this metric (%s)"), flameView.getFlameData().getAnMetric()); if (Filters.getInstance().anyFilters()) { msg += AnLocale.getString(" and filter selection"); } int msgWidth = g.getFontMetrics().stringWidth(msg); g.drawString(msg, width / 2 - msgWidth / 2, ret.y + ret.height / 2 + 10); flameView.updateSelection(); } private void paintRows(Graphics g, FlameData flameData) { if (flameData == null) { paintNoData(g); return; } if (flameData.getFlameRows().length == 0 || flameData.getFlameRows()[0] == null || flameData.getFlameRows()[0].getFlameBlocks().isEmpty()) { paintNoData(g); return; } FlameRow[] flameRows = flameData.getFlameRows(); if (flameRows != null) { int width = getSize().width; int height = getSize().height; Rectangle visibleRectangle = getVisibleRect(); g.setFont(font); for (int row = 0; row < flameRows.length; row++) { FlameRow flameRow = flameRows[row]; g.setClip(visibleRectangle); int blockTextYPos = height - (rowHeight * row) - 4 - innerGap; if (flameRow != null && flameRow.isReadyToPaint()) { int blockYPos = height - (rowHeight * row) - rowHeight - innerGap; FlameBlock flameBlock = flameRow.getFirstPaintedFlameBlock(); while (flameBlock != null) { if (flameBlock.paintBlock()) { int blockWidth = flameBlock.getXWidth(); int blockXPos = flameBlock.getXPos() + innerGap; if (blockWidth >= 2) { g.setColor(flameBlock.getColor()); g.fillRect(blockXPos, blockYPos, blockWidth, rowHeight); } g.setColor(AnEnvironment.FLAME_BLOCK_BORDER_COLOR); g.drawRect(blockXPos, blockYPos, blockWidth, rowHeight); if (blockWidth > 6) { Font font = g.getFont(); Font boldFont = font.deriveFont(Font.BOLD); g.setColor(Color.BLACK); if (flameBlock == flameData.getBaseFlameBlock()) { g.setFont(boldFont); } g.setClip(blockXPos, visibleRectangle.y, blockWidth, visibleRectangle.height); g.drawString(flameBlock.getFunctionDisplayName(), blockXPos + 2, blockTextYPos); if (flameBlock == flameData.getBaseFlameBlock()) { String valueText = flameBlock.getValueText(); g.setFont(boldFont); int valueWidth = g.getFontMetrics().stringWidth(valueText); g.setColor(flameBlock.getColor()); g.fillRect( blockXPos + blockWidth - valueWidth - 20, blockYPos, blockWidth, rowHeight); g.setColor(Color.BLACK); g.drawString(valueText, blockWidth - valueWidth, blockTextYPos + 0); g.setFont(font); } g.setFont(font); g.setClip(visibleRectangle); } } flameBlock = flameBlock.getNextFlameBlock(FlameBlock.RIGHT); } } else if (flameRow != null) { g.setColor(Color.GREEN.darker().darker()); g.drawString( String.format("%2s", row) + ": " + AnLocale.getString("Ready..."), width / 2 - 12, blockTextYPos); } else { g.setColor(AnEnvironment.FLAME_INFO_TEXT_COLOR); g.drawString( String.format("%2s", row) + ": " + AnLocale.getString("Fetching data..."), width / 2 - 12, blockTextYPos); } } FlameBlock selectedFlameBlock = flameData.getSelectedFlameBlock(); FlameBlock mouseOverFlameBlock = flameData.getMouseOverFlameBlock(); if (selectedFlameBlock != null) { drawXFlameBlock( g, selectedFlameBlock, AnEnvironment.FLAME_BLOCK_SELECTED_BORDER1, AnEnvironment.FLAME_BLOCK_SELECTED_BORDER2); } if (mouseOverFlameBlock != null) { drawXFlameBlock( g, mouseOverFlameBlock, AnEnvironment.FLAME_BLOCK_MOUSEOVER_BORDER1, null); } } } private void drawXFlameBlock(Graphics g, FlameBlock flameBlock, Color color1, Color color2) { if (flameBlock.paintBlock()) { int height = getSize().height; int blockWidth = flameBlock.getXWidth(); int blockXPos = flameBlock.getXPos() + innerGap; int blockYPos = height - (rowHeight * flameBlock.getFlameRow().getRow()) - rowHeight - innerGap; if (color1 != null) { g.setColor(color1); g.drawRect(blockXPos, blockYPos, blockWidth, rowHeight); g.drawRect(blockXPos - 1, blockYPos - 1, blockWidth + 2, rowHeight + 2); } if (color2 != null) { g.setColor(color2); g.drawRect(blockXPos + 1, blockYPos + 1, blockWidth - 2, rowHeight - 2); } } } } protected static int getOuterGap() { return outerGap; } protected static int getInnerGap() { return innerGap; } } ��������������������������gprofng-gui-1.0/org/gprofng/mpmt/flame/FlameRow.java������������������������������������������������0000644�0001750�0001750�00000005171�14517772113�017404� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.flame; import java.util.HashMap; import java.util.List; import java.util.Map; public class FlameRow { private FlameData flameData; private int row; private List<FlameBlock> flameBlocks; private boolean readyToPaint; private FlameBlock firstPaintedFlameBlock; private Map<Integer, FlameBlock> idToBlockMap; protected FlameRow(FlameData flameData, int row, List<FlameBlock> flameBlocks) { this.flameData = flameData; this.row = row; this.flameBlocks = flameBlocks; readyToPaint = false; idToBlockMap = new HashMap<Integer, FlameBlock>(); if (flameBlocks != null) { for (FlameBlock flameBlock : flameBlocks) { idToBlockMap.put(flameBlock.getID(), flameBlock); } } } protected FlameBlock findFlameBlock(int id) { FlameBlock block = idToBlockMap.get(id); return block; } protected int getRow() { return row; } protected List<FlameBlock> getFlameBlocks() { return flameBlocks; } protected FlameData getFlameData() { return flameData; } protected boolean isReadyToPaint() { return readyToPaint; } protected void setReadyToPaint() { readyToPaint = true; } protected void resetReadyToPaint() { readyToPaint = false; } protected void resetBlockColors() { for (FlameBlock flameBlock : flameBlocks) { flameBlock.resetColor(); } } protected FlameBlock getFirstPaintedFlameBlock() { return firstPaintedFlameBlock; } protected void setFirstPaintedFlameBlock(FlameBlock firstPaintedFlameBlock) { this.firstPaintedFlameBlock = firstPaintedFlameBlock; } protected String dump() { StringBuilder buf = new StringBuilder(); buf.append("======================================== "); buf.append("row=" + row); buf.append(" "); buf.append("blocks=" + flameBlocks.size()); buf.append("\n"); for (FlameBlock flameBlock : flameBlocks) { buf.append(flameBlock.dump()); } return buf.toString(); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/flame/FlameData.java�����������������������������������������������0000644�0001750�0001750�00000036774�14517772113�017523� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt.flame; import org.gprofng.mpmt.AnMetric; import org.gprofng.mpmt.AnWindow; import org.gprofng.mpmt.statecolors.StackState; import org.gprofng.mpmt.util.gui.AnUtility; import java.util.Date; import java.util.List; import java.util.Map; public class FlameData { private FlameView flameView; private AnMetric anMetric = null; private FlameRow[] flameRows = null; private Map<Long, StackState> functionIdNameMap = null; private FlameBlock baseFlameBlock = null; private FlameBlock mouseOverFlameBlock = null; private FlameBlock selectedFlameBlock = null; private static Object selectedObjectLock = new Object(); private static UpdateSelectedObjectThread selectedObjectThread; protected FlameData(FlameView flameView, AnMetric anMetric, int rowCount) { this.flameView = flameView; this.anMetric = anMetric; flameRows = new FlameRow[rowCount]; } protected void rowDone(FlameRow flameRow) { flameRows[flameRow.getRow()] = flameRow; if (flameRow.getRow() == 0) { if (!flameRow.getFlameBlocks().isEmpty() && !flameRows[0].getFlameBlocks().isEmpty()) { baseFlameBlock = getTotalFlameBlock(); baseFlameBlock.resetPaintBlock(); baseFlameBlock.setPaintBlock(true); baseFlameBlock.setFlameRow(flameRow); flameRow.setFirstPaintedFlameBlock(baseFlameBlock); setBaseFlameBlock(baseFlameBlock); flameView.getFlameToolBar().initSetBaseStack(); flameView.getFlameToolBar().pushToSetBaseStack(baseFlameBlock); } } } protected FlameBlock getTotalFlameBlock() { if (flameRows[0].getFlameBlocks().isEmpty()) { return null; } else { return flameRows[0].getFlameBlocks().get(0); // Only one block here!!!!!! } } protected FlameRow[] getFlameRows() { return flameRows; } protected boolean allRowsDone() { boolean allDone = false; if (flameRows != null) { allDone = true; for (FlameRow flameRow : flameRows) { if (flameRow == null) { allDone = false; break; } } } return allDone; } protected void resetReadyToPaint() { for (FlameRow flameRow : flameRows) { if (flameRow != null) { flameRow.resetReadyToPaint(); } } } protected void resetBlockColors() { for (FlameRow flameRow : flameRows) { if (flameRow != null) { flameRow.resetBlockColors(); } } } protected void recalculateFlameBlockWidths(int width) { resetReadyToPaint(); calculateFlameBlockWidths(width); } protected void calculateFlameBlockWidths(int width) { Date start = new Date(); FlameRow[] flameRows = getFlameRows(); FlameBlock baseFlameBlock = getBaseFlameBlock(); for (int row = 0; row < flameRows.length; row++) { if (flameRows[row] == null) { break; } if (flameRows[row].isReadyToPaint()) { continue; } FlameRow flameRow = flameRows[row]; if (flameRow == null) { break; } List<FlameBlock> flameBlocks = flameRow.getFlameBlocks(); if (flameBlocks.isEmpty()) { break; } if (row <= baseFlameBlock.getFlameRow().getRow()) { flameRow.setFirstPaintedFlameBlock(null); for (FlameBlock fb : flameRow.getFlameBlocks()) { if (fb == baseFlameBlock) { fb.setPaintBlock(true); fb.setXPosAndWidth(0, width - 1); fb.setFlameRow(flameRow); flameRow.setFirstPaintedFlameBlock(fb); fb.initNext(); int r = row; while (r > 0) { FlameRow fr = flameRows[r - 1]; FlameBlock pfb = fr.findFlameBlock(fb.getParentID()); pfb.setPaintBlock(true); pfb.setXPosAndWidth(0, width - 1); pfb.setFlameRow(fr); fr.setFirstPaintedFlameBlock(pfb); pfb.initNext(); pfb.setNextFlameBlock(FlameBlock.UP, fb); fb.setNextFlameBlock(FlameBlock.DOWN, pfb); fb = pfb; r--; } } else { fb.setPaintBlock(false); } flameRow.setReadyToPaint(); } } else { double xFactor = ((double) width) / ((double) baseFlameBlock.getInclusiveValue()); FlameRow parentFlameRow = flameRows[row - 1]; if (parentFlameRow == null || !parentFlameRow.isReadyToPaint()) { break; } int lastXPos = -1; int lastParentID = -1; int childOffset = 0; flameRow.setFirstPaintedFlameBlock(null); FlameBlock lastPaintedFlameBlock = null; for (int n = flameBlocks.size() - 1; n >= 0; n--) { FlameBlock flameBlock = flameBlocks.get(n); flameBlock.resetPaintBlock(); FlameBlock parentFlameBlock = parentFlameRow.findFlameBlock(flameBlock.getParentID()); if (parentFlameBlock == null) { System.out.println( "Error: can't find flameblock row: " + parentFlameRow.getRow() + " id=" + flameBlock.getParentID()); break; } if (!parentFlameBlock.paintBlock()) { flameBlock.setPaintBlock(false); continue; } if (flameBlock.getParentID() != lastParentID) { childOffset = 0; lastParentID = flameBlock.getParentID(); } int xWidth = (int) (flameBlock.getInclusiveValue() * xFactor + 0.5); // round up/down ???? int xPos = parentFlameBlock.getXPos() + parentFlameBlock.getXWidth() - xWidth - childOffset; // if (flameBlock.getInclusiveValue() < // (baseFlameBlock.getInclusiveValue() * 0.001)) { // <==== Threshold (0.001)! // flameBlock.setPaintBlock(false); // } // else if (xPos < parentFlameBlock.getXPos()) { // Because of accumulating rounding, we can end up with a block to the left of it's // parent. Just adjust it here..... xWidth -= parentFlameBlock.getXPos() - xPos; xPos = parentFlameBlock.getXPos(); } if (xWidth <= 0 && xPos == lastXPos) { // Don't paint blocks with zero width if one already painted at same x position flameBlock.setPaintBlock(false); } else { flameBlock.setPaintBlock(true); flameBlock.setXPosAndWidth(xPos, xWidth); flameBlock.setFlameRow(flameRow); lastXPos = xPos; childOffset = childOffset + xWidth; flameBlock.initNext(); parentFlameBlock.setNextFlameBlock(FlameBlock.UP, flameBlock); flameBlock.setNextFlameBlock(FlameBlock.DOWN, parentFlameBlock); if (lastPaintedFlameBlock != null) { lastPaintedFlameBlock.setNextFlameBlock(FlameBlock.LEFT, flameBlock); flameBlock.setNextFlameBlock(FlameBlock.RIGHT, lastPaintedFlameBlock); } // flameRow.setFirstPaintedFlameBlock(flameBlock); // XXX lastPaintedFlameBlock = flameBlock; } } // Update LEFT/RIGHT links. Up until here, only blocks with same parent are linked // correctly. Blocks with different // paraents are shuffled due to the sorting. FlameBlock fbChild = null; FlameBlock pfb = flameRows[row - 1].getFirstPaintedFlameBlock(); FlameBlock lastFBChild = null; while (pfb != null) { FlameBlock pfbFirstChild = pfb.getNextFlameBlock(FlameBlock.UP); if (pfbFirstChild != null) { if (fbChild == null) { flameRow.setFirstPaintedFlameBlock(pfbFirstChild); pfbFirstChild.setNextFlameBlock(FlameBlock.LEFT, null); } if (lastFBChild != null) { lastFBChild.setNextFlameBlock(FlameBlock.RIGHT, pfbFirstChild); pfbFirstChild.setNextFlameBlock(FlameBlock.LEFT, lastFBChild); } fbChild = pfbFirstChild; while (fbChild != null && fbChild.getNextFlameBlock(FlameBlock.RIGHT) != null && fbChild.getNextFlameBlock(FlameBlock.RIGHT).getParentID() == pfb.getID()) { fbChild = fbChild.getNextFlameBlock(FlameBlock.RIGHT); } if (fbChild != null) { fbChild.setNextFlameBlock(FlameBlock.RIGHT, null); } lastFBChild = fbChild; } pfb = pfb.getNextFlameBlock(FlameBlock.RIGHT); } flameRow.setReadyToPaint(); } } // System.out.println("calculateFlameBlockWidths() " + (new Date().getTime() - // start.getTime())); } private int getBlockCount() { int blockCount = 0; for (FlameRow flameRow : flameRows) { blockCount += flameRow.getFlameBlocks().size(); } return blockCount; } protected Map<Long, StackState> getFunctionIdNameMap() { return functionIdNameMap; } protected double getTotalValue() { if (baseFlameBlock != null) { return baseFlameBlock.getInclusiveValue(); } else { // FIXUP: Error!!!!! return 0; } } protected void setFunctionIdNameMap(Map<Long, StackState> functionIdNameMap) { this.functionIdNameMap = functionIdNameMap; } protected FlameBlock findFlameBlock(int row, int x) { FlameBlock fb = null; if (row >= 0 && row < flameRows.length) { FlameRow flameRow = flameRows[row]; if (flameRow != null) { for (FlameBlock flameBlock : flameRow.getFlameBlocks()) { if (flameBlock.paintBlock()) { if (x >= flameBlock.getXPos() && x <= flameBlock.getXPos() + flameBlock.getXWidth()) { fb = flameBlock; break; } } } } } return fb; } /** * Search all painted flame blocks for function id. * * @param functionID * @return */ protected FlameBlock findFunctionFlameBlock(long functionID) { for (FlameRow flameRow : flameRows) { for (FlameBlock flameBlock = flameRow.getFirstPaintedFlameBlock(); flameBlock != null; flameBlock = flameBlock.getNextFlameBlock(FlameBlock.RIGHT)) { if (flameBlock.getFunctionID() == functionID) { return flameBlock; } } } return null; } protected FlameBlock getSelectedFlameBlock() { return selectedFlameBlock; } protected boolean setSelectedFlameBlock(FlameBlock selectedFlameBlock) { if (selectedFlameBlock != null && selectedFlameBlock != this.selectedFlameBlock) { handleSelectedObject(selectedFlameBlock); this.selectedFlameBlock = selectedFlameBlock; flameView.updateSelection(selectedFlameBlock); return true; } else { return false; } } /* Setting selected object is slow so delay and interrupt if another selection follows within xxx ms. */ private static void handleSelectedObject(final FlameBlock selectedFlameBlock) { synchronized (selectedObjectLock) { if (selectedObjectThread != null /* && selectedObjectThread.isAlive()*/) { selectedObjectThread.doInterrupt(); } selectedObjectThread = new UpdateSelectedObjectThread(selectedFlameBlock); AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { selectedObjectThread.run(); } }, "handleSelectedObject"); } } static class UpdateSelectedObjectThread extends Thread { private FlameBlock flameBlock; private boolean interrupted = false; public UpdateSelectedObjectThread(FlameBlock flameBlock) { this.flameBlock = flameBlock; } @Override public void run() { int loops = 10; int n = 0; while (n < loops && !interrupted) { try { Thread.sleep(40); } catch (InterruptedException ie) { } ; n++; } if (!interrupted) { // System.out.println("select " + flameBlock.getFunctionDisplayName()); AnWindow.getInstance().getSelectedObject().setSelObjV2(flameBlock.getFunctionID()); AnWindow.getInstance().getSelectionManager().updateSelection(); } } public void doInterrupt() { interrupted = true; } } protected FlameBlock getMouseOverFlameBlock() { return mouseOverFlameBlock; } protected boolean setMouseOverFlameBlock(FlameBlock mouseOverFlameBlock) { if (mouseOverFlameBlock != this.mouseOverFlameBlock) { this.mouseOverFlameBlock = mouseOverFlameBlock; return true; } else { return false; } } protected FlameBlock getBaseFlameBlock() { return baseFlameBlock; } protected void setBaseFlameBlock(FlameBlock baseFlameBlock) { this.baseFlameBlock = baseFlameBlock; setSelectedFlameBlock(baseFlameBlock); flameView.updateSelection(baseFlameBlock); } protected AnMetric getAnMetric() { return anMetric; } protected FlameBlock nextFlameBlock(FlameBlock flameBlock, boolean forward) { FlameBlock nextFlameBlock = null; if (!forward) { nextFlameBlock = flameBlock.getNext()[FlameBlock.RIGHT]; if (nextFlameBlock == null) { int row = flameBlock.getFlameRow().getRow(); row++; if (row < getFlameRows().length) { nextFlameBlock = getFlameRows()[row].getFirstPaintedFlameBlock(); } } if (nextFlameBlock == null) { nextFlameBlock = getFlameRows()[0].getFirstPaintedFlameBlock(); } } else { nextFlameBlock = flameBlock.getNext()[FlameBlock.LEFT]; if (nextFlameBlock == null) { int row = flameBlock.getFlameRow().getRow(); row--; if (row >= 0) { nextFlameBlock = getFlameRows()[row].getFirstPaintedFlameBlock(); if (nextFlameBlock != null) { while (nextFlameBlock.getNext()[FlameBlock.RIGHT] != null) { nextFlameBlock = nextFlameBlock.getNext()[FlameBlock.RIGHT]; } } } } if (nextFlameBlock == null) { int row = getFlameRows().length - 1; nextFlameBlock = null; while (nextFlameBlock == null && row > 0) { nextFlameBlock = getFlameRows()[row].getFirstPaintedFlameBlock(); row--; } if (nextFlameBlock != null) { while (nextFlameBlock.getNext()[FlameBlock.RIGHT] != null) { nextFlameBlock = nextFlameBlock.getNext()[FlameBlock.RIGHT]; } } } } return nextFlameBlock; } protected String dump(int rows) { StringBuilder buf = new StringBuilder(); buf.append("metric=" + anMetric.getUserName()); buf.append("\n"); buf.append("rows=" + flameRows.length); buf.append("\n"); for (int i = 0; i < rows && i < flameRows.length; i++) { buf.append(flameRows[i].dump()); } return buf.toString(); } } ����gprofng-gui-1.0/org/gprofng/mpmt/SelectionManager.java����������������������������������������������0000644�0001750�0001750�00000004326�14517772113�020025� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.mpmt.event.AnChangeEvent; import org.gprofng.mpmt.event.AnEventManager; import org.gprofng.mpmt.event.AnSelectionEvent; public class SelectionManager { public void updateSelection(long[] selObjs, int type, int subtype, int version) { updateSummaryPanel(selObjs, type, subtype, version); } public void updateSelection(long selObj, int type, int subtype, int version) { long[] objs = new long[1]; objs[0] = selObj; updateSummaryPanel(objs, type, subtype, version); } public void updateSelection(int[] selObj, int type, int subtype, int version) { int len = selObj.length; long[] objs = new long[len]; for (int i = 0; i < len; i++) { objs[i] = (long) selObj[i]; } updateSummaryPanel(objs, type, subtype, version); } public void updateSelection() { AnChangeEvent anChangeEvent = new AnChangeEvent(this, AnChangeEvent.Type.SELECTION_UPDATE); AnEventManager.getInstance().fireAnChangeEvent(anChangeEvent); } private void updateSummaryPanel(long[] selObjs, int type, int subtype, int version) { // System.out.println("updateSummaryPanel: " + type + " " + subtype + " " + version); // for (long l : selObjs) { // System.out.println(" " + l); // } AnSelectionEvent anSelectionEvent = new AnSelectionEvent(this, selObjs, type, subtype, version); AnChangeEvent anChangeEvent = new AnChangeEvent(anSelectionEvent, AnChangeEvent.Type.SELECTION_CHANGED); AnEventManager.getInstance().fireAnChangeEvent(anChangeEvent); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/AnInteger.java�����������������������������������������������������0000644�0001750�0001750�00000004040�14517772113�016452� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; // Analyzer Integer object public final class AnInteger extends AnObject implements Comparable { private final int value; private final Integer obj; // Constructor public AnInteger(int value) { this.value = value; obj = this.value; } // Analyzer int printing format public String toString() { return obj.toString(); } // Analyzer formatted printing format public String toFormString() { if (value == 0) { if (!showZero) { return quote_space; } } return format_group_integer.format(value); } // Percent printing public String toPercent(double total) { if (value == 0) { if (!showZero) { return quote_space; } return zero_percent; } return format_percent.format(value * total); } // To Integer public Integer toInteger() { return obj; } // To int public int intValue() { return value; } // To double public double doubleValue() { return value; } // As int.compareTo public int compareTo(Object o) { return obj.compareTo(((AnInteger) o).toInteger()); } // Convert int[] to AnInteger[] public static AnInteger[] toArray(int[] list) { int length = list.length; AnInteger[] new_list = new AnInteger[length]; for (int i = 0; i < length; i++) { new_list[i] = new AnInteger(list[i]); } return new_list; } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/mpmt/ResolveFilePathPanel.java������������������������������������������0000644�0001750�0001750�00000041741�14517772113�020623� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.mpmt; import org.gprofng.analyzer.AnEnvironment; import org.gprofng.mpmt.util.gui.AnUtility; import java.awt.Color; import java.io.File; import javax.swing.JFileChooser; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; public class ResolveFilePathPanel extends javax.swing.JPanel { private final ResolveFilePathDialog resolveFilePathDialog; private final String notFoundFilePath; private final String notFoundFileName; private String resolvedAsPath; private String filePath; private static boolean archiveCheckBoxState = true; private static boolean archiveThisFileOnlyState = true; private static String feed = ""; public ResolveFilePathPanel( ResolveFilePathDialog resolveFilePathDialog, String notFoundFilePath) { this.resolveFilePathDialog = resolveFilePathDialog; this.notFoundFilePath = notFoundFilePath; notFoundFileName = AnUtility.basename(notFoundFilePath); initComponents(); setBackground(AnEnvironment.DEFAULT_PANEL_BACKGROUND); infoLabel.setText(AnLocale.getString("Locate the source file below and click OK.")); AnUtility.setAccessibleContext(infoLabel.getAccessibleContext(), infoLabel.getText()); infoLabel.setDisplayedMnemonic(AnLocale.getString('L', "ResolvePanelLocateLabelMnemonic")); infoLabel.setLabelFor(pathTextField); AnUtility.setAccessibleContext( pathTextField.getAccessibleContext(), AnLocale.getString("Path")); String unResolvedTT = AnLocale.getString("Can not find source file") + " " + notFoundFilePath; unResolvedLabel.setIcon(AnUtility.fileUnResolved); unResolvedLabel.setText(""); unResolvedLabel.setToolTipText(unResolvedTT); AnUtility.setAccessibleContext( unResolvedLabel.getAccessibleContext(), AnLocale.getString("Unresolved Path")); unResolvedTextField.setText(notFoundFilePath + " " + AnLocale.getString("(not found)")); unResolvedTextField.setToolTipText(unResolvedTT); AnUtility.setAccessibleContext( unResolvedTextField.getAccessibleContext(), AnLocale.getString("Unresolved Path")); AnUtility.setAccessibleContext( resolvedTextField.getAccessibleContext(), AnLocale.getString("Rresolved Path")); browseButton.setMnemonic(AnLocale.getString('B', "ResolvePanelBrowseButtonMN")); browseButton.setToolTipText(AnLocale.getString("Browse for file (ALT B)")); thisFileOnlyCheckBox.setText(AnLocale.getString("Archive this file only")); thisFileOnlyCheckBox.setMnemonic(AnLocale.getString('R', "ResolvePanelThisFileOnly heckboxMN")); thisFileOnlyCheckBox.setToolTipText(AnLocale.getString("Only this file will be resolved")); thisFileOnlyCheckBox.setOpaque(false); thisFileOnlyCheckBox.setSelected(archiveThisFileOnlyState); archiveCheckBox.setText(AnLocale.getString("Archive source file(s) inside experiment")); archiveCheckBox.setToolTipText( AnLocale.getString( "Use Archive feature to save a copy of the file(s) inside the experiment")); archiveCheckBox.setMnemonic(AnLocale.getString('A', "ResolvePanelArchiveCheckkboxMN")); archiveCheckBox.setOpaque(false); archiveCheckBox.setSelected(archiveCheckBoxState); errorLabel.setForeground(Color.red); if (feed != null) { pathTextField.setText(feed); } pathTextField .getDocument() .addDocumentListener( new DocumentListener() { @Override public void changedUpdate(DocumentEvent e) { updateStates(); } @Override public void insertUpdate(DocumentEvent e) { updateStates(); } @Override public void removeUpdate(DocumentEvent e) { updateStates(); } }); updateStatesInternal(); } private void updateStates() { AnUtility.dispatchOnAWorkerThread( new Runnable() { @Override public void run() { updateStatesInternal(); } }, "updateStates"); } private void updateStatesInternal() { AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { errorLabel.setText(" "); resolveFilePathDialog.getOKButton().setEnabled(false); resolvedLabel.setIcon(null); resolvedTextField.setText(""); resolvedLabel.setToolTipText(null); resolvedTextField.setToolTipText(null); filePath = pathTextField.getText(); } }); if (filePath.equals("/net") || filePath.equals("/net/")) { return; // optimization } String fileName = AnUtility.basename(filePath); String error = null; resolvedAsPath = null; if (filePath.length() > 0 && !filePath.startsWith("/")) { error = AnLocale.getString("Use absolute path"); } if (error == null) { if (notFoundFilePath.startsWith("/")) { // Native absolute path File filePathFile = new AnFile(filePath); if (filePathFile.exists()) { if (filePathFile.isDirectory()) { String tryThis = filePathFile.getAbsoluteFile() + "/" + notFoundFileName; if (new AnFile(tryThis).exists()) { resolvedAsPath = tryThis; } } else if (notFoundFileName.equals(fileName)) { resolvedAsPath = filePath; } } else { if (fileName.equals(notFoundFileName)) { error = AnLocale.getString("File doesn't exists"); } } } else { // Java relative path File filePathFile = new AnFile(filePath); if (filePathFile.exists()) { if (filePathFile.isDirectory()) { String tryThis = filePathFile.getAbsoluteFile() + "/" + notFoundFilePath; if (new AnFile(tryThis).exists()) { resolvedAsPath = tryThis; } } else { // Compare file names String fName = AnUtility.basename(filePath); String nfName = AnUtility.basename(notFoundFilePath); if (nfName.equals(fName)) { resolvedAsPath = filePath; } } } else { if (fileName.equals(notFoundFileName)) { error = AnLocale.getString("File doesn't exists"); } } } } final String errorMsg = error; AnUtility.dispatchOnSwingThread( new Runnable() { @Override public void run() { if (errorMsg != null) { errorLabel.setText(errorMsg); } else if (resolvedAsPath != null) { resolveFilePathDialog.getOKButton().setEnabled(true); resolvedLabel.setIcon(AnUtility.fileResolved); resolvedTextField.setText(resolvedAsPath + " " + AnLocale.getString("(resolved)")); String tt = AnLocale.getString("File resolved as ") + resolvedAsPath; resolvedLabel.setToolTipText(tt); resolvedTextField.setToolTipText(tt); } } }); } private void updateCheckBoxStates() { thisFileOnlyCheckBox.setEnabled(archiveCheckBox.isSelected()); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT * modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; infoLabel = new javax.swing.JLabel(); unResolvedLabel = new javax.swing.JLabel(); unResolvedTextField = new javax.swing.JTextField(); resolvedLabel = new javax.swing.JLabel(); resolvedTextField = new javax.swing.JTextField(); pathTextField = new javax.swing.JTextField(); browseButton = new javax.swing.JButton(); archiveCheckBox = new javax.swing.JCheckBox(); thisFileOnlyCheckBox = new javax.swing.JCheckBox(); errorLabel = new javax.swing.JLabel(); setLayout(new java.awt.GridBagLayout()); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 0; gridBagConstraints.gridwidth = 2; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(6, 0, 0, 0); add(infoLabel, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 3; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 0, 0, 0); add(unResolvedLabel, gridBagConstraints); unResolvedTextField.setEditable(false); unResolvedTextField.setText("222"); unResolvedTextField.setBorder(null); unResolvedTextField.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 3; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(12, 4, 0, 0); add(unResolvedTextField, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 4; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); add(resolvedLabel, gridBagConstraints); resolvedTextField.setEditable(false); resolvedTextField.setText("111"); resolvedTextField.setBorder(null); resolvedTextField.setOpaque(false); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 1; gridBagConstraints.gridy = 4; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 0); add(resolvedTextField, gridBagConstraints); pathTextField.setColumns(50); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 5; gridBagConstraints.gridwidth = 2; gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; gridBagConstraints.weightx = 1.0; gridBagConstraints.insets = new java.awt.Insets(4, 0, 0, 0); add(pathTextField, gridBagConstraints); browseButton.setText("..."); browseButton.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { browseButtonActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 2; gridBagConstraints.gridy = 5; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(4, 4, 0, 0); add(browseButton, gridBagConstraints); archiveCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { archiveCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 6; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0); add(archiveCheckBox, gridBagConstraints); thisFileOnlyCheckBox.addActionListener( new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { thisFileOnlyCheckBoxActionPerformed(evt); } }); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 7; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; gridBagConstraints.insets = new java.awt.Insets(2, 17, 0, 0); add(thisFileOnlyCheckBox, gridBagConstraints); gridBagConstraints = new java.awt.GridBagConstraints(); gridBagConstraints.gridx = 0; gridBagConstraints.gridy = 9; gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; gridBagConstraints.anchor = java.awt.GridBagConstraints.LINE_START; add(errorLabel, gridBagConstraints); } // </editor-fold>//GEN-END:initComponents private void browseButtonActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_browseButtonActionPerformed // TODO add your handling code here: if (!Analyzer.getInstance().isRemote()) { // Local feed = pathTextField.getText(); File feedFile = new File(feed); if (!feedFile.exists()) { feed = Analyzer.getInstance().getWorkingDirectory(); feedFile = new File(feed); if (!feedFile.exists()) { feedFile = null; } } JFileChooser fileChooser = new JFileChooser(); // Always local file chooser fileChooser.setDialogTitle(AnLocale.getString("Resolve Source File")); if (feedFile != null) { fileChooser.setCurrentDirectory(feedFile); } fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { String filePath = fileChooser.getSelectedFile().getAbsolutePath(); pathTextField.setText(filePath); feed = pathTextField.getText(); } updateStates(); } else { // Remote feed = pathTextField.getText(); AnFile feedFile = new AnFile(feed); if (!feedFile.exists()) { feed = Analyzer.getInstance().getWorkingDirectory(); feedFile = new AnFile(feed); if (!feedFile.exists()) { feedFile = null; } } AnChooser fileChooser = AnWindow.getInstance() .getAnChooser( AnLocale.getString("Resolve Source File"), AnChooser.DIR_FILE_CHOOSER, feed); // JFileChooser fileChooser = new JFileChooser(); // Always local file chooser if (feedFile != null) { fileChooser.setCurrentDirectory(feedFile); } fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int ret = fileChooser.showOpenDialog(this); if (ret == JFileChooser.APPROVE_OPTION) { String filePath = fileChooser.getSelectedFile().getAbsolutePath(); pathTextField.setText(filePath); feed = pathTextField.getText(); } updateStates(); } } // GEN-LAST:event_browseButtonActionPerformed private void archiveCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_archiveCheckBoxActionPerformed archiveCheckBoxState = archiveCheckBox.isSelected(); if (archiveCheckBox.isSelected()) { thisFileOnlyCheckBox.setSelected(archiveThisFileOnlyState); } else { thisFileOnlyCheckBox.setSelected(false); } updateCheckBoxStates(); } // GEN-LAST:event_archiveCheckBoxActionPerformed private void thisFileOnlyCheckBoxActionPerformed( java.awt.event.ActionEvent evt) { // GEN-FIRST:event_thisFileOnlyCheckBoxActionPerformed archiveThisFileOnlyState = thisFileOnlyCheckBox.isSelected(); updateCheckBoxStates(); } // GEN-LAST:event_thisFileOnlyCheckBoxActionPerformed protected String getResolvedPath() { return resolvedAsPath; } protected boolean resolveThisFileOnly() { return thisFileOnlyCheckBox.isSelected(); } protected boolean archiveFiles() { return archiveCheckBox.isSelected(); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox archiveCheckBox; private javax.swing.JButton browseButton; private javax.swing.JLabel errorLabel; private javax.swing.JLabel infoLabel; private javax.swing.JTextField pathTextField; private javax.swing.JLabel resolvedLabel; private javax.swing.JTextField resolvedTextField; private javax.swing.JCheckBox thisFileOnlyCheckBox; private javax.swing.JLabel unResolvedLabel; private javax.swing.JTextField unResolvedTextField; // End of variables declaration//GEN-END:variables } �������������������������������gprofng-gui-1.0/org/gprofng/collector/��������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�015043� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/collector/CollectorAPI.java���������������������������������������������0000644�0001750�0001750�00000004522�14517772113�020074� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.collector; /** This class provides access to the gprofng GUI collector API. */ public class CollectorAPI { private static boolean inited = false; static { init(); } public static void init() { // Check if previously initialized if (inited) { return; } // Check if Java profiling is on if (!Boolean.getBoolean("collector.init")) { return; } try { System.loadLibrary("collector"); } catch (UnsatisfiedLinkError e) { System.err.println("CollectorAPI: " + e); return; } catch (SecurityException e) { System.err.println("CollectorAPI: " + e); return; } inited = true; } private static native void _sample(String name); public static void sample(String name) { if (inited) { _sample(name); } } public static void sample() { sample(null); } private static native void _pause(); public static void pause() { if (inited) { _pause(); } } private static native void _resume(); public static void resume() { if (inited) { _resume(); } } private static native void _threadPause(Thread thread); public static void threadPause(Thread thread) { if (inited) { _threadPause(thread); } } public static void threadPause() { threadPause(null); } private static native void _threadResume(Thread thread); public static void threadResume(Thread thread) { if (inited) { _threadResume(thread); } } public static void threadResume() { threadResume(null); } private static native void _terminate(); public static void terminate() { if (inited) { _terminate(); } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/analyzer/���������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775726�014702� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/analyzer/AnMain.java����������������������������������������������������0000644�0001750�0001750�00000025762�14517772113�016627� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.analyzer; import org.gprofng.mpmt.AnLocale; import org.gprofng.mpmt.Analyzer; import org.gprofng.mpmt.ExperimentPickList; import org.gprofng.mpmt.ExperimentPickListElement; import org.gprofng.mpmt.ExperimentPickLists; import org.gprofng.mpmt.guitesting.GUITesting; import org.gprofng.mpmt.persistence.UserPref; import org.gprofng.mpmt.persistence.UserPrefPersistence; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JDialog; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.UIManager; import javax.swing.plaf.FontUIResource; /** Main class for standalone analyzer */ public final class AnMain { private static JOptionPane importOldSettingPane = null; private static final int JVM_MAJOR = 1; private static final int JVM_MINOR = 8; /* The size of the fonts in the UI - 0 pt. The value can be changed by command-line argument -fontsize <size> */ private static int uiFontSize = 0; /** * Parses the command line arguments * * @param args command line arguments * @return array of arguments without the fontsize flag and that value */ private static String[] processArgs(final String[] args) { ArrayList<String> argsExp = new ArrayList<String>(); String argvOrig; for (int i = 0; i < args.length; i++) { argvOrig = args[i]; if (argvOrig.equals("-f") || argvOrig.equals("--fontsize")) { try { uiFontSize = Integer.parseInt(args[++i]); } catch (ArrayIndexOutOfBoundsException e) { System.out.println(AnLocale.getString("Font size expected, using default font size...")); } catch (NumberFormatException e2) { System.out.println( AnLocale.getString("Bad format of the font size, using default font size...")); } } else if (argvOrig.equals("-c") || argvOrig.equals("--compare")) { Analyzer.compareMode = true; } else if (argvOrig.equals("-u") || argvOrig.equals("--userdir")) { if (i >= (args.length - 1)) { System.out.println(AnLocale.getString("Not enough arguments, exiting...")); System.exit(1); } String userdir = args[++i]; UserPref.getInstance().setUserDir(userdir); } else if (argvOrig.startsWith("--bindir=")) { UserPref.binDirFromCommandLine = argvOrig.substring(argvOrig.indexOf("=") + 1); } else if (argvOrig.startsWith("--datadir=")) { UserPref.dataDirFromCommandLine = argvOrig.substring(argvOrig.indexOf("=") + 1); } else if (argvOrig.startsWith("--gprofngdir=")) { UserPref.gprofngdir = argvOrig.substring(argvOrig.indexOf("=") + 1); } else { argsExp.add(argvOrig); // This argument is an experiment name, or a name of a binary to profile // Don't parse target's options - pass them down for (int j = i + 1; j < args.length; j++) { argsExp.add(args[j]); } break; } } return argsExp.toArray(new String[argsExp.size()]); } // sets Fonts for the value of -fontsize key private static void setFontSize(int size) { // Set all font size to new size Enumeration keys = UIManager.getDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); Object value = UIManager.get(key); if (value instanceof FontUIResource) { FontUIResource font = (FontUIResource) value; UIManager.put(key, new FontUIResource(font.deriveFont((float) size))); } } } // Show Java version warning private static void warningVersion() { final String rec_ver, msg; final int sel; final Object[] options = new Object[] {AnLocale.getString("Continue"), AnLocale.getString("Exit")}; rec_ver = AnLocale.getString("J2SE[tm] ") + JVM_MAJOR + "." + JVM_MINOR; msg = AnLocale.getString("The J2SE[tm] ") + Analyzer.jvm_ver + AnLocale.getString(" found at ") + Analyzer.jvm_home + AnLocale.getString(" should not be used by the gprofng tools.\n") + rec_ver + AnLocale.getString(" is recommended.\n") + AnLocale.getString("Use the -j option to specify a path to ") + rec_ver + "."; sel = JOptionPane.showOptionDialog( null, msg, AnLocale.getString("Warning: Java Runtime Environment Version"), JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[1]); if ((sel == JOptionPane.CLOSED_OPTION) || (sel == JOptionPane.NO_OPTION)) { System.exit(0); } } public static void main(final String[] args) { // AnMemoryManager.getInstance().checkMemoryUsage(); AnEnvironment.setLookAndFeel(); Analyzer analyzer = new Analyzer(); int major = 0; int minor = 0; int n1, n2; String ver = analyzer.jvm_ver; if ((n1 = ver.indexOf('.')) != -1) { major = Integer.parseInt(ver.substring(0, n1)); if ((n2 = ver.indexOf('.', n1 + 1)) != -1) { minor = Integer.parseInt(ver.substring(n1 + 1, n2)); } } else { // Check if it is java 9 if (ver.startsWith("9")) { major = 1; minor = 9; } } if (major == 0 || (major == 1 && minor < 8) || (major > 1 && major < 8)) { warningVersion(); } ToolTipManager.sharedInstance().setInitialDelay(250); final String[] argsNew = processArgs(args); File fromDirFile = null; File toDirFile = null; if (!GUITesting.getInstance().isRunningUnderGUITesting()) { String actualUserDirPath = UserPref.getAnalyzerDirPath(); String actualInitFilePath = UserPref.getAnalyzerInitFilePath(); if (actualUserDirPath.equals(UserPref.getDefaultAnalyzerDirPath())) { if (!new File(actualInitFilePath).exists()) { for (String userDir : UserPref.getOldUserDirs()) { String userDirPath = UserPref.getAnalyzerDirPath(userDir); String initFilePath = UserPref.getAnalyzerInitFilePath(userDir); if (new File(initFilePath).exists()) { fromDirFile = new File(userDirPath); toDirFile = new File(actualUserDirPath); try { // FIXUP: should use copyDirectory from AnUtility but it doesn't run this early due // to class loader issue UserPref.copyDirectory(fromDirFile, toDirFile); } catch (IOException e) { e.printStackTrace(); // FIXUP: what to do? } String msg = AnLocale.getString( "Settings created by a previous version of Analyzer were found on your system" + " at %s.\n" + "They have been imported into %s."); String formattedMsg = String.format(msg, userDirPath, actualUserDirPath); // JOptionPane.showMessageDialog(null, formattedMsg, // AnLocale.getString("Import Settings"), JOptionPane.PLAIN_MESSAGE); importOldSettingPane = new JOptionPane(formattedMsg, JOptionPane.PLAIN_MESSAGE); break; } } } } // Read user settings new UserPrefPersistence() .restoreSettings(UserPref.getAnalyzerInitFilePath(), UserPref.getInstance()); // Copy those config files that are beeing used (from the picklists) if (fromDirFile != null && toDirFile != null) { ExperimentPickLists pickLists = UserPref.getInstance().getExperimentsPicklists(); if (pickLists != null) { Map<String, ExperimentPickList> picklistMap = pickLists.getPicklistMap(); if (picklistMap != null) { Set<String> hosts = picklistMap.keySet(); if (hosts != null) { for (String host : hosts) { ExperimentPickList experimentPickList = picklistMap.get(host); if (experimentPickList != null) { List<ExperimentPickListElement> elements = experimentPickList.getRecentExperiments(); if (elements != null) { for (ExperimentPickListElement element : elements) { String mangledFileNameNoTimestamp = UserPref.getMangledFileName(element.getPath(), host, false) + UserPref.configurationSuffix; String fromConfigPath = fromDirFile + "/" + UserPref.configDirName + "/" + UserPref.configAsWhenClosedName + "/" + mangledFileNameNoTimestamp; String asClosedDir = toDirFile + "/" + UserPref.configDirName + "/" + UserPref.configAsWhenClosedName; new File(asClosedDir).mkdirs(); String toConfigPath = asClosedDir + "/" + mangledFileNameNoTimestamp; try { UserPref.copyFile(new File(fromConfigPath), new File(toConfigPath)); } catch (IOException ioe) { } } } } } } } } } } if (uiFontSize > 0) { setFontSize(uiFontSize); } boolean in_netbeans = false; Analyzer.initPath(in_netbeans); analyzer.initMetricColors(); SwingUtilities.invokeLater( () -> { try { analyzer.initAnalyzer(argsNew); } catch (Exception e) { e.printStackTrace(); } }); } public static void showImportOldSettingsDialog() { if (importOldSettingPane != null) { final JDialog importOldSettingDialog = importOldSettingPane.createDialog(AnLocale.getString("Import Settings")); importOldSettingDialog.setModal(false); importOldSettingDialog.setVisible(true); importOldSettingDialog.requestFocus(); importOldSettingPane = null; } } } ��������������gprofng-gui-1.0/org/gprofng/analyzer/AnEnvironment.java���������������������������������������������0000644�0001750�0001750�00000033430�14517772113�020236� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.analyzer; import org.gprofng.mpmt.guitesting.GUITesting; import org.gprofng.mpmt.util.gui.AnScrollBarUI; import java.awt.Color; import java.awt.Font; import java.util.Enumeration; import javax.swing.UIManager; import javax.swing.plaf.FontUIResource; public class AnEnvironment { public static final Color NIMBUS_PANEL_BACKGROUND = new Color(236, 236, 240); public static final Color NIMBUS_PANEL_LIGHT_BACKGROUND = new Color(249, 249, 251); public static final Color NIMBUS_TABLE_BACKGROUND = new Color(252, 253, 254); public static final Color NIMBUS_SCROLLPANE_BACKGROUND = NIMBUS_TABLE_BACKGROUND; public static final Color NIMBUS_TEXT_BACKGROUND = NIMBUS_TABLE_BACKGROUND; public static final Color NIMBUS_LIST_BACKGROUND = NIMBUS_TABLE_BACKGROUND; public static final Color NIMBUS_TREE_BACKGROUND = NIMBUS_TABLE_BACKGROUND; public static final Color NIMBUS_TABLE_HEADER_BACKGROUND = new Color(230, 230, 234); public static final Color NIMBUS_TABLE_SELECTION_BACKGROUND = new Color(190, 210, 229); public static final Color SCROLLPANE_BACKGROUND = Color.WHITE; public static final Color INVISIBLE_BACKGROUND = new Color(0, 0, 0, 0); public static final Color DEFAULT_BACKGROUND_COLOR = UIManager.getLookAndFeel().getDefaults().getColor("Panel.background"); public static final Color DEFAULT_PANEL_BACKGROUND = new Color(251, 251, 251); public static final Color DEFAULT_DIALOG_BACKGROUND = new Color(248, 248, 248); public static final Color DEFAULT_TEXT_PANE_RO_BACKGROUND = new Color(250, 250, 250); public static final Color NAVIGATION_PANEL_BACKGROUND_COLOR = new Color(221, 222, 227); public static final Color NAVIGATION_PANEL_SECTION_BACKGROUND_COLOR = new Color(199, 200, 205); public static final Color NAVIGATION_PANEL_BORDER_COLOR = new Color(179, 178, 178); public static final Color NAVIGATION_SPLIT_PANE_DIVIDER_COLOR = new Color(146, 146, 148); public static final Color VIEW_SELECTED_TOP_COLOR = new Color(209, 225, 239); public static final Color VIEW_SELECTED_BOTTOM_COLOR = new Color(176, 189, 201); public static final Color VIEW_FOCUSED_TOP_COLOR = new Color(239, 239, 239); public static final Color VIEW_FOCUSED_BOTTOM_COLOR = new Color(218, 218, 218); public static final Color VIEW_FOCUSED_BACKGROUND_COLOR = new Color(215, 220, 230); public static final Color VIEW_SELECTED_BACKGROUND_COLOR = new Color(183, 196, 220); public static final Color VIEW_SELECTED_BORDER_COLOR = new Color(190, 190, 200); public static final Color STATUS_SELECTED_BORDER_COLOR = new Color(150, 150, 160); public static final Color DROP_LINE_COLOR = new Color(255, 165, 0); public static final Color SUBVIEW_PANEL_BACKGROUND = new Color(242, 242, 244); public static final Color ABOUT_BOX_BORDER_COLOR = new Color(204, 204, 204); public static final Color SPLIT_PANE_BORDER_COLOR = new Color(206, 208, 210); public static final Color SPLIT_PANE_BORDER_COLOR_INSIDE = new Color(206 + 20, 208 + 20, 210 + 20); public static final Color SPLIT_PANE_DIVIDER_BACKGROUND_COLOR = new Color(249, 249, 251); public static final Color SPLIT_PANE_DIVIDER_BACKGROUND_COLOR_INSIDE = new Color(210, 210, 212); public static final Color SPLIT_PANE_ONE_TOUCH_BUTTON_COLOR = new Color(120, 120, 120); public static final Color SPLIT_PANE_ONE_TOUCH_BUTTON_FOCUSED_COLOR = new Color(10, 10, 10); public static final Color TABBED_PANE_BORDER_COLOR = new Color(206, 208, 210); public static final Color TABBED_PANE_BACKGROUND_COLOR = new Color(218, 218, 218); public static final Color TABBED_PANE_DEFAULT_COLOR = new Color(218, 218, 218); public static final Color TABBED_PANE_TAB_AREA_TOP_COLOR = new Color(244, 244, 245); public static final Color TABBED_PANE_TAB_AREA_BOTTOM_COLOR = new Color(218, 218, 218); public static final Color TABBED_PANE_DIVIDER_COLOR = new Color(163, 163, 163); public static final Color TABBED_PANE_LINE_COLOR = new Color(238, 238, 238); public static final Color TABBED_PANE_SELECTED_TAB_COLOR = new Color(238, 238, 238); public static final Color TABBED_PANE_FOCUSED_TAB_TOP_COLOR = new Color(221, 229, 236); public static final Color TABBED_PANE_FOCUSED_TAB_BOTTOM_COLOR = new Color(207, 215, 222); public static final Color TABBED_PANE_DESELECTED_TAB_TOP_COLOR = new Color(244, 244, 245); public static final Color TABBED_PANE_DESELECTED_TAB_BOTTOM_COLOR = new Color(218, 218, 218); public static final Color TABBED_PANE_DESELECTED_FORGROUND_COLOR = new Color(150, 150, 150); public static final Color TABBED_PANE_TAB_FOCUS_COLOR = new Color(180, 180, 180); public static final Color FILTER_FOREGROUND_COLOR = new Color(44, 121, 6); public static final Color FILTER_BACKGROUND1_COLOR = DEFAULT_TEXT_PANE_RO_BACKGROUND; public static final Color FILTER_BACKGROUND2_COLOR = new Color(251 - 4, 251 - 4, 251 - 4); public static final Color FILTER_BACKGROUND_SELECTED_COLOR = new Color(233, 238, 244); public static final Color FILTER_INFO_TEXT_COLOR = new Color(160, 160, 160); public static final Color FILTER_DIVIDER_BACKGROUND_COLOR = new Color(196 + 5, 197 + 5, 201 + 5); public static final Color FILTER_HEADER_COLOR = new Color(51, 51, 51); public static final Color FILTER_TOOLBAR_BACKGROUND1_COLOR = new Color(238, 238, 238); public static final Color FILTER_TOOLBAR_BACKGROUND2_COLOR = new Color(219, 219, 219); public static final Color FILTER_STATUS_BORDER_COLOR = new Color(182, 181, 186); public static final Color WELCOME_BUTTON_FOCUSED_COLOR = new Color(100, 130, 220); public static final Color WELCOME_BUTTON_DISABLED_COLOR = new Color(190, 190, 190); public static final Color WELCOME_BUTTON_ACTION_COLOR = new Color(125, 125, 125); public static final Color WELCOME_BUTTON_EXPERIMENT_COLOR = new Color(125, 125, 125); public static final Color WELCOME_MAIN_LABEL_COLOR = new Color(102, 102, 102); public static final Color STATUS_PANEL_BORDER_COLOR = new Color(179, 178, 178); public static final Color STATUS_PANEL_BACKGROUND_COLOR1 = new Color(228, 228, 228); public static final Color STATUS_PANEL_BACKGROUND_COLOR2 = new Color(191, 190, 191); public static final Color TOOLBAR_BACKGROUND_COLOR = new Color(178, 178, 178); public static final Color TOOLBAR_BORDER_COLOR = new Color(133 + 30, 133 + 30, 133 + 30); public static final Color MENUBAR_BACKGROUND_COLOR1 = new Color(228, 228, 228); public static final Color MENUBAR_BACKGROUND_COLOR2 = new Color(191, 190, 191); public static final Color MENUBAR_BORDER_COLOR = new Color(179, 178, 178); public static final Color MENUBAR_BACKGROUND_COLOR = new Color(207, 207, 207); public static final Color BAR_BORDER_COLOR = new Color(190, 190, 190); public static final Color BAR_BACKGROUND_COLOR = Color.WHITE; public static final Color BAR_COMPARE_COLOR1 = new Color(195, 195, 195); public static final Color BAR_COMPARE_COLOR2 = new Color(215, 215, 215); public static final Color METRIC_HOT_HIGHLIGHT = new Color(255, 200, 0); public static final Color TOOLTIP_POPUP_BACKGROUND_COLOR = new Color(223, 236, 243); public static final Color TOOLTIP_POPUP_FOREGROUND_COLOR = new Color(51, 77, 100); public static final Color TOOLTIP_POPUP_BORDER_COLOR = new Color(144, 145, 149); public static final Color TOOLTIP_VIEW_BACKGROUND_COLOR = new Color(247, 247, 255); // Scroll bars public static final Color SCROLLBAR_TRACK_COLOR = new Color(248, 248, 248); public static final Color SCROLLBAR_BORDER_COLOR = new Color(199, 200, 202); public static final Color SCROLLBAR_THUMB_COLOR = new Color(179, 178, 178); public static final Color SCROLLBAR_THUMB_FOCUSED_COLOR = new Color(129, 129, 129); public static final Color SCROLLBAR_INC_DEC_COLOR = new Color(129, 129, 129); public static final Color SCROLLBAR_INC_DEC_FOCUSED_COLOR = new Color(55, 55, 55); // Tables public static final Color TABLE_HEADER_FOREGROUND_COLOR = new Color(86, 101, 125); public static final Color TABLE_HEADER_BACKGROUND_COLOR_1 = new Color(248, 248, 251); public static final Color TABLE_HEADER_BACKGROUND_COLOR_2 = new Color(248 - 6, 248 - 6, 251 - 6); public static final Color TABLE_HEADER_SELECTED_COLOR = new Color(209, 225, 239); public static final Color TABLE_LINE_BACKGROUND_COLOR_2 = new Color(249, 249, 249); public static final Color TABLE_LINE_BACKGROUND_SELECTED_COLUMN_COLOR_1 = new Color(238, 244, 249); public static final Color TABLE_LINE_BACKGROUND_SELECTED_COLUMN_COLOR_2 = new Color(228, 233, 238); public static final Color TABLE_VERTICAL_GRID_COLOR = new Color(230 - 5, 230 - 5, 230 - 5); public static final Color TABLE_VERTICAL_GRID_METRIC_COLOR = new Color(200 - 20, 200 - 20, 200 - 20); public static final Color TABLE_VERTICAL_GRID_ATTRIBUTE_COMP_COLOR = new Color(210 - 20, 210 - 20, 210 - 20); public static final Color TABLE_VERTICAL_GRID_METRIC_COMP_COLOR = new Color(180 - 20, 180 - 20, 180 - 20); // Metric public static final Color METRIC_MENU_SECTION_COLOR = new Color(80, 80, 80); public static final Color METRIC_SELCTOR_MENU_SEPARATOR_COLOR = new Color(220, 220, 220); // Compare status panel public static final Color COMPARE_TOGGLE_ICON_BORDER_COLOR = new Color(150, 150, 150); public static final Color COMPARE_TOGGLE_ICON_BORDER_FOCUSED_COLOR = new Color(100, 100, 100); public static final Color COMPARE_TOGGLE_ICON_SELECTED_COLOR = new Color(209, 225, 239); public static final Color COMPARE_ICON_BORDER_COLOR = new Color(219, 219, 219); public static final Color COMPARE_ICON_MOUSE_PRESSED_BACKGROUND_COLOR = new Color(209 - 20, 225 - 20, 239 - 20); public static final Color COMPARE_ICON_TOGGLE_BACKGROUND_COLOR = new Color(217, 219, 224); public static final Color FLAME_TOP_COLOR = new Color(254, 254, 254); public static final Color FLAME_BOTTOM_COLOR = new Color(230, 230, 230); public static final Color FLAME_INFO_TEXT_COLOR = new Color(120, 120, 120); public static final Color FLAME_BLOCK_BORDER_COLOR = new Color(180, 180, 180); public static final Color FLAME_BLOCK_BASE_BACKGROUND = new Color(255, 157, 14); public static final Color FLAME_BLOCK_SELECTED_BACKGROUND = new Color(210, 210, 210); public static final Color FLAME_BLOCK_SELECTED_BORDER1 = new Color(35, 85, 135); public static final Color FLAME_BLOCK_SELECTED_BORDER2 = new Color(210, 210, 210); public static final Color FLAME_BLOCK_MOUSEOVER_BORDER1 = new Color(0, 102, 51); public static final String DefaultLFName = "Metal"; public enum LF { Metal, Nimbus, Windows, AppleAqua, Motif, GTK }; private static LF lf = null; public static void setLookAndFeel() { // Always set L&F to Metal, if available String lfName = UIManager.getLookAndFeel().getName(); if (!lfName.equals(DefaultLFName)) { try { UIManager.LookAndFeelInfo[] installedLookAndFeels = UIManager.getInstalledLookAndFeels(); for (UIManager.LookAndFeelInfo lookAndFeelInfo : installedLookAndFeels) { if (lookAndFeelInfo.getName().equals(DefaultLFName)) { javax.swing.UIManager.setLookAndFeel(lookAndFeelInfo.getClassName()); break; } } } catch (ClassNotFoundException ex) { } catch (InstantiationException ex) { } catch (IllegalAccessException ex) { } catch (javax.swing.UnsupportedLookAndFeelException ex) { } } lfName = UIManager.getLookAndFeel().getName(); if (lfName.equals("Metal")) { lf = LF.Metal; setAnalyzerMetalTheme(); } else if (lfName.equals("Nimbus")) { lf = LF.Nimbus; setAnalyzerNimbusTheme(); } else if (lfName.startsWith("Mac")) { lf = LF.AppleAqua; } else if (lfName.startsWith("Windows")) { lf = LF.Windows; } else if (lfName.equals("CDE/Motif")) { lf = LF.Motif; } else if (lfName.equals("GTK+")) { lf = LF.GTK; } else { lf = LF.Metal; } } /** * @return true if current L&F is Metal */ public static boolean isLFMetal() { return lf == LF.Metal; } /** * @return true if current L&F is Nimbus */ public static boolean isLFNimbus() { return lf == LF.Nimbus; } /** * @return the current L&F */ public static LF getLF() { return lf; } private static void setAnalyzerNimbusTheme() { UIManager.getLookAndFeel().getDefaults().put("FileChooser.background", NIMBUS_PANEL_BACKGROUND); UIManager.getLookAndFeel().getDefaults().put("Panel.background", NIMBUS_PANEL_BACKGROUND); } private static void setAnalyzerMetalTheme() { // Set all fonts to PLAIN Enumeration keys = UIManager.getDefaults().keys(); while (keys.hasMoreElements()) { Object key = keys.nextElement(); Object value = UIManager.get(key); if (value instanceof FontUIResource) { if (GUITesting.getInstance().isRunningUnderGUITesting()) { Font font = new Font("monospaced", Font.PLAIN, 12); FontUIResource fontResource = new FontUIResource(font); UIManager.put(key, fontResource); } else { FontUIResource font = (FontUIResource) value; UIManager.put(key, new FontUIResource(font.deriveFont(Font.PLAIN))); } } } // Install our own scroll bar UI UIManager.put("ScrollBarUI", AnScrollBarUI.class.getName()); UIManager.put("ScrollBar.width", 14); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/org/gprofng/analyzer/AnLog.java�����������������������������������������������������0000644�0001750�0001750�00000003555�14517772113�016460� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ package org.gprofng.analyzer; import org.gprofng.mpmt.persistence.UserPref; import java.io.File; import java.io.FileWriter; import java.io.IOException; public class AnLog { private static final String logfileName = "log.text"; private static String logFilePath = null; private static FileWriter fileWriter = null; private static FileWriter getFileWriter() { if (fileWriter == null) { boolean ok = new File(getLogFileDir()).mkdirs(); File logFile = new File(getLogFilePath()); try { fileWriter = new FileWriter(logFile, false); } catch (IOException ioe) { } } return fileWriter; } public static String getLogFileDir() { return UserPref.getInstance().getAnalyzerDirPath(); } public static String getLogFilePath() { if (logFilePath == null) { logFilePath = getLogFileDir() + "/" + logfileName; } return logFilePath; } public static void log(String text) { if (text == null) { return; } if (getFileWriter() == null) { System.err.println(text); return; } try { getFileWriter().write(text); getFileWriter().write("\n"); getFileWriter().flush(); } catch (IOException ioe) { } } } ���������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/configure���������������������������������������������������������������������������0000755�0001750�0001750�00000433670�14517775004�012455� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for gprofng-gui 1.0. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 </dev/null exec 6>&1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='gprofng-gui' PACKAGE_TARNAME='gprofng-gui' PACKAGE_VERSION='1.0' PACKAGE_STRING='gprofng-gui 1.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS JAR JAVAC JAVA am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir runstatedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL am__quote' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' runstatedir='${localstatedir}/run' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -runstatedir | --runstatedir | --runstatedi | --runstated \ | --runstate | --runstat | --runsta | --runst | --runs \ | --run | --ru | --r) ac_prev=runstatedir ;; -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \ | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \ | --run=* | --ru=* | --r=*) runstatedir=$ac_optarg ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir runstatedir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures gprofng-gui 1.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/gprofng-gui] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of gprofng-gui 1.0:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a nonstandard directory <lib dir> LIBS libraries to pass to the linker, e.g. -l<library> CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if you have headers in a nonstandard directory <include dir> Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF gprofng-gui configure 1.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by gprofng-gui $as_me 1.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.16' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='gprofng-gui' VERSION='1.0' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> # <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> mkdir_p='$(MKDIR_P)' # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542> Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: <https://www.gnu.org/software/coreutils/>. If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdarg.h> #include <stdio.h> struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} supports the include directive" >&5 $as_echo_n "checking whether ${MAKE-make} supports the include directive... " >&6; } cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do { echo "$as_me:$LINENO: ${MAKE-make} -f confmf.$s && cat confinc.out" >&5 (${MAKE-make} -f confmf.$s && cat confinc.out) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } case $?:`cat confinc.out 2>/dev/null` in #( '0:this is the am__doit target') : case $s in #( BSD) : am__include='.include' am__quote='"' ;; #( *) : am__include='include' am__quote='' ;; esac ;; #( *) : ;; esac if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${_am_result}" >&5 $as_echo "${_am_result}" >&6; } # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi for ac_prog in java do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JAVA+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JAVA"; then ac_cv_prog_JAVA="$JAVA" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JAVA="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi JAVA=$ac_cv_prog_JAVA if test -n "$JAVA"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVA" >&5 $as_echo "$JAVA" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$JAVA" && break done test -n "$JAVA" || JAVA="no" for ac_prog in javac do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JAVAC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JAVAC"; then ac_cv_prog_JAVAC="$JAVAC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JAVAC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi JAVAC=$ac_cv_prog_JAVAC if test -n "$JAVAC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAVAC" >&5 $as_echo "$JAVAC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$JAVAC" && break done test -n "$JAVAC" || JAVAC="no" for ac_prog in jar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_JAR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$JAR"; then ac_cv_prog_JAR="$JAR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_JAR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi JAR=$ac_cv_prog_JAR if test -n "$JAR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $JAR" >&5 $as_echo "$JAR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$JAR" && break done test -n "$JAR" || JAR="no" ac_config_files="$ac_config_files Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by gprofng-gui $as_me 1.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ gprofng-gui config.status 1.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' <conf$$subs.awk | sed ' /^[^""]/{ N s/\n// } ' >>$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. case $CONFIG_FILES in #( *\'*) : eval set x "$CONFIG_FILES" ;; #( *) : set x $CONFIG_FILES ;; #( *) : ;; esac shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`$as_echo "$am_mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`$as_dirname -- "$am_mf" || $as_expr X"$am_mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$am_mf" : 'X\(//\)[^/]' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$am_mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` am_filepart=`$as_basename -- "$am_mf" || $as_expr X/"$am_mf" : '.*/\([^/][^/]*\)/*$' \| \ X"$am_mf" : 'X\(//\)$' \| \ X"$am_mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$am_mf" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` { echo "$as_me:$LINENO: cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles" >&5 (cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } || am_rc=$? done if test $am_rc -ne 0; then { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE=\"gmake\" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking). See \`config.log' for more details" "$LINENO" 5; } fi { am_dirpart=; unset am_dirpart;} { am_filepart=; unset am_filepart;} { am_mf=; unset am_mf;} { am_rc=; unset am_rc;} rm -f conftest-deps.mk } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi if test "x$JAVA" = "xno"; then as_fn_error $? "java is needed to build gprofng-gui. Please install the JRE." "$LINENO" 5 fi if test "x$JAVAC" = "xno"; then as_fn_error $? "A java compiler is needed to build gprofng-gui. Please install the JDK." "$LINENO" 5 fi if test "x$JAR" = "xno"; then as_fn_error $? "JAR is needed to buidl gprofng-guil. Please install the JDK." "$LINENO" 5 fi ������������������������������������������������������������������������gprofng-gui-1.0/install-sh��������������������������������������������������������������������������0000755�0001750�0001750�00000035776�14517772130�012554� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/bin/sh # install - install a program, script, or datafile scriptversion=2020-11-14.01; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. tab=' ' nl=' ' IFS=" $tab$nl" # Set DOITPROG to "echo" to test this script. doit=${DOITPROG-} doit_exec=${doit:-exec} # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_mkdir= # Desired mode of installed file. mode=0755 # Create dirs (including intermediate dirs) using mode 755. # This is like GNU 'install' as of coreutils 8.32 (2020). mkdir_umask=22 backupsuffix= chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false is_target_a_directory=possibly usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -p pass -p to $cpprog. -s $stripprog installed files. -S SUFFIX attempt to back up existing files, with suffix SUFFIX. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG By default, rm is invoked with -f; when overridden with RMPROG, it's up to you to specify -f if you want it. If -S is not specified, no backups are attempted. Email bug reports to bug-automake@gnu.org. Automake home page: https://www.gnu.org/software/automake/ " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *"$tab"* | *"$nl"* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -p) cpprog="$cpprog -p";; -s) stripcmd=$stripprog;; -S) backupsuffix="$2" shift;; -t) is_target_a_directory=always dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) is_target_a_directory=never;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done # We allow the use of options -d and -T together, by making -d # take the precedence; this is for compatibility with GNU install. if test -n "$dir_arg"; then if test -n "$dst_arg"; then echo "$0: target directory not allowed when installing a directory." >&2 exit 1 fi fi if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then if test $# -gt 1 || test "$is_target_a_directory" = always; then if test ! -d "$dst_arg"; then echo "$0: $dst_arg: Is not a directory." >&2 exit 1 fi fi fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? # Don't chown directories that already exist. if test $dstdir_status = 0; then chowncmd="" fi else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename. if test -d "$dst"; then if test "$is_target_a_directory" = never; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dstbase=`basename "$src"` case $dst in */) dst=$dst$dstbase;; *) dst=$dst/$dstbase;; esac dstdir_status=0 else dstdir=`dirname "$dst"` test -d "$dstdir" dstdir_status=$? fi fi case $dstdir in */) dstdirslash=$dstdir;; *) dstdirslash=$dstdir/;; esac obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false # The $RANDOM variable is not portable (e.g., dash). Use it # here however when possible just to lower collision chance. tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap ' ret=$? rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null exit $ret ' 0 # Because "mkdir -p" follows existing symlinks and we likely work # directly in world-writeable /tmp, make sure that the '$tmpdir' # directory is successfully created first before we actually test # 'mkdir -p'. if (umask $mkdir_umask && $mkdirprog $mkdir_mode "$tmpdir" && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. test_tmpdir="$tmpdir/a" ls_ld_tmpdir=`ls -ld "$test_tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$test_tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null fi trap '' 0;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac oIFS=$IFS IFS=/ set -f set fnord $dstdir shift set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=${dstdirslash}_inst.$$_ rmtmp=${dstdirslash}_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && { test -z "$stripcmd" || { # Create $dsttmp read-write so that cp doesn't create it read-only, # which would cause strip to fail. if test -z "$doit"; then : >"$dsttmp" # No need to fork-exec 'touch'. else $doit touch "$dsttmp" fi } } && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # If $backupsuffix is set, and the file being installed # already exists, attempt a backup. Don't worry if it fails, # e.g., if mv doesn't support -f. if test -n "$backupsuffix" && test -f "$dst"; then $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null fi # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: ��gprofng-gui-1.0/aclocal.m4��������������������������������������������������������������������������0000644�0001750�0001750�00000121700�14517772126�012374� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# generated automatically by aclocal 1.16.3 -*- Autoconf -*- # Copyright (C) 1996-2020 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.16' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.16.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.16.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl # Expand $ac_aux_dir to an absolute path. am_aux_dir=`cd "$ac_aux_dir" && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. # TODO: see whether this extra hack can be removed once we start # requiring Autoconf 2.70 or later. AS_CASE([$CONFIG_FILES], [*\'*], [eval set x "$CONFIG_FILES"], [*], [set x $CONFIG_FILES]) shift # Used to flag and report bootstrapping failures. am_rc=0 for am_mf do # Strip MF so we end up with the name of the file. am_mf=`AS_ECHO(["$am_mf"]) | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile which includes # dependency-tracking related rules and includes. # Grep'ing the whole file directly is not great: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. sed -n 's,^am--depfiles:.*,X,p' "$am_mf" | grep X >/dev/null 2>&1 \ || continue am_dirpart=`AS_DIRNAME(["$am_mf"])` am_filepart=`AS_BASENAME(["$am_mf"])` AM_RUN_LOG([cd "$am_dirpart" \ && sed -e '/# am--include-marker/d' "$am_filepart" \ | $MAKE -f - am--depfiles]) || am_rc=$? done if test $am_rc -ne 0; then AC_MSG_FAILURE([Something went wrong bootstrapping makefile fragments for automatic dependency tracking. If GNU make was not used, consider re-running the configure script with MAKE="gmake" (or whatever is necessary). You can also try re-running configure with the '--disable-dependency-tracking' option to at least be able to build the package (albeit without support for automatic dependency tracking).]) fi AS_UNSET([am_dirpart]) AS_UNSET([am_filepart]) AS_UNSET([am_mf]) AS_UNSET([am_rc]) rm -f conftest-deps.mk } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking is enabled. # This creates each '.Po' and '.Plo' makefile fragment that we'll need in # order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" MAKE="${MAKE-make}"])]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html> # <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html> AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target (and possibly the TAP driver). The # system "awk" is bad on some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542> Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: <https://www.gnu.org/software/coreutils/>. If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi dnl The trailing newline in this macro's definition is deliberate, for dnl backward compatibility and to allow trailing 'dnl'-style comments dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841. ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh+set}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check whether make has an 'include' directive that can support all # the idioms we need for our automatic dependency tracking code. AC_DEFUN([AM_MAKE_INCLUDE], [AC_MSG_CHECKING([whether ${MAKE-make} supports the include directive]) cat > confinc.mk << 'END' am__doit: @echo this is the am__doit target >confinc.out .PHONY: am__doit END am__include="#" am__quote= # BSD make does it like this. echo '.include "confinc.mk" # ignored' > confmf.BSD # Other make implementations (GNU, Solaris 10, AIX) do it like this. echo 'include confinc.mk # ignored' > confmf.GNU _am_result=no for s in GNU BSD; do AM_RUN_LOG([${MAKE-make} -f confmf.$s && cat confinc.out]) AS_CASE([$?:`cat confinc.out 2>/dev/null`], ['0:this is the am__doit target'], [AS_CASE([$s], [BSD], [am__include='.include' am__quote='"'], [am__include='include' am__quote=''])]) if test "$am__include" != "#"; then _am_result="yes ($s style)" break fi done rm -f confinc.* confmf.* AC_MSG_RESULT([${_am_result}]) AC_SUBST([am__include])]) AC_SUBST([am__quote])]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then MISSING="\${SHELL} '$am_aux_dir/missing'" fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2020 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar <conftest.tar]) AM_RUN_LOG([cat conftest.dir/file]) grep GrepMe conftest.dir/file >/dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR ����������������������������������������������������������������gprofng-gui-1.0/doc/��������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�14517775727�011372� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/doc/local.mk������������������������������������������������������������������������0000644�0001750�0001750�00000003351�14517772113�012721� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������## Process this file with automake to generate Makefile.in # # Copyright (C) 2012-2023 Free Software Foundation, Inc. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING3. If not see # <http://www.gnu.org/licenses/>. # docdir = $(srcdir)/doc # Options to extract the man page MANCONF = -Dman TEXI2POD = perl $(srcdir)/etc/texi2pod.pl $(AM_MAKEINFOFLAGS) POD2MAN = pod2man --center="User Commands" \ --release="binutils-$(VERSION)" --section=1 #info_TEXINFOS = gp-display-gui.texi TEXINFO_TEX = . MAKEINFOHTML = $(MAKEINFO) --html --no-split man_MANS = gp-display-gui.1 # Build the man page from the texinfo file # The sed command removes the no-adjust Nroff command so that # the man output looks standard. $(man_MANS): $(docdir)/gp-macros.texi $(AM_V_GEN)touch $@ ( nm=`basename $@ .1` ; \ $(AM_V_at)$(TEXI2POD) $(MANCONF) < $(docdir)/$$nm.texi > $$nm.pod ; \ $(AM_V_at)($(POD2MAN) $$nm.pod | sed -e '/^.if n .na/d' > $@.tmp && \ mv -f $@.tmp $@) || (rm -f $@.tmp && exit 1) ; \ $(AM_V_at)rm -f $$nm.pod ) gp-display-gui.1: $(docdir)/gp-display-gui.texi EXTRA_DIST += $(man_MANS) $(docdir)/gp-macros.texi $(docdir)/gp-display-gui.texi CLEANFILES += $(man_MANS) ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/doc/gp-macros.texi������������������������������������������������������������������0000644�0001750�0001750�00000002465�14517772113�014066� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@c -- Macro definitions ------------------------------------------------------- @c @c Since only letters can be used, we use capitalization to distinguish @c different words. @c ---------------------------------------------------------------------------- @macro CollectApp{} @command{gprofng collect app} @end macro @macro DisplayHTML{} @command{gprofng display html} @end macro @macro DisplayText{} @command{gprofng display text} @end macro @macro DisplaySRC{} @command{gprofng display src} @end macro @macro Archive{} @command{gprofng archive} @end macro @macro Driver{} @command{gprofng} @end macro @macro ProductName{} gprofng @end macro @macro ToolName{} @command{gprofng} @end macro @macro IndexSubentry{label, string} @c -- @cindex \label\ @subentry \string\ @cindex \label\, \string\ @end macro @macro vspace {lines} @iftex @sp \lines\ @end iftex @end macro @c -- For some reason ending this macro with @noindent does not work out well. @macro OptionHeader {lines, option, description} @sp \lines\ @noindent @code{\option\} @ @emph{\description\} @c -- @sp 1 @end macro @macro gcctabopt{body} @code{\body\} @end macro @macro ManPageStart{headername} @ifclear man @sp 1 @noindent @b{\headername\} @indentedblock @end ifclear @end macro @macro ManPageEnd{} @ifclear man @end indentedblock @end ifclear @end macro �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/doc/gp-display-gui.texi�������������������������������������������������������������0000644�0001750�0001750�00000026013�14517772113�015024� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������@c ---------------------------------------------------------------------------- @c This is the Texinfo source file for the gp-display-gui man page. @c @c Author: Ruud van der Pas @c ---------------------------------------------------------------------------- @ifset man \input texinfo @c -*-texinfo-*- @setfilename gp-display-gui @settitle Graphical tool to analyze one or more gprofng experiments @include gp-macros.texi @end ifset @clear REMOTE_HOST @c ---------------------------------------------------------------------------- @c This is from the man-pages(7) man page @c @c "The list below shows conventional or suggested sections. Most manual pages @c should include at least the highlighted sections. Arrange a new manual @c page so that sections are placed in the order shown in the list." @c @c NAME @c SYNOPSIS @c CONFIGURATION [Normally only in Section 4] @c DESCRIPTION @c OPTIONS [Normally only in Sections 1, 8] @c EXIT STATUS [Normally only in Sections 1, 8] @c RETURN VALUE [Normally only in Sections 2, 3] @c ERRORS [Typically only in Sections 2, 3] @c ENVIRONMENT @c FILES @c VERSIONS [Normally only in Sections 2, 3] @c ATTRIBUTES [Normally only in Sections 2, 3] @c CONFORMING TO @c NOTES @c BUGS @c EXAMPLES @c AUTHORS [Discouraged] @c REPORTING BUGS [Not used in man-pages] @c COPYRIGHT [Not used in man-pages] @c SEE ALSO @c @c This is what the texi2pod.pl tool recognizes: @c @c for $sect (qw(NAME SYNOPSIS TARGET DESCRIPTION OPTIONS ENVIRONMENT FILES @c BUGS NOTES FOOTNOTES SEEALSO AUTHOR COPYRIGHT)) { @c @c What is interesting is that it places "SEE ALSO" before "COPYRIGHT", which @c makes sense and adhered to for the other formats. @c ---------------------------------------------------------------------------- @c ---------------------------------------------------------------------------- @c NAME section @c ---------------------------------------------------------------------------- @ManPageStart{NAME} @c man begin NAME gp-display-gui - Graphical tool to analyze one or more gprofng experiments @c man end @ManPageEnd{} @c ---------------------------------------------------------------------------- @c SYNOPSIS section @c ---------------------------------------------------------------------------- @ManPageStart{SYNOPSIS} @c man begin SYNOPSIS @ifclear man @IndexSubentry{Options, @code{-c}} @end ifclear @iftex @command{gprofng display gui} [@var{option(s)}] \ @indentedblock [[@option{-c}] @var{experiment(s)} | @var{target} [@var{target-options}]] @end indentedblock @end iftex @ifnottex @command{gprofng display gui} [@var{option(s)}] [[@option{-c}] @var{experiment(s)} | @var{target} [@var{target-options}]] @end ifnottex @c man end @ManPageEnd{} @c ---------------------------------------------------------------------------- @c DESCRIPTION section @c ---------------------------------------------------------------------------- @ManPageStart{DESCRIPTION} @c man begin DESCRIPTION The @command{gprofng display gui} tool starts the GUI, which is a Java based graphical tool that can be used to analyze performance data that has been collected with the @command{gprofng collect app} tool. Multiple experiments may be specified on the command line. The data for all these experiments is loaded and ready for analysis. Once the tool has started, it is also possible to drop or load other experiments. By default, if multiple experiments are specified, the data is aggregated across the experiments. If the @ifclear man @IndexSubentry{Options, @code{-c}} @end ifclear @option{-c} option is used, the tool starts in comparison mode. In this case, the data for the various experiments can be compared. If this option is used, at least two experiments must be specified on the command line. Alternatively, the tool can be invoked without specifying experiments. In this case, a target program is expected to be specified. Optionally, there may be options for the target. In this case, a window with user settings will be opened. These may be used to specify the options and other preferences that define the data collection experiment. The user can then run the experiment from this window and upon successful completion, analyze the results. If @command{gprofng display gui} is invoked without specifying one or more experiments, or a target, a welcome screen is shown. In this screen, the user can specify whether to analyze an existing experiment, or to create a new experiment by specifying the data collection settings to define and run a new performance experiment. @c man end @ManPageEnd{} @c ---------------------------------------------------------------------------- @c OPTIONS section @c ---------------------------------------------------------------------------- @ManPageStart{OPTIONS} @c man begin OPTIONS @table @gcctabopt @item --version @ifclear man @IndexSubentry{Options, @code{--version}} @end ifclear Print the version number and exit. @item --help @ifclear man @IndexSubentry{Options, @code{--help}} @end ifclear Print usage information and exit. @item -v, --verbose @ifclear man @IndexSubentry{Options, @code{-v}} @IndexSubentry{Options, @code{--verbose}} @end ifclear By default, verbose mode is disabled. This option enables it. @item -j, --jdkhome @var{jvmpath} @ifclear man @IndexSubentry{Options, @code{-j}} @IndexSubentry{Options, @code{--jdkhome}} @end ifclear Specify the path to the Java Virtual Machine (JVM) to be used for running @command{gprofng display gui}. The default path is taken first by examining environment variables for a path to the JVM, in the order @env{JDK_HOME}, and then @env{JAVA_PATH}. If neither environment variable is set, the version found in the search path set with the @env{PATH} environment variable is used. If none is found, @command{/usr/java/bin/java} is tried. @item -J@var{jvm-setting} @ifclear man @IndexSubentry{Options, @code{-J}} @end ifclear Use this option to pass on settings to the JVM. Multiple @option{-J} options and corresponding settings may be supplied. Note that there is @emph{no} space between the @option{-J} option and the @var{jvm-setting} setting to the JVM. @item -c @var{base-group compare-group} @ifclear man @IndexSubentry{Options, @code{-c}} @end ifclear By default, the results for multiple experiments are aggregated. With this option, the GUI starts in comparison mode. If this option is specified, two or more experiments must be provided as arguments. The first experiment is the base group. The results in the other experiment(s) are compared to this reference experiment. Note that the user can toggle between aggregation and comparison mode from within the GUI. @item -f, --fontsize @var{size} @ifclear man @IndexSubentry{Options, @code{-f}} @IndexSubentry{Options, @code{--fontsize}} @end ifclear Specify the font size to be used in the GUI. @item -u, --userdir @var{dir-path} @ifclear man @IndexSubentry{Options, @code{-u}} @IndexSubentry{Options, @code{--userdir}} @end ifclear Specify the path to the user directory in which to store user settings. @end table @c man end @ManPageEnd{} @ifset REMOTE_HOST @c ----------------------------------------------------------------------------- @c ENVIRONMENT SECTION @c @c Temporarily disabled until the remote host feature has been implemented. @c Once this has been done, remove the ifset REMOTE_HOST/end ifset and the @c "@c deferred " strings. @c ----------------------------------------------------------------------------- @c deferred @ManPageStart{ENVIRONMENT} @c deferred @c man begin ENVIRONMENT The following environment variables for connecting to a remote host are supported: @table @samp @item @env{GPROFNG_HEARTBEAT_DISABLE} @cindex Environment variables If defined, disable periodic checking of the connection between @command{gprofng} and the remote host. By default, a heartbeat packet is sent periodically from @command{gprofng} to the remote back-end. When enabled, the heartbeat packet can help to keep some SSH connections from automatically closing due to inactivity. @item @env{GPROFNG_HEARTBEAT_MSEC} @cindex Environment variables Set the interval for checking the connection between @command{gprofng} and the remote host. The default is 2000 milliseconds. @item @env{GPROFNG_REMOTE_SHELL} @cindex Environment variables Set this variable to @command{/usr/bin/ssh} to use @samp{/usr/bin/ssh} for connecting @command{gprofng} to a remote host. If this variable is not set, the internal tool to connect is used. For example: @smallexample $ export GPROFNG_REMOTE_SHELL="/usr/bin/ssh -u test-linux-nm1.pem" @end smallexample Note that this variable is only available on UNIX-based systems, and only for connections that do not require a password or passphrase. @end table @c deferred @c man end @c deferred @ManPageEnd{} @end ifset @c ---------------------------------------------------------------------------- @c NOTES section @c ---------------------------------------------------------------------------- @ManPageStart{NOTES} @c man begin NOTES The @command{gprofng display gui} tool relies on other @command{gprofng} components. Therefore, it is necessary to also install the other components, either by using one of the available rpm's, install from a tar file distribution, or to build and install @command{gprofng} directly from the source. @c man end @ManPageEnd{} @c ---------------------------------------------------------------------------- @c SEEALSO section @c ---------------------------------------------------------------------------- @ManPageStart{SEE ALSO} @c man begin SEEALSO gprofng(1), gp-archive(1), gp-collect-app(1), gp-display-html(1), gp-display-src(1), gp-display-text(1) @iftex @vspace{1} @end iftex The user guide for gprofng is maintained as a Texinfo manual. If the @command{info} and @command{gprofng} programs are correctly installed, the command @command{info gprofng} should give access to this document. @c man end @ManPageEnd{} @c ---------------------------------------------------------------------------- @c COPYRIGHT section @c ---------------------------------------------------------------------------- @ManPageStart{COPYRIGHT} @c man begin COPYRIGHT Copyright @copyright{} 2022-2023 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled ``GNU Free Documentation License''. @c man end @ManPageEnd{} @c ---------------------------------------------------------------------------- @c If this text is used for a man page, exit. Otherwise we need to continue. @c ---------------------------------------------------------------------------- @ifset man @bye @end ifset ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/gprofng-gui.spec��������������������������������������������������������������������0000644�0001750�0001750�00000004351�14517772113�013632� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Copyright (C) 2022, 2023 Free Software Foundation # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. Summary: Graphical User Interface for the gprofng profiler. Name: gprofng-gui Version: 2.40 Release: 1%{?dist} License: GPLv3+ URL: FIX_ME:https://www.gnu.org/software/gprofng-gui Source: FIX_ME:https://ftp.gnu.org/gnu/gprofng-gui/gprofng-gui-%{version}.tar.xz BuildRequires: autoconf automake make sed coreutils BuildRequires: java-devel Requires: binutils-gprofng >= %{Version} Requires: java-devel Provides: gprofng-gui = %{version}-%{release} %description The GNU gprofng GUI is a feature rich graphical user interface for the GNU gprofng tool. It makes it possible to interactively analyze and compare gprofng profiling experiments. Users can drill into an applications profile together with the applications code to gather an understanding and insight into what an application is doing throughout it's runtime. %global debug_package %{nil} #---------------------------------------------------------------------------- %prep %setup #---------------------------------------------------------------------------- %build %configure %make_build #---------------------------------------------------------------------------- %install %make_install DESTDIR=%{buildroot} #---------------------------------------------------------------------------- %files %{_bindir}/gp-display-gui %{_datadir}/%{name}/gprofng-analyzer.jar %{_datadir}/%{name}/gprofng-collector.jar %{_datadir}/%{name}/gprofng.jar #---------------------------------------------------------------------------- %changelog * Thu Oct 27 2022 Vladimir Mezentsev <vladimir.mezentsev@oracle.com> - First version being package ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/INSTALL�����������������������������������������������������������������������������0000644�0001750�0001750�00000036614�14517772130�011571� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������Installation Instructions ************************* Copyright (C) 1994-1996, 1999-2002, 2004-2016 Free Software Foundation, Inc. Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved. This file is offered as-is, without warranty of any kind. Basic Installation ================== Briefly, the shell command './configure && make && make install' should configure, build, and install this package. The following more-detailed instructions are generic; see the 'README' file for instructions specific to this package. Some packages provide this 'INSTALL' file but do not implement all of the features documented below. The lack of an optional feature in a given package is not necessarily a bug. More recommendations for GNU packages can be found in *note Makefile Conventions: (standards)Makefile Conventions. The 'configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a 'Makefile' in each directory of the package. It may also create one or more '.h' files containing system-dependent definitions. Finally, it creates a shell script 'config.status' that you can run in the future to recreate the current configuration, and a file 'config.log' containing compiler output (useful mainly for debugging 'configure'). It can also use an optional file (typically called 'config.cache' and enabled with '--cache-file=config.cache' or simply '-C') that saves the results of its tests to speed up reconfiguring. Caching is disabled by default to prevent problems with accidental use of stale cache files. If you need to do unusual things to compile the package, please try to figure out how 'configure' could check whether to do them, and mail diffs or instructions to the address given in the 'README' so they can be considered for the next release. If you are using the cache, and at some point 'config.cache' contains results you don't want to keep, you may remove or edit it. The file 'configure.ac' (or 'configure.in') is used to create 'configure' by a program called 'autoconf'. You need 'configure.ac' if you want to change it or regenerate 'configure' using a newer version of 'autoconf'. The simplest way to compile this package is: 1. 'cd' to the directory containing the package's source code and type './configure' to configure the package for your system. Running 'configure' might take a while. While running, it prints some messages telling which features it is checking for. 2. Type 'make' to compile the package. 3. Optionally, type 'make check' to run any self-tests that come with the package, generally using the just-built uninstalled binaries. 4. Type 'make install' to install the programs and any data files and documentation. When installing into a prefix owned by root, it is recommended that the package be configured and built as a regular user, and only the 'make install' phase executed with root privileges. 5. Optionally, type 'make installcheck' to repeat any self-tests, but this time using the binaries in their final installed location. This target does not install anything. Running this target as a regular user, particularly if the prior 'make install' required root privileges, verifies that the installation completed correctly. 6. You can remove the program binaries and object files from the source code directory by typing 'make clean'. To also remove the files that 'configure' created (so you can compile the package for a different kind of computer), type 'make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. 7. Often, you can also type 'make uninstall' to remove the installed files again. In practice, not all packages have tested that uninstallation works correctly, even though it is required by the GNU Coding Standards. 8. Some packages, particularly those that use Automake, provide 'make distcheck', which can by used by developers to test that all other targets like 'make install' and 'make uninstall' work correctly. This target is generally not run by end users. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the 'configure' script does not know about. Run './configure --help' for details on some of the pertinent environment variables. You can give 'configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c99 CFLAGS=-g LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you can use GNU 'make'. 'cd' to the directory where you want the object files and executables to go and run the 'configure' script. 'configure' automatically checks for the source code in the directory that 'configure' is in and in '..'. This is known as a "VPATH" build. With a non-GNU 'make', it is safer to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use 'make distclean' before reconfiguring for another architecture. On MacOS X 10.5 and later systems, you can create libraries and executables that work on multiple system types--known as "fat" or "universal" binaries--by specifying multiple '-arch' options to the compiler but only a single '-arch' option to the preprocessor. Like this: ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ CPP="gcc -E" CXXCPP="g++ -E" This is not guaranteed to produce working output in all cases, you may have to build one architecture at a time and combine the results using the 'lipo' tool if you have problems. Installation Names ================== By default, 'make install' installs the package's commands under '/usr/local/bin', include files under '/usr/local/include', etc. You can specify an installation prefix other than '/usr/local' by giving 'configure' the option '--prefix=PREFIX', where PREFIX must be an absolute file name. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option '--exec-prefix=PREFIX' to 'configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like '--bindir=DIR' to specify different values for particular kinds of files. Run 'configure --help' for a list of the directories you can set and what kinds of files go in them. In general, the default for these options is expressed in terms of '${prefix}', so that specifying just '--prefix' will affect all of the other directory specifications that were not explicitly provided. The most portable way to affect installation locations is to pass the correct locations to 'configure'; however, many packages provide one or both of the following shortcuts of passing variable assignments to the 'make install' command line to change installation locations without having to reconfigure or recompile. The first method involves providing an override variable for each affected directory. For example, 'make install prefix=/alternate/directory' will choose an alternate location for all directory configuration variables that were expressed in terms of '${prefix}'. Any directories that were specified during 'configure', but not in terms of '${prefix}', must each be overridden at install time for the entire installation to be relocated. The approach of makefile variable overrides for each directory variable is required by the GNU Coding Standards, and ideally causes no recompilation. However, some platforms have known limitations with the semantics of shared libraries that end up requiring recompilation when using this method, particularly noticeable in packages that use GNU Libtool. The second method involves providing the 'DESTDIR' variable. For example, 'make install DESTDIR=/alternate/directory' will prepend '/alternate/directory' before all installation names. The approach of 'DESTDIR' overrides is not required by the GNU Coding Standards, and does not work on platforms that have drive letters. On the other hand, it does better at avoiding recompilation issues, and works well even when some directory options were not specified in terms of '${prefix}' at 'configure' time. Optional Features ================= If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving 'configure' the option '--program-prefix=PREFIX' or '--program-suffix=SUFFIX'. Some packages pay attention to '--enable-FEATURE' options to 'configure', where FEATURE indicates an optional part of the package. They may also pay attention to '--with-PACKAGE' options, where PACKAGE is something like 'gnu-as' or 'x' (for the X Window System). The 'README' should mention any '--enable-' and '--with-' options that the package recognizes. For packages that use the X Window System, 'configure' can usually find the X include and library files automatically, but if it doesn't, you can use the 'configure' options '--x-includes=DIR' and '--x-libraries=DIR' to specify their locations. Some packages offer the ability to configure how verbose the execution of 'make' will be. For these packages, running './configure --enable-silent-rules' sets the default to minimal output, which can be overridden with 'make V=1'; while running './configure --disable-silent-rules' sets the default to verbose, which can be overridden with 'make V=0'. Particular systems ================== On HP-UX, the default C compiler is not ANSI C compatible. If GNU CC is not installed, it is recommended to use the following options in order to use an ANSI C compiler: ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" and if that doesn't work, install pre-built binaries of GCC for HP-UX. HP-UX 'make' updates targets which have the same time stamps as their prerequisites, which makes it generally unusable when shipped generated files such as 'configure' are involved. Use GNU 'make' instead. On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot parse its '<wchar.h>' header file. The option '-nodtk' can be used as a workaround. If GNU CC is not installed, it is therefore recommended to try ./configure CC="cc" and if that doesn't work, try ./configure CC="cc -nodtk" On Solaris, don't put '/usr/ucb' early in your 'PATH'. This directory contains several dysfunctional programs; working variants of these programs are available in '/usr/bin'. So, if you need '/usr/ucb' in your 'PATH', put it _after_ '/usr/bin'. On Haiku, software installed for all users goes in '/boot/common', not '/usr/local'. It is recommended to use the following options: ./configure --prefix=/boot/common Specifying the System Type ========================== There may be some features 'configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, 'configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the '--build=TYPE' option. TYPE can either be a short name for the system type, such as 'sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file 'config.sub' for the possible values of each field. If 'config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option '--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with '--host=TYPE'. Sharing Defaults ================ If you want to set default values for 'configure' scripts to share, you can create a site shell script called 'config.site' that gives default values for variables like 'CC', 'cache_file', and 'prefix'. 'configure' looks for 'PREFIX/share/config.site' if it exists, then 'PREFIX/etc/config.site' if it exists. Or, you can set the 'CONFIG_SITE' environment variable to the location of the site script. A warning: not all 'configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to 'configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the 'configure' command line, using 'VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified 'gcc' to be used as the C compiler (unless it is overridden in the site shell script). Unfortunately, this technique does not work for 'CONFIG_SHELL' due to an Autoconf limitation. Until the limitation is lifted, you can use this workaround: CONFIG_SHELL=/bin/bash ./configure CONFIG_SHELL=/bin/bash 'configure' Invocation ====================== 'configure' recognizes the following options to control how it operates. '--help' '-h' Print a summary of all of the options to 'configure', and exit. '--help=short' '--help=recursive' Print a summary of the options unique to this package's 'configure', and exit. The 'short' variant lists options used only in the top level, while the 'recursive' variant lists options also present in any nested packages. '--version' '-V' Print the version of Autoconf used to generate the 'configure' script, and exit. '--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally 'config.cache'. FILE defaults to '/dev/null' to disable caching. '--config-cache' '-C' Alias for '--cache-file=config.cache'. '--quiet' '--silent' '-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to '/dev/null' (any error messages will still be shown). '--srcdir=DIR' Look for the package's source code in directory DIR. Usually 'configure' can determine that directory automatically. '--prefix=DIR' Use DIR as the installation prefix. *note Installation Names:: for more details, including other options available for fine-tuning the installation locations. '--no-create' '-n' Run the configure checks, but stop before creating any output files. 'configure' also accepts some other, not widely useful, options. Run 'configure --help' for more details. ��������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/tools/������������������������������������������������������������������������������0000755�0001750�0001750�00000000000�14517772113�011747� 5����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/tools/LocaleString.java�������������������������������������������������������������0000644�0001750�0001750�00000025451�14517772113�015127� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* Copyright (C) 2022 Free Software Foundation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses>. */ // stdin: source files // stdout: properties file import java.io.BufferedReader; import java.io.InputStreamReader; import java.text.MessageFormat; import java.text.ParsePosition; import java.util.Arrays; import java.util.Vector; public final class LocaleString { private final static MessageFormat mf1 = new MessageFormat("({0}){1}"); // NOI18N private final static MessageFormat mf2 = new MessageFormat("{0}){1}"); // NOI18N private final static MessageFormat mf3 = new MessageFormat("\''{0}\'',{1}"); // NOI18N private final static MessageFormat mf4 = new MessageFormat("\"{0}\",{1}"); // NOI18N private final static ParsePosition parsePos = new ParsePosition(0); private final static String key = "AnLocale.getString"; // NOI18N private final static int key_len = key.length(); private final static String key1 = "getLocaleStr"; // NOI18N private final static int key1_len = key1.length(); public static void main(String[] args) { final BufferedReader in; String line; Vector values, mnem_values; int index, index1; Elem strs; // Open stdin as BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); line = null; values = new Vector(); mnem_values = new Vector(); try { for (;;) { if ((line == null) && ((line = in.readLine()) == null)) { break; } // Search keyword, the Locale get string method index = line.indexOf(key); index1 = line.indexOf(key1); if ((line.indexOf("getLocaleStr(String") > 0) || // NOI18N (line.indexOf("AnLocale.getString(str") > 0) || // NOI18N (line.indexOf("getLocaleStr(char") > 0) || // NOI18N (line.indexOf("AnLocale.getString(c") > 0)) { // NOI18N line = null; continue; } if ((index == -1) && (index1 == -1)) { line = null; continue; } // Parse for the string argument for (;;) { if (index != -1) { strs = parse(line.substring(index + key_len).trim()); } else { strs = parse(line.substring(index1 + key1_len).trim()); } if (strs != null) { if (strs.isMnemonic()) { mnem_values.addElement(strs); } else { values.addElement(strs); } line = strs.getLeftStr(); break; } line += in.readLine(); } } } catch (Exception e) { System.err.println(e); System.exit(1); } // Sort & Output result properties values = sort(values); mnem_values = sort(mnem_values); Elem elem; for (index = 0; index < values.size(); index++) { elem = (Elem) values.get(index); if (elem.getKey() != null) { System.out.println(setEscape(elem.getValue()) + "[" + elem.getKey() + "]" + "=" + // NOI18N (elem.getValue().startsWith(" ") ? "\\" : "") + elem.getValue()); // NOI18N } else { System.out.println(setEscape(elem.getValue()) + "=" + // NOI18N (elem.getValue().startsWith(" ") ? "\\" : "") + elem.getValue()); // NOI18N } } if (mnem_values.size() > 0) { System.out.println("\n# MNEMONICS"); // NOI18N System.out.println("# =================================================================================="); // NOI18N System.out.println("#"); // NOI18N for (index = 0; index < mnem_values.size(); index++) { elem = (Elem) mnem_values.get(index); System.out.println(elem.getKey() + "=" + // NOI18N (elem.getValue().startsWith(" ") ? "\\" : "") + elem.getValue()); // NOI18N } } } private final static Object syncFormat = new Object(); // Parser for getting the string argument private static Elem parse(String str) { MessageFormat mf; String ans, value, check; Object[] result; Elem elem; mf = mf1; ans = ""; // NOI18N for (;;) { parsePos.setIndex(0); result = mf.parse(str, parsePos); mf = mf2; if (result != null) { value = (String) result[0]; str = (String) result[1]; ans += value; check = value.trim(); // If ends with ", then done if (check.endsWith("\"") && !check.endsWith("\\\"")) { // NOI18N value = ans.trim(); parsePos.setIndex(0); synchronized (syncFormat) { // begin critical section: format is not thread safe result = mf3.parse(value, parsePos); String key = null; boolean is_mnemonic = false; if (result != null) { value = ((String) result[0]).trim(); key = ((String) result[1]).trim(); is_mnemonic = true; } else { result = mf4.parse(value, parsePos); if (result != null) { value = ((String) result[0]).trim(); key = ((String) result[1]).trim(); } } elem = new Elem(key, value, str, is_mnemonic); } // end of critical section return elem.removeQuotes(); } else { ans += ")"; // NOI18N } } else { return null; } } } // Sort the string list private static Vector sort(final Vector vec) { final int size; int index; final Vector result; // Convert results to Object[] & Sort size = vec.size(); final Object[] strs = vec.toArray(); Arrays.sort(strs); // Remove Repeated elements Elem elem = null; result = new Vector(); for (index = 0; index < size; index++) { if (((Elem) strs[index]).equals(elem)) { continue; } elem = (Elem) strs[index]; // Remove the "" from the both ends result.addElement(new Elem(elem)); } return result; } // Add escape char '\' for ' ' & ':' private static String setEscape(final String str) { String esc; final int size; int index; char c; esc = ""; // NOI18N size = str.length(); for (index = 0; index < size; index++) { c = str.charAt(index); if ((c == ' ') || (c == ':') || (c == '=')) // NOI18N { esc += '\\'; // NOI18N } esc += c; } return esc; } /* Class which contains a parsed properties value */ private static final class Elem implements Comparable { private String key; // optional bundle key private String value; // required properties value private String left; // residual string private boolean is_mnemonic; // element is mnemonic // Constructor public Elem(final String key, final String value, final String left, final boolean is_mnemonic) { this.key = key; this.value = value; this.left = left; this.is_mnemonic = is_mnemonic; } // Copy constructor public Elem(final Elem elem) { this.key = elem.key; this.value = elem.value; this.is_mnemonic = elem.is_mnemonic; } public String getLeftStr() { return left; } public String getKey() { return key; } public boolean isMnemonic() { return is_mnemonic; } public String getValue() { return value; } // Comparator implementation method public int compareTo(final Object obj) { final String obj_key = ((Elem) obj).key; final String obj_value = ((Elem) obj).value; final boolean obj_mnem = ((Elem) obj).is_mnemonic; if (key != null && obj_key != null) { if (is_mnemonic && obj_mnem) { return key.compareTo(obj_key); } else { return (value + key).compareTo(obj_value + obj_key); } } else { return value.compareTo(obj_value); } } public String toString() { return (key == null ? value : key) + "=" + value; // NOI18N } protected Elem removeQuotes() { if (key != null) { if (key.charAt(0) == '\"' || key.charAt(0) == '\'') { // NOI18N key = key.substring(1, key.length() - 1); } } if (value != null) { if (value.charAt(0) == '\"' || value.charAt(0) == '\'') { // NOI18N value = value.substring(1, value.length() - 1); } } return this; } public boolean equals(final Elem e) { if (e != null) { if (!this.is_mnemonic && !e.is_mnemonic) { if (this.key != null && e.key != null) { return this.compareTo(e) == 0; } if (this.key != null || e.key != null) { return false; } } return this.compareTo(e) == 0; } return false; } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/missing�����������������������������������������������������������������������������0000755�0001750�0001750�00000015336�14517772130�012135� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2018-03-07.03; # UTC # Copyright (C) 1996-2020 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to <bug-automake@gnu.org>." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=https://www.perl.org/ flex_URL=https://github.com/westes/flex gnu_software_URL=https://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC0" # time-stamp-end: "; # UTC" # End: ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/gp-display-gui.1��������������������������������������������������������������������0000644�0001750�0001750�00000021512�14517772144�013451� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "GP-DISPLAY-GUI 1" .TH GP-DISPLAY-GUI 1 "2023-10-30" "binutils-1.0" "User Commands" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" gp\-display\-gui \- Graphical tool to analyze one or more gprofng experiments .SH "SYNOPSIS" .IX Header "SYNOPSIS" \&\fBgprofng display gui\fR [\fIoption(s)\fR] [[\fB\-c\fR] \fIexperiment(s)\fR | \fItarget\fR [\fItarget-options\fR]] .SH "DESCRIPTION" .IX Header "DESCRIPTION" The \fBgprofng display gui\fR tool starts the \s-1GUI,\s0 which is a Java based graphical tool that can be used to analyze performance data that has been collected with the \fBgprofng collect app\fR tool. .PP Multiple experiments may be specified on the command line. The data for all these experiments is loaded and ready for analysis. .PP Once the tool has started, it is also possible to drop or load other experiments. .PP By default, if multiple experiments are specified, the data is aggregated across the experiments. .PP If the \&\fB\-c\fR option is used, the tool starts in comparison mode. In this case, the data for the various experiments can be compared. If this option is used, at least two experiments must be specified on the command line. .PP Alternatively, the tool can be invoked without specifying experiments. In this case, a target program is expected to be specified. Optionally, there may be options for the target. .PP In this case, a window with user settings will be opened. These may be used to specify the options and other preferences that define the data collection experiment. The user can then run the experiment from this window and upon successful completion, analyze the results. .PP If \fBgprofng display gui\fR is invoked without specifying one or more experiments, or a target, a welcome screen is shown. In this screen, the user can specify whether to analyze an existing experiment, or to create a new experiment by specifying the data collection settings to define and run a new performance experiment. .SH "OPTIONS" .IX Header "OPTIONS" .IP "\fB\-\-version\fR" 4 .IX Item "--version" Print the version number and exit. .IP "\fB\-\-help\fR" 4 .IX Item "--help" Print usage information and exit. .IP "\fB\-v, \-\-verbose\fR" 4 .IX Item "-v, --verbose" By default, verbose mode is disabled. This option enables it. .IP "\fB\-j, \-\-jdkhome\fR \fIjvmpath\fR" 4 .IX Item "-j, --jdkhome jvmpath" Specify the path to the Java Virtual Machine (\s-1JVM\s0) to be used for running \fBgprofng display gui\fR. The default path is taken first by examining environment variables for a path to the \s-1JVM,\s0 in the order \fB\s-1JDK_HOME\s0\fR, and then \fB\s-1JAVA_PATH\s0\fR. .Sp If neither environment variable is set, the version found in the search path set with the \fB\s-1PATH\s0\fR environment variable is used. If none is found, \&\fB/usr/java/bin/java\fR is tried. .IP "\fB\-J\fR\fIjvm-setting\fR" 4 .IX Item "-Jjvm-setting" Use this option to pass on settings to the \s-1JVM.\s0 Multiple \fB\-J\fR options and corresponding settings may be supplied. Note that there is \fIno\fR space between the \fB\-J\fR option and the \&\fIjvm-setting\fR setting to the \s-1JVM.\s0 .IP "\fB\-c\fR \fIbase-group compare-group\fR" 4 .IX Item "-c base-group compare-group" By default, the results for multiple experiments are aggregated. With this option, the \s-1GUI\s0 starts in comparison mode. If this option is specified, two or more experiments must be provided as arguments. The first experiment is the base group. The results in the other experiment(s) are compared to this reference experiment. .Sp Note that the user can toggle between aggregation and comparison mode from within the \s-1GUI.\s0 .IP "\fB\-f, \-\-fontsize\fR \fIsize\fR" 4 .IX Item "-f, --fontsize size" Specify the font size to be used in the \s-1GUI.\s0 .IP "\fB\-u, \-\-userdir\fR \fIdir-path\fR" 4 .IX Item "-u, --userdir dir-path" Specify the path to the user directory in which to store user settings. .SH "NOTES" .IX Header "NOTES" The \fBgprofng display gui\fR tool relies on other \fBgprofng\fR components. Therefore, it is necessary to also install the other components, either by using one of the available rpm's, install from a tar file distribution, or to build and install \fBgprofng\fR directly from the source. .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fBgprofng\fR\|(1), \&\fBgp\-archive\fR\|(1), \&\fBgp\-collect\-app\fR\|(1), \&\fBgp\-display\-html\fR\|(1), \&\fBgp\-display\-src\fR\|(1), \&\fBgp\-display\-text\fR\|(1) .PP The user guide for gprofng is maintained as a Texinfo manual. If the \&\fBinfo\fR and \fBgprofng\fR programs are correctly installed, the command \fBinfo gprofng\fR should give access to this document. .SH "COPYRIGHT" .IX Header "COPYRIGHT" Copyright (c) 2022\-2023 Free Software Foundation, Inc. .PP Permission is granted to copy, distribute and/or modify this document under the terms of the \s-1GNU\s0 Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the license is included in the section entitled \*(L"\s-1GNU\s0 Free Documentation License\*(R". ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������gprofng-gui-1.0/gprofng-gui.sh����������������������������������������������������������������������0000644�0001750�0001750�00000024500�14517772113�013310� �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#!/usr/bin/env bash # Copyright (C) 2022 Free Software Foundation # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. # loader for gprofng GUI # # L10N Message translation utility # $1 - message id # $2 - fallback message text # GTXT() { eval I18Ntxt$2='$1' eval I18Nset$2='$3' eval I18Nid$2='$4' } # define all i18n messages GTXT "Usage: %s {options} arguments\n\nOptions can be\n\n" 1 17 1 GTXT "\t-?|-h|--help\n\t show usage and exit\n" 2 17 2 GTXT "\t-j|--jdkhome <path>\n\t specify the JVM directory\n" 3 17 3 GTXT "\t-J<jvm_options>\n\t pass <jvm_options> to JVM\n" 4 17 4 GTXT "\t-v|--verbose\n\t enable verbose output\n" 5 17 5 GTXT "\t-V|--version\n\t show version and exit\n" 6 17 6 GTXT "\nAll other options and arguments are passed to the Analyzer.\nSee documentations for details.\n" 7 17 7 GTXT "Cannot find JVM. Please set the JAVA_PATH environment variable to point\nto your JVM installation directory, or use the -j switch.\n" 8 17 8 GTXT "Cannot find JVM at \"%s\". Please set the JAVA_PATH\nenvironment variable to point to your JVM installation directory,\nor use the -j switch.\n" 9 17 9 GTXT "\t-f|--fontsize <size>\n\t specify the font size to be used in the gprofng GUI\n" 10 17 10 GTXT "Unrecognized option \"%s\"\n" 11 17 11 GTXT "Studio Default" 12 17 12 GTXT "WARNING: JDK_1_4_HOME is obsolete, and is ignored\n" 13 17 13 GTXT "Java at %s selected by %s\n" 14 17 14 GTXT "System Default" 15 17 15 GTXT "%s: ERROR: environment variable DISPLAY is not set\n" 16 17 16 GTXT "%s: WARNING: Current directory does not exist\n" 17 17 17 GTXT "%s: WARNING: Changed current directory to /\n" 18 17 18 GTXT "\t-c|--compare\n\t enter compare mode\n" 19 17 19 GTXT "\t-u|--userdir <path>\n\t use specified directory to store user settings\n" 20 17 20 GTXT "%s: ERROR: argument is missed for %s option\n" 21 17 21 GTXT "Error: java (%s) cannot be used to run gprofng GUI (command not found)\n" 22 17 22 GTXT "Error: java (%s) cannot be used to run gprofng GUI (Unsupported major.minor version)\n" 23 17 23 GTXT " The following J2SE[tm] versions are recommended:\n" 24 17 24 GTXT " J2SE[tm] 1.7.0_72 or later 1.7.0 updates\n" 25 17 25 GTXT " J2SE[tm] 1.8.0_20 or later 1.8.0 updates\n" 26 17 26 GTXT "Error: java (%s) cannot be used to run gprofng GUI (unrecognized class file version)\n" 27 17 27 Message() { text=I18Ntxt$1 mset=I18Nset$1 mid=I18Nid$1 if [ -x /usr/dt/bin/dtdspmsg ]; then eval eval /usr/dt/bin/dtdspmsg -s \${${mset}} analyzer.cat \${${mid}} \\\"\\\${$text}\\\" ${2:+"\\\"$2\\\""} ${3:+"\\\"$3\\\""} ${4:+"\\\"$4\\\""} else eval eval printf \\\"\\\${$text}\\\" ${2:+"\\\"$2\\\""} ${3:+"\\\"$3\\\""} ${4:+"\\\"$4\\\""} fi } Usage() { Message 1 $0 # "Usage: %s {options} arguments\n\nOptions can be\n\n" Message 2 # "\t-?|-h|--help\n\t show usage and exit\n" Message 3 # "\t-j|--jdkhome <path>\n\t specify the JVM directory\n" Message 4 # "\t-J<jvm_options>\n\t pass <jvm_options> to JVM\n" Message 10 # "\t-f|--fontsize <size>\n\t specify the font size to be used in the Analyzer\n" Message 5 # "\t-v|--verbose\n\t enable verbose output\n" Message 6 # "\t-V|--version\n\t show version and exit\n" Message 19 # -c|--compare Message 20 # -u|--userdir Message 7 # "\nAll other options and arguments are passed to the Analyzer.\nSee documentations for details.\n" } ########################################################################### # main program starts here # defaults # jdkhome will be really set below # the jvmflags value set here can be augmented by a -J argument # the verbose value set here can be overridden by a -v argument jdkhome="" java_how="?" jvmflags="-Xmx1024m" verbose="false" # end of defaults PATH=$PATH:/bin:/usr/bin export PATH # # define OS_TYPE # OS_TYPE=`/bin/uname` PRG=$(readlink -f -- "$0") progdir=$(dirname -- "$PRG") fdhome="$progdir/.." GPROFNG_bindir= GPROFNG_libdir= GPROFNG_datadir= # # L10N path # NLSPATH="${GPROFNG_libdir}/locale/%L/LC_MESSAGES/%N.cat:${GPROFNG_libdir}/locale/%L/LC_MESSAGES/%N:$NLSPATH" export NLSPATH # # absolutize fdhome # oldpwd=`pwd` ; if [ $? -ne 0 ]; then Message 17 $0 # echo "$0: WARNING: Current directory does not exist" cd / Message 18 $0 # echo "$0: WARNING: Changed current directory to /" oldpwd=`pwd` ; fi cd "$fdhome"; fdhome=`pwd`; cd "$oldpwd"; unset oldpwd jargs=$jvmflags args="--bindir='${GPROFNG_bindir}' --datadir='${GPROFNG_datadir}'" # see if invoked as "tha" or "rdt", and set environment variable accordingly if [ "`basename $0`" = "tha" -o "`basename $0`" = "rdt" ]; then SP_ANALYZER_CONFIG_MODE="R" export SP_ANALYZER_CONFIG_MODE fi # Check that there is an argument for the $1 option CheckArgsCount() { if [ $2 -lt 2 ]; then Message 21 ${PRG} $1 # Usage; exit 2 fi } HOME_USER_DIR=${HOME}/.gprofng DEFAULT_USER_DIR=${HOME_USER_DIR}/gui USER_DIR=${DEFAULT_USER_DIR} whoami=`basename $PRG` # parse arguments endargs=false while [ $# -gt 0 ] ; do case "$1" in --whoami=*) whoami=`echo -- "$1" | sed -e 's/--whoami=//'` ;; -j|--jdkhome) CheckArgsCount "$1" $# ; shift; java_how="-j"; jdkhome=$1; # jdk home ;; -J*) jopt=`expr $1 : '-J\(.*\)'`; jargs="$jargs \"$jopt\"";; -v|--verbose) verbose="true";; -V|--version) echo GNU `basename $PRG`: "REPLACE_ME_WITH_VERSION"; exit 0;; -\?|-h|--help) Usage; exit 0;; -f|--fontsize) CheckArgsCount "$1" $# ; args="$args \"$1\"" ; # option shift; args="$args \"$1\"" ; # font size ;; -c|--compare) args="$args $1" ;; -u|--userdir) CheckArgsCount "$1" $# ; args="$args \"$1\"" ; # option shift; args="$args \"$1\"" ; # user directory USER_DIR=$1 ;; --gprofngdir=*) args="$args \"$1\"" ;; -*) Message 11 $1; Usage; exit 1;; *) endargs=true ;; esac [ $endargs = true ] && break shift done # Add remaining arguments and pass them down while [ $# -gt 0 ] ; do args="$args \"$1\"" ; shift done # create user directory and set correct permissions if [ ! -d ${USER_DIR} ]; then /bin/mkdir -p ${USER_DIR} if [ "${USER_DIR}" = "${DEFAULT_USER_DIR}" ]; then /bin/chmod 700 ${HOME_USER_DIR} fi fi /bin/chmod 700 ${USER_DIR} # if user did not specify a jdkhome, set default if [ "$jdkhome" = "" ]; then # look at environment variables, and -j to find Java # if JAVA_PATH is set it overrides the default in the script if [ ! -z "$JAVA_PATH" ] ; then jdkhome="$JAVA_PATH" java_how="JAVA_PATH" fi # if JDK_HOME is set it overrides the default and JAVA_PATH in the script if [ ! -z "$JDK_HOME" ] ; then jdkhome="$JDK_HOME" java_how="JDK_HOME" fi # if we still don't have a jdkhome, try the user's path if [ "$jdkhome" = "" ]; then javaloc=`LC_ALL=C type java | sed -e 's|^[^/]*||' | sed -e "s|/java'|/java|"` if [ -f "$javaloc" ]; then javaloc1=$(dirname -- "$javaloc") jdkhome=$(dirname -- "$javaloc1") java_how="PATH" fi fi # finally, just try /usr/java/bin/java if [ "$jdkhome" = "" ]; then jdkhome=/usr/java java_how=$I18Ntxt15 fi fi # # check JVM # if [ -z "$jdkhome" ] ; then Message 8 exit 1 fi if [ ! -x "$jdkhome/bin/java" ] ; then Message 9 $jdkhome exit 1 fi if [ $verbose = "true" ] ; then echo `basename $PRG`: "REPLACE_ME_WITH_VERSION"; Message 14 "$jdkhome/bin/java" "$java_how" $jdkhome/bin/java -version; fi # Check DISPLAY variable if [ "no$DISPLAY" = "no" ]; then Message 16 $0 # "$0: ERROR: environment variable DISPLAY is not set" exit 2 fi # If this is Solaris SPARC disable sun.java2d.xrender if [ "${OS_TYPE}" = "SunOS" ]; then # if [ "no$VNCDESKTOP" != "no" ]; then HW_TYPE=`/bin/uname -p` if [ "${HW_TYPE}" = "sparc" ]; then jargs="-Dsun.java2d.xrender=false ${jargs}" fi # fi fi # Set special environment variable SP_COLLECTOR_FROM_GUI=1 export SP_COLLECTOR_FROM_GUI PID=$$ LOG="${USER_DIR}/an.${PID}.log" /bin/rm -f -- "${LOG}" gprofng_jar="${GPROFNG_datadir}/gprofng-gui/gprofng-analyzer.jar" if [ $verbose = "true" ] ; then echo "Run java:" echo "'$jdkhome/bin/java' $jargs -jar ${gprofng_jar} $args > ${LOG} 2>&1" # eval "/usr/bin/strace -v -f -t -o ${USER_DIR}/truss.log '$jdkhome/bin/java'" $jargs -jar ${gprofng_jar} $args # exit fi eval "'$jdkhome/bin/java'" $jargs -jar ${gprofng_jar} $args > "${LOG}" 2>&1 res=$? if [ ${res} -eq 0 ]; then /bin/cat -- "${LOG}" /bin/rm -f -- "${LOG}" exit ${res} fi # Execution failed # /bin/echo "Command failed: $jdkhome/bin/java $jargs -jar ${gprofng_jar} $args" err=`/bin/cat -- "${LOG}" | /bin/grep UnsupportedClassVersionError | wc -l` if [ ${err} -eq 0 ]; then err=`/bin/cat -- "${LOG}" | /bin/grep 'java: command not found' | wc -l` if [ ${err} -eq 0 ]; then err=`/bin/cat -- "${LOG}" | /bin/grep ClassFormatError | wc -l` if [ ${err} -eq 0 ]; then # unknown error /bin/cat -- "${LOG}" /bin/rm -f -- "${LOG}" exit ${res} fi Message 27 "$jdkhome/bin/java" # /bin/echo "Error: java from PATH cannot be used to run Performance Analyzer GUI (unrecognized class file version)" else Message 22 "$jdkhome/bin/java" # /bin/echo "Error: java from PATH cannot be used to run Performance Analyzer GUI (command not found)" fi else Message 23 "$jdkhome/bin/java" # /bin/echo "Error: java from PATH cannot be used to run Performance Analyzer GUI (Unsupported major.minor version)" fi Message 24 Message 25 Message 26 /bin/rm -f -- "${LOG}" exit ${res} ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������